HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_OrderedIndexGroup.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GU_OrderedIndexGroup.h ( GU Library, C++)
7  *
8  * COMMENTS: This is a helper class for GU_Selection derivatives to keep
9  * selection as an ordered group of indices, rather than offsets,
10  * so that selection can remain GA_Detail invariant.
11  */
12 
13 #ifndef __GU_OrderedIndexGroup__
14 #define __GU_OrderedIndexGroup__
15 
16 #include <UT/UT_Array.h>
17 #include <UT/UT_Map.h>
18 #include <iostream>
19 #include <iterator>
20 
21 // Tombstone value for the index type, so that we can mark a dead value as
22 // distinct from a potentially valid value.
23 template<typename INDEX>
24 inline INDEX
25 tombstone() { return INDEX(); }
26 
27 template<typename INDEX>
29 {
32 
33 public:
34  typedef INDEX type;
35 
36  GU_OrderedIndexGroup() : myCompact(true) {}
37 
38  void append(const INDEX &idx)
39  {
40  typename IndexMap::iterator it = myIndices.find(idx);
41 
42  if (it == myIndices.end())
43  {
44  exint order = myOrder.append(idx);
45  myIndices.insert(std::make_pair(idx, order));
46  }
47  else
48  {
49  // Just update the order. The newly added entry gets put last.
50  myOrder(it->second) = tombstone<INDEX>();
51  it->second = myOrder.append(idx);
52  }
53  }
54 
55  // This method is safe to use while iterating over this ordered group
56  // because it doesn't change the size of myOrder. Should this ever
57  // change, all calling code will need to be examined to determine if
58  // it needs to be updated.
59  bool erase(const INDEX &idx)
60  {
61  typename IndexMap::const_iterator it = myIndices.find(idx);
62 
63  if (it == myIndices.end())
64  return false;
65 
66  exint order = it->second;
67  myOrder(order) = tombstone<INDEX>();
68 
69  myIndices.erase(it);
70  myCompact = false;
71 
72  return true;
73  }
74 
75  void clear()
76  {
77  myIndices.clear();
78  myOrder.clear();
79  myCompact = true;
80  }
81 
82  bool contains(const INDEX &idx) const
83  {
84  // The order doesn't matter for is-member search.
85  return myIndices.find(idx) != myIndices.end();
86  }
87 
88  bool contains(const INDEX &idx, INDEX &contained_idx) const
89  {
90  // The order doesn't matter for is-member search.
91  typename IndexMap::const_iterator it = myIndices.find(idx);
92 
93  if (it != myIndices.end())
94  {
95  contained_idx = myOrder(it->second);
96  return true;
97  }
98 
99  return false;
100  }
101 
102  // For sizing, the index list is the most authoritative one.
103  size_t size() const { return myIndices.size(); }
104 
105  bool empty() const { return myIndices.empty(); }
106 
107  // Simple adapter to skip over tombstones when iterating over indices
109  {
110  public:
111  using iterator_category = std::forward_iterator_tag;
112  using value_type = const INDEX;
113  using difference_type = std::ptrdiff_t;
114  using pointer = value_type*;
116 
117  const INDEX &operator *() { return *myIt; }
118 
119  bool operator==(const const_iterator &it) const
120  { return myIt == it.myIt; }
121  bool operator!=(const const_iterator &it) const
122  { return myIt != it.myIt; }
123 
125  {
126  // Skip over tombstones so our user doesn't see them.
127  do { ++myIt; } while(myIt != myEnd && *myIt == tombstone<INDEX>());
128  return *this;
129  }
130  protected:
131  friend class GU_OrderedIndexGroup;
133  const typename IndexOrder::const_iterator &end)
134  : myIt(it), myEnd(end)
135  {
136  // Fast forward until we're no longer looking at tombstones
137  while(myIt != myEnd && *myIt == tombstone<INDEX>())
138  ++myIt;
139  }
140  private:
141  typename IndexOrder::const_iterator myIt, myEnd;
142  };
143  typedef const_iterator iterator;
144 
145  const_iterator begin() const
146  {
147  return const_iterator(myOrder.begin(), myOrder.end());
148  }
149  const_iterator end() const
150  {
151  return const_iterator(myOrder.end(), myOrder.end());
152  }
153 
154  void dump(std::ostream &os) const
155  {
156  os << "Indices: ";
157  for(const typename IndexMap::value_type &oi : myIndices)
158  os << "[ " << oi.first << ", " << oi.second << "] ";
159  os << "\n";
160  os << "Order: " << myOrder << "\n";
161  }
162 
163 
165  {
166  myIndices.swap(group.myIndices);
167  myOrder.swap(group.myOrder);
168  std::swap(myCompact, group.myCompact);
169  }
170 
171  void compact()
172  {
173  if (myCompact)
174  return;
175 
176  // Create a remapping array for the new order. We use this to move
177  // items in the order list into their new positions and also to modify
178  // the order stored in the index list.
179  UT_Array<exint> order_remap;
180 
181  exint order = 0;
182  order_remap.setSizeNoInit(myOrder.size());
183  for (int i = 0, ie = myOrder.size(); i < ie; i++)
184  {
185  if (myOrder(i) == tombstone<INDEX>())
186  order_remap(i) = -1;
187  else
188  {
189  // Shift entries down in the order array.
190  myOrder(order) = myOrder(i);
191  order_remap(i) = order++;
192  }
193  }
194 
195  myOrder.truncate(order);
196 
197  // Now map the order stored in the index list to the new order as
198  // represented in the order array.
199  // Note that unordered_set iterators are always constant, but since the
200  // order field doesn't contribute to equivalence, it's mutable and we
201  // can change it at will without affecting the order of the set.
202  for(typename IndexMap::value_type &oi : myIndices)
203  {
204  oi.second = order_remap(oi.second);
205  }
206 
207  myCompact = true;
208  }
209 
210  int64 getMemoryUsage(bool inclusive) const
211  {
212  int64 mem = inclusive ? sizeof(*this) : 0;
213  // Compute size of unordered_multiset, see UT_Set.h for original.
214  mem += myIndices.bucket_count() * sizeof(void*);
215  mem += myIndices.size() * (sizeof(size_t) + sizeof(void*) + sizeof(INDEX));
216  mem += myOrder.getMemoryUsage(false);
217  return mem;
218  }
219 
220 private:
221  IndexMap myIndices;
222  IndexOrder myOrder;
223  bool myCompact;
224 };
225 
226 #endif // __GU_OrderedIndexGroup__
bool erase(const INDEX &idx)
const_iterator begin() const
bool operator!=(const const_iterator &it) const
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1699
bool contains(const INDEX &idx, INDEX &contained_idx) const
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:719
int64 exint
Definition: SYS_Types.h:125
int64 getMemoryUsage(bool inclusive=false) const
Definition: UT_Array.h:681
void append(const INDEX &idx)
void clear()
Definition: UT_Map.h:191
exint size() const
Definition: UT_Array.h:667
const_iterator(const typename IndexOrder::const_iterator &it, const typename IndexOrder::const_iterator &end)
int64 getMemoryUsage(bool inclusive) const
void swap(GU_OrderedIndexGroup &group)
GLuint GLuint end
Definition: glcorearb.h:475
INDEX tombstone()
iterator begin()
Definition: UT_Array.h:1039
GLdouble GLdouble GLint GLint order
Definition: glad.h:2676
long long int64
Definition: SYS_Types.h:116
Base::iterator iterator
Definition: UT_Map.h:124
void dump(std::ostream &os) const
exint append()
Definition: UT_Array.h:142
std::forward_iterator_tag iterator_category
const_iterator end() const
bool contains(const INDEX &idx) const
base_iterator< const INDEX, true > const_iterator
Definition: UT_Array.h:1032
void truncate(exint maxsize)
Decreases, but never expands, to the given maxsize.
Definition: UT_Array.h:747
Base::value_type value_type
Definition: UT_Map.h:121
void clear()
Resets list to an empty list.
Definition: UT_Array.h:753
Base::const_iterator const_iterator
Definition: UT_Map.h:125
void swap(UT_Array< T > &other)
Definition: UT_ArrayImpl.h:688
iterator end()
End iterator.
Definition: UT_Array.h:1044
bool operator==(const const_iterator &it) const