/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2013 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLUtils/src/ICLUtils/MultiTypeMap.h ** ** Module : ICLUtils ** ** Authors: Christof Elbrechter ** ** ** ** ** ** GNU LESSER GENERAL PUBLIC LICENSE ** ** This file may be used under the terms of the GNU Lesser General ** ** Public License version 3.0 as published by the ** ** ** ** Free Software Foundation and appearing in the file LICENSE.LGPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the license requirements will ** ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** ********************************************************************/ #pragma once #include #include #include #include #include #include #include #include namespace icl{ namespace utils{ /// Abstract and associative Data Container for Data of different types /** The MultiTypeMap class can be used to create an associative container for different types. It provides an interface for a type-save handling of single elements as well as arrays of data.\n Single elements are created internally as a copy (copy constructor) of a given value (by default the empty constructor for a specific type is used to create a default initializing instance). Arrays elements and value elements may not be mixed up as array elements must be created and released in a different way (using new[] and delete[] instead of new() and delete).\n In addition the class provides some utility functions to get information about all contained data elements.\n The type-safety is facilitated using the C++ RTTI (Run-Time Type Identification) which is not very fast. Also the access functions getValue() and getArray() are not very fast, because the underlying memory is organized in a std::map, which must be searched. Hence, the more elements a MultiTypeMap object contains, the slower a single data element will be accessible (it's just a map internally :-) ). \n To accelerate data access just store a reference to the data element or a pointer anywhere and work with that pointer!. */ class ICLUtils_API MultiTypeMap{ public: /// Default constructor (create a new MultiTypeMap object) MultiTypeMap(); /// Destructor (deletes all remaining data) ~MultiTypeMap(); /// internally used wrapper function for RTTI template static inline const std::string &get_type_name(){ static std::string NAME = typeid(T).name(); return NAME; } /// Allocates a new memory block (new T[n]) for the given id string /** @param id name of this data block @param n count of elements (min 1) @return data pointer that was just created */ template inline T *allocArray(const std::string &id,unsigned int n){ if(!n){ ERROR_LOG("unable to create an array of size 0 for id " << id << "!"); return 0; } if(contains(id)){ ERROR_LOG("id " << id << "is already defined"); return 0; } DataArray &da = (*m_oDataMapPtr)[id]; da.data = new T[n]; da.len = n; da.type = get_type_name(); da.release_func = DataArray::release_data_array; return reinterpret_cast(da.data); } /// Allocates a new memory elements (new T(val)) for the given id string /** @param id name of this data block @param val initial value for this data block @return reference the the data element, that was just created */ template inline T &allocValue(const std::string &id, const T &val=T()){ static T _NULL = T(); if(contains(id)){ ERROR_LOG("id " << id << "is already defined"); return _NULL; } DataArray &da = (*m_oDataMapPtr)[id]; da.data = new T(val); da.len = 0; // indicates a single value ! da.type = get_type_name(); da.release_func = DataArray::release_data_array; return *(reinterpret_cast(da.data)); } /// release the data element that is associated with the given id /** @param id name of the entry to release */ template inline void release(const std::string &id){ if(!contains(id)){ ERROR_LOG("id "<< id << " not found \n"); return; } DataArray &da = (*m_oDataMapPtr)[id]; if(da.type != get_type_name()){ ERROR_LOG("unable to cast "<< id << " to a given type "<< get_type_name() <<"\n"); ERROR_LOG("type is " << da.type << "\n"); return; } da.release_func(&da); m_oDataMapPtr->erase(m_oDataMapPtr->find(id)); } /// get a T* that is associated with the given id /** @param id name of the entry to get @param lenDst pointer to store the array len (in T's) in if not NULL @return data pointer that is associated with id or NULL if the id is invalid */ template inline T* getArray(const std::string &id, int *lenDst=0){ if(!contains(id)){ ERROR_LOG("id "<< id << " not found \n"); return 0; } DataArray &da = (*m_oDataMapPtr)[id]; if(da.type != get_type_name()){ ERROR_LOG("unable to cast "<< id << " to a given type "<< get_type_name() <<"\n"); return 0; } if(!da.len){ ERROR_LOG("unable to access entry " << id << " as array, because it is a value!"); return 0; } if(lenDst) *lenDst = da.len; return reinterpret_cast(da.data); } /// get a T reference that is associated with the given id /** @param id name of the entry to get @param checkType @return reference to the value that is associated with the given id */ template inline T &getValue(const std::string &id, bool checkType=true){ static T _NULL; if(!contains(id)){ ERROR_LOG("id "<< id << " not found \n"); return _NULL; } // orig DataArray &da = (*m_oDataMapPtr)[id]; //DEBUG_LOG("type of da is " << da.type); if(checkType && (da.type != get_type_name())){ ERROR_LOG("unable to cast "<< id << " to a given type "<< get_type_name() <<"\n"); ERROR_LOG("type is " << da.type << "\n"); return _NULL; } if(da.len){ ERROR_LOG("unable to access entry " << id << " as value, because it is an array!"); return _NULL; } return *reinterpret_cast(da.data); } template inline const T &getValue(const std::string &id, bool checkType=true) const{ return const_cast(this)->getValue(id,checkType); } /// returns the RTTI string type identifier, for the entry associated with id /** @param id name of the entry @return RTTI string type identifier */ const std::string &getType(const std::string &id) const; /// checks if the type-id associated with the template parameter T is compatible to the entry for id /** @param id name of the entry @return whether the entry associated with id has type T */ template inline bool checkType(const std::string &id) const{ return check_type_internal(id,get_type_name()); } /// returns whether an entry is an array or a value /** @param id name of the entry to check @return whether the entry for id is an array */ bool isArray(const std::string &id) const; /// returns whether a given value is already set /** @param id name of the parameter @return whether a parameter with that id is contained*/ bool contains(const std::string &id) const; // internally locks the datastore inline void lock() const { m_oMutexPtr->lock(); } /// internally unlocks the data store inline void unlock() const { m_oMutexPtr->unlock(); } protected: bool check_type_internal(const std::string &id, const std::string &typestr) const; /// internally used data handling structure struct DataArray{ /// delete function, given to the data Array after construction to delete its own data /** @param da filled with the "this" argument internally by the Parent MultiTypeMap object */ template static void release_data_array(DataArray *da){ ICLASSERT_RETURN(da->type == get_type_name()); if(da->len) delete [] reinterpret_cast(da->data); else delete reinterpret_cast(da->data); } /// Create an empty DataArray object DataArray(void *data=0, int len=0):data(data),len(len),type(""),release_func(0){} void *data; // getEntryList() const; protected: /// internal definition typedef std::map DataMap; /// internal definition typedef SmartPtr SmartDataMapPtr; /// internal definition typedef SmartPtr SmartMutexPtr; /// Smart-Pointer to the underlying data (allows shallow copies) mutable SmartDataMapPtr m_oDataMapPtr; /// mutex to handle syncronous calls mutable SmartMutexPtr m_oMutexPtr; }; } // namespace utils }