Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarIdMap.hpp
blob: 7f13b400b1fc231b76c643dd167c26ac82e16789 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#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 <typename BaseMap>
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 <typename Base>
  friend DataStream& operator>>(DataStream& ds, IdMapWrapper<Base>& map);
  template <typename Base>
  friend DataStream& operator<<(DataStream& ds, IdMapWrapper<Base> const& map);

private:
  IdType m_min;
  IdType m_max;
  IdType m_nextId;
};

template <class Key, class Value>
using IdMap = IdMapWrapper<Map<Key, Value>>;

template <class Key, class Value>
using IdHashMap = IdMapWrapper<HashMap<Key, Value>>;

template <typename BaseMap>
IdMapWrapper<BaseMap>::IdMapWrapper()
  : m_min(lowest<IdType>()), m_max(highest<IdType>()), m_nextId(m_min) {}

template <typename BaseMap>
IdMapWrapper<BaseMap>::IdMapWrapper(IdType min, IdType max)
  : m_min(min), m_max(max), m_nextId(m_min) {
  starAssert(m_max > m_min);
}

template <typename BaseMap>
auto IdMapWrapper<BaseMap>::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 <typename BaseMap>
void IdMapWrapper<BaseMap>::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 <typename BaseMap>
auto IdMapWrapper<BaseMap>::add(MappedType mappedType) -> IdType {
  auto id = nextId();
  BaseMap::insert(id, mappedType);
  return id;
}

template <typename BaseMap>
void IdMapWrapper<BaseMap>::clear() {
  BaseMap::clear();
  m_nextId = m_min;
}

template <typename BaseMap>
bool IdMapWrapper<BaseMap>::operator==(IdMapWrapper const& rhs) const {
  return tie(m_min, m_max) == tie(rhs.m_min, rhs.m_max) && BaseMap::operator==(rhs);
}

template <typename BaseMap>
bool IdMapWrapper<BaseMap>::operator!=(IdMapWrapper const& rhs) const {
  return !operator==(rhs);
}

template <typename BaseMap>
DataStream& operator>>(DataStream& ds, IdMapWrapper<BaseMap>& map) {
  ds.readMapContainer((BaseMap&)map);
  ds.read(map.m_min);
  ds.read(map.m_max);
  ds.read(map.m_nextId);
  return ds;
}

template <typename BaseMap>
DataStream& operator<<(DataStream& ds, IdMapWrapper<BaseMap> const& map) {
  ds.writeMapContainer((BaseMap const&)map);
  ds.write(map.m_min);
  ds.write(map.m_max);
  ds.write(map.m_nextId);
  return ds;
}

}