Overte C++ Documentation
IndexedContainer.h
1 //
2 // IndexedContainer.h
3 // render
4 //
5 // Created by Sam Gateau on 9/6/2016.
6 // Copyright 2016 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_render_IndexedContainer_h
13 #define hifi_render_IndexedContainer_h
14 
15 #include <cassert>
16 #include <vector>
17 #include <algorithm>
18 
19 namespace render {
20 namespace indexed_container {
21 
22  using Index = int32_t;
23  const Index MAXIMUM_INDEX { 1 << 30 };
24  const Index INVALID_INDEX { -1 };
25  using Indices = std::vector< Index >;
26 
27  template <Index MaxNumElements = MAXIMUM_INDEX>
28  class Allocator {
29  public:
30  Allocator() {}
31  Indices _freeIndices;
32  Index _nextNewIndex { 0 };
33 
34  bool checkIndex(Index index) const { return ((index >= 0) && (index < _nextNewIndex)); }
35  Index getNumIndices() const { return _nextNewIndex - (Index) _freeIndices.size(); }
36  Index getNumFreeIndices() const { return (Index) _freeIndices.size(); }
37  Index getNumAllocatedIndices() const { return _nextNewIndex; }
38 
39  Index allocateIndex() {
40  if (_freeIndices.empty()) {
41  Index index = _nextNewIndex;
42  if (index >= MaxNumElements) {
43  // abort! we are trying to go overboard with the total number of allocated elements
44  assert(false);
45  // This should never happen because Bricks are allocated along with the cells and there
46  // is already a cap on the cells allocation
47  return INVALID_INDEX;
48  }
49  _nextNewIndex++;
50  return index;
51  } else {
52  Index index = _freeIndices.back();
53  _freeIndices.pop_back();
54  return index;
55  }
56  }
57 
58  void freeIndex(Index index) {
59  if (checkIndex(index)) {
60  _freeIndices.push_back(index);
61  }
62  }
63 
64  void clear() {
65  _freeIndices.clear();
66  _nextNewIndex = 0;
67  }
68  };
69 
70  template <class T, Index MaxNumElements = MAXIMUM_INDEX>
71  class IndexedVector {
72  Allocator<MaxNumElements> _allocator;
73  public:
74  using Element = T;
75  using Elements = std::vector<T>;
76 
77  Elements _elements;
78 
79  bool checkIndex(Index index) const { return _allocator.checkIndex(index); };
80  Index getNumElements() const { return _allocator.getNumIndices(); }
81  Index getNumFreeIndices() const { return _allocator.getNumFreeIndices(); }
82  Index getNumAllocatedIndices() const { return _allocator.getNumAllocatedIndices(); }
83 
84  Index newElement(const Element& e) {
85  Index index = _allocator.allocateIndex();
86  if (index != INVALID_INDEX) {
87  if (index < (Index) _elements.size()) {
88  _elements[index] = e;
89  } else {
90  assert(index == (Index)_elements.size());
91  _elements.emplace_back(e);
92  }
93  }
94  return index;
95  }
96 
97  const Element& freeElement(Index index) {
98  _allocator.freeIndex(index);
99  return _elements[index];
100  }
101 
102  bool isElementFreed(Index index) const {
103  return std::find(_allocator._freeIndices.begin(), _allocator._freeIndices.end(), index) != _allocator._freeIndices.end();
104  }
105 
106  const Element& get(Index index) const {
107  return _elements[index];
108  }
109  Element& edit(Index index) {
110  return _elements[index];
111  }
112  };
113 
114  template <class T, Index MaxNumElements = MAXIMUM_INDEX>
115  class IndexedPointerVector {
116  Allocator<MaxNumElements> _allocator;
117  public:
118  using Data = T;
119  using ElementPtr = std::shared_ptr<Data>;
120  using Elements = std::vector<ElementPtr>;
121 
122  Elements _elements;
123 
124  bool checkIndex(Index index) const { return _allocator.checkIndex(index); };
125  Index getNumElements() const { return _allocator.getNumIndices(); }
126  Index getNumFreeIndices() const { return _allocator.getNumFreeIndices(); }
127  Index getNumAllocatedIndices() const { return _allocator.getNumAllocatedIndices(); }
128 
129  Index newElement(const ElementPtr& e) {
130  Index index = _allocator.allocateIndex();
131  if (index != INVALID_INDEX) {
132  if (index < (Index) _elements.size()) {
133  _elements[index] = e;
134  } else {
135  assert(index == (Index) _elements.size());
136  _elements.emplace_back(e);
137  }
138  }
139  return index;
140  }
141 
142  ElementPtr freeElement(Index index) {
143  ElementPtr freed;
144  if (checkIndex(index)) {
145  _allocator.freeIndex(index);
146  freed = _elements[index];
147  _elements[index].reset(); // really forget it
148  }
149  return freed;
150  }
151 
152  ElementPtr get(Index index) const {
153  if (checkIndex(index)) {
154  return _elements[index];
155  } else {
156  return ElementPtr();
157  }
158  }
159  };
160 };
161 }
162 #endif