254 lines
7.6 KiB
C++
254 lines
7.6 KiB
C++
///////////////////////////////////////////////////////////////////
|
|
//*-------------------------------------------------------------*//
|
|
//| Part of the Game Jolt API C++ Library (http://gamejolt.com) |//
|
|
//*-------------------------------------------------------------*//
|
|
//| Released under the zlib License |//
|
|
//| More information available in the readme file |//
|
|
//*-------------------------------------------------------------*//
|
|
///////////////////////////////////////////////////////////////////
|
|
#pragma once
|
|
#ifndef _GJ_GUARD_LOOKUP_H_
|
|
#define _GJ_GUARD_LOOKUP_H_
|
|
|
|
typedef unsigned int gjUint;
|
|
#ifndef ASSERT
|
|
#define ASSERT(x)
|
|
#endif
|
|
|
|
|
|
// ****************************************************************
|
|
// lookup container class
|
|
template <typename T> class gjLookup final
|
|
{
|
|
public:
|
|
//! internal types
|
|
typedef std::pair<std::string, T> gjEntry;
|
|
typedef std::vector<gjEntry> gjList;
|
|
typedef typename gjList::iterator gjIterator;
|
|
typedef typename gjList::const_iterator gjConstIterator;
|
|
|
|
|
|
private:
|
|
gjList m_aList; //!< vector-list with pair-values
|
|
|
|
|
|
public:
|
|
gjLookup()noexcept;
|
|
gjLookup(const gjLookup<T>& c)noexcept;
|
|
gjLookup(gjLookup<T>&& m)noexcept;
|
|
~gjLookup();
|
|
|
|
//! assignment operator
|
|
//! @{
|
|
gjLookup<T>& operator = (gjLookup<T> o)noexcept;
|
|
template <typename S> friend void swap(gjLookup<S>& a, gjLookup<S>& b)noexcept;
|
|
//! @}
|
|
|
|
//! access specific entry
|
|
//! @{
|
|
const T& at(const char* pcKey)const noexcept;
|
|
T& operator [] (const char* pcKey)noexcept;
|
|
inline T& operator [] (const gjUint& iIndex)noexcept {return m_aList[iIndex].second;}
|
|
//! @}
|
|
|
|
//! check number of existing entries
|
|
//! @{
|
|
inline gjUint count(const char* pcKey)const noexcept {return this->__check(this->__retrieve(pcKey)) ? 1 : 0;}
|
|
inline gjUint size()const noexcept {return m_aList.size();}
|
|
inline bool empty()const noexcept {return m_aList.empty();}
|
|
//! @}
|
|
|
|
//! control memory consumption
|
|
//! @{
|
|
inline void reserve(const gjUint& iReserve)noexcept {m_aList.reserve(iReserve);}
|
|
inline gjUint capacity()const noexcept {return m_aList.capacity();}
|
|
//! @}
|
|
|
|
//! remove existing entries
|
|
//! @{
|
|
void erase(const T& Entry)noexcept;
|
|
void erase(const char* pcKey)noexcept;
|
|
inline void erase(const gjUint& iIndex)noexcept {ASSERT(iIndex < m_aList.size()) m_aList.erase(m_aList.begin()+iIndex);}
|
|
inline void erase(const gjConstIterator& Iterator)noexcept {m_aList.erase(Iterator);}
|
|
inline void clear()noexcept {m_aList.clear();}
|
|
//! @}
|
|
|
|
//! retrieve internal iterator
|
|
//! @{
|
|
inline gjIterator begin()noexcept {return m_aList.begin();}
|
|
inline gjConstIterator begin()const noexcept {return m_aList.begin();}
|
|
inline gjIterator end()noexcept {return m_aList.end();}
|
|
inline gjConstIterator end()const noexcept {return m_aList.end();}
|
|
//! @}
|
|
|
|
|
|
private:
|
|
//! retrieve iterator
|
|
//! @{
|
|
gjIterator __retrieve(const T& Entry)noexcept;
|
|
gjConstIterator __retrieve(const T& Entry)const noexcept;
|
|
gjIterator __retrieve(const char* pcKey)noexcept;
|
|
gjConstIterator __retrieve(const char* pcKey)const noexcept;
|
|
//! @}
|
|
|
|
//! check for valid iterator
|
|
//! @{
|
|
inline bool __check(const gjIterator& it)const noexcept {return (it != m_aList.end()) ? true : false;}
|
|
inline bool __check(const gjConstIterator& it)const noexcept {return (it != m_aList.end()) ? true : false;}
|
|
//! @}
|
|
};
|
|
|
|
|
|
// ****************************************************************
|
|
// constructor
|
|
template <typename T> gjLookup<T>::gjLookup()noexcept
|
|
{
|
|
// reserve variable sized memory
|
|
constexpr_var gjUint iSize = 1 + 64/sizeof(T);
|
|
m_aList.reserve(iSize);
|
|
}
|
|
|
|
template <typename T> gjLookup<T>::gjLookup(const gjLookup<T>& c)noexcept
|
|
: m_aList (c.m_aList)
|
|
{
|
|
}
|
|
|
|
template <typename T> gjLookup<T>::gjLookup(gjLookup<T>&& m)noexcept
|
|
: m_aList (std::move(m.m_aList))
|
|
{
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// destructor
|
|
template <typename T> gjLookup<T>::~gjLookup()
|
|
{
|
|
m_aList.clear();
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// assignment operator
|
|
template <typename T> gjLookup<T>& gjLookup<T>::operator = (gjLookup<T> o)noexcept
|
|
{
|
|
swap(*this, o);
|
|
return *this;
|
|
}
|
|
|
|
template <typename S> void swap(gjLookup<S>& a, gjLookup<S>& b)noexcept
|
|
{
|
|
using std::swap;
|
|
swap(a.m_aList, b.m_aList);
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// access specific entry
|
|
template <typename T> const T& gjLookup<T>::at(const char* pcKey)const noexcept
|
|
{
|
|
// retrieve and check iterator by specific key
|
|
auto it = this->__retrieve(pcKey);
|
|
ASSERT(this->__check(it))
|
|
|
|
return it->second;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// access specific entry and create it if necessary
|
|
template <typename T> T& gjLookup<T>::operator [] (const char* pcKey)noexcept
|
|
{
|
|
// retrieve and check iterator by specific key
|
|
auto it = this->__retrieve(pcKey);
|
|
if(!this->__check(it))
|
|
{
|
|
// create new entry
|
|
m_aList.push_back(gjEntry(pcKey, T()));
|
|
it = m_aList.end()-1;
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// remove existing entry
|
|
template <typename T> void gjLookup<T>::erase(const T& Entry)noexcept
|
|
{
|
|
// retrieve and check iterator by specific value
|
|
auto it = this->__retrieve(Entry);
|
|
if(this->__check(it))
|
|
{
|
|
// remove existing entry
|
|
m_aList.erase(it);
|
|
}
|
|
}
|
|
|
|
|
|
template <typename T> void gjLookup<T>::erase(const char* pcKey)noexcept
|
|
{
|
|
// retrieve and check iterator by specific key
|
|
auto it = this->__retrieve(pcKey);
|
|
if(this->__check(it))
|
|
{
|
|
// remove existing entry
|
|
m_aList.erase(it);
|
|
}
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// retrieve iterator by specific value
|
|
template <typename T> typename gjLookup<T>::gjIterator gjLookup<T>::__retrieve(const T& Entry)noexcept
|
|
{
|
|
// loop through all entries
|
|
FOR_EACH(it, m_aList)
|
|
{
|
|
// compare values
|
|
if(it->second == Entry)
|
|
return it;
|
|
}
|
|
return m_aList.end();
|
|
}
|
|
|
|
template <typename T> typename gjLookup<T>::gjConstIterator gjLookup<T>::__retrieve(const T& Entry)const noexcept
|
|
{
|
|
// loop through all entries
|
|
FOR_EACH(it, m_aList)
|
|
{
|
|
// compare values
|
|
if(it->second == Entry)
|
|
return it;
|
|
}
|
|
return m_aList.end();
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
// retrieve iterator by specific key
|
|
template <typename T> typename gjLookup<T>::gjIterator gjLookup<T>::__retrieve(const char* pcKey)noexcept
|
|
{
|
|
// loop through all entries
|
|
FOR_EACH(it, m_aList)
|
|
{
|
|
// compare string-keys
|
|
if(!std::strcmp(it->first.c_str(), pcKey))
|
|
return it;
|
|
}
|
|
return m_aList.end();
|
|
}
|
|
|
|
template <typename T> typename gjLookup<T>::gjConstIterator gjLookup<T>::__retrieve(const char* pcKey)const noexcept
|
|
{
|
|
// loop through all entries
|
|
FOR_EACH(it, m_aList)
|
|
{
|
|
// compare string-keys
|
|
if(!std::strcmp(it->first.c_str(), pcKey))
|
|
return it;
|
|
}
|
|
return m_aList.end();
|
|
}
|
|
|
|
|
|
#endif /* _GJ_GUARD_LOOKUP_H_ */ |