#pragma once #include "StarMap.hpp" #include "StarMathCommon.hpp" #include "StarDataStream.hpp" namespace Star { STAR_EXCEPTION(IdMapException, StarException); // Maps key ids to values with auto generated ids in a given id range. Tries // to cycle through ids as new values are added and avoid re-using ids until // the id space wraps around. template class IdMapWrapper : private BaseMap { public: typedef typename BaseMap::iterator iterator; typedef typename BaseMap::const_iterator const_iterator; typedef typename BaseMap::key_type key_type; typedef typename BaseMap::value_type value_type; typedef typename BaseMap::mapped_type mapped_type; typedef key_type IdType; typedef value_type ValueType; typedef mapped_type MappedType; IdMapWrapper(); IdMapWrapper(IdType min, IdType max); // New valid id that does not exist in this map. Tries not to immediately // recycle ids, to avoid temporally close id repeats. IdType nextId(); // Throws exception if key already exists void add(IdType id, MappedType mappedType); // Add with automatically allocated id IdType add(MappedType mappedType); void clear(); bool operator==(IdMapWrapper const& rhs) const; bool operator!=(IdMapWrapper const& rhs) const; using BaseMap::keys; using BaseMap::values; using BaseMap::pairs; using BaseMap::contains; using BaseMap::size; using BaseMap::empty; using BaseMap::get; using BaseMap::ptr; using BaseMap::maybe; using BaseMap::take; using BaseMap::maybeTake; using BaseMap::remove; using BaseMap::value; using BaseMap::begin; using BaseMap::end; using BaseMap::erase; template friend DataStream& operator>>(DataStream& ds, IdMapWrapper& map); template friend DataStream& operator<<(DataStream& ds, IdMapWrapper const& map); private: IdType m_min; IdType m_max; IdType m_nextId; }; template using IdMap = IdMapWrapper>; template using IdHashMap = IdMapWrapper>; template IdMapWrapper::IdMapWrapper() : m_min(lowest()), m_max(highest()), m_nextId(m_min) {} template IdMapWrapper::IdMapWrapper(IdType min, IdType max) : m_min(min), m_max(max), m_nextId(m_min) { starAssert(m_max > m_min); } template auto IdMapWrapper::nextId() -> IdType { if ((IdType)BaseMap::size() > m_max - m_min) throw IdMapException("No id space left in IdMapWrapper"); IdType nextId = m_nextId; while (BaseMap::contains(nextId)) nextId = cycleIncrement(nextId, m_min, m_max); m_nextId = cycleIncrement(nextId, m_min, m_max); return nextId; } template void IdMapWrapper::add(IdType id, MappedType mappedType) { if (!BaseMap::insert(make_pair(std::move(id), std::move(mappedType))).second) throw IdMapException::format("IdMapWrapper::add(id, value) called with pre-existing id '{}'", outputAny(id)); } template auto IdMapWrapper::add(MappedType mappedType) -> IdType { auto id = nextId(); BaseMap::insert(id, mappedType); return id; } template void IdMapWrapper::clear() { BaseMap::clear(); m_nextId = m_min; } template bool IdMapWrapper::operator==(IdMapWrapper const& rhs) const { return tie(m_min, m_max) == tie(rhs.m_min, rhs.m_max) && BaseMap::operator==(rhs); } template bool IdMapWrapper::operator!=(IdMapWrapper const& rhs) const { return !operator==(rhs); } template DataStream& operator>>(DataStream& ds, IdMapWrapper& map) { ds.readMapContainer((BaseMap&)map); ds.read(map.m_min); ds.read(map.m_max); ds.read(map.m_nextId); return ds; } template DataStream& operator<<(DataStream& ds, IdMapWrapper const& map) { ds.writeMapContainer((BaseMap const&)map); ds.write(map.m_min); ds.write(map.m_max); ds.write(map.m_nextId); return ds; } }