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) { return myIt == it.myIt; }
120  bool operator!=(const const_iterator &it) { return myIt != it.myIt; }
121 
123  {
124  // Skip over tombstones so our user doesn't see them.
125  do { ++myIt; } while(myIt != myEnd && *myIt == tombstone<INDEX>());
126  return *this;
127  }
128  protected:
129  friend class GU_OrderedIndexGroup;
131  const typename IndexOrder::const_iterator &end)
132  : myIt(it), myEnd(end)
133  {
134  // Fast forward until we're no longer looking at tombstones
135  while(myIt != myEnd && *myIt == tombstone<INDEX>())
136  ++myIt;
137  }
138  private:
139  typename IndexOrder::const_iterator myIt, myEnd;
140  };
141  typedef const_iterator iterator;
142 
143  const_iterator begin() const
144  {
145  return const_iterator(myOrder.begin(), myOrder.end());
146  }
147  const_iterator end() const
148  {
149  return const_iterator(myOrder.end(), myOrder.end());
150  }
151 
152  void dump(std::ostream &os) const
153  {
154  os << "Indices: ";
155  for(const typename IndexMap::value_type &oi : myIndices)
156  os << "[ " << oi.first << ", " << oi.second << "] ";
157  os << "\n";
158  os << "Order: " << myOrder << "\n";
159  }
160 
161 
163  {
164  myIndices.swap(group.myIndices);
165  myOrder.swap(group.myOrder);
166  std::swap(myCompact, group.myCompact);
167  }
168 
169  void compact()
170  {
171  if (myCompact)
172  return;
173 
174  // Create a remapping array for the new order. We use this to move
175  // items in the order list into their new positions and also to modify
176  // the order stored in the index list.
177  UT_Array<exint> order_remap;
178 
179  exint order = 0;
180  order_remap.setSizeNoInit(myOrder.size());
181  for (int i = 0, ie = myOrder.size(); i < ie; i++)
182  {
183  if (myOrder(i) == tombstone<INDEX>())
184  order_remap(i) = -1;
185  else
186  {
187  // Shift entries down in the order array.
188  myOrder(order) = myOrder(i);
189  order_remap(i) = order++;
190  }
191  }
192 
193  myOrder.truncate(order);
194 
195  // Now map the order stored in the index list to the new order as
196  // represented in the order array.
197  // Note that unordered_set iterators are always constant, but since the
198  // order field doesn't contribute to equivalence, it's mutable and we
199  // can change it at will without affecting the order of the set.
200  for(typename IndexMap::value_type &oi : myIndices)
201  {
202  oi.second = order_remap(oi.second);
203  }
204 
205  myCompact = true;
206  }
207 
208  int64 getMemoryUsage(bool inclusive) const
209  {
210  int64 mem = inclusive ? sizeof(*this) : 0;
211  // Compute size of unordered_multiset, see UT_Set.h for original.
212  mem += myIndices.bucket_count() * sizeof(void*);
213  mem += myIndices.size() * (sizeof(size_t) + sizeof(void*) + sizeof(INDEX));
214  mem += myOrder.getMemoryUsage(false);
215  return mem;
216  }
217 
218 private:
219  IndexMap myIndices;
220  IndexOrder myOrder;
221  bool myCompact;
222 };
223 
224 #endif // __GU_OrderedIndexGroup__
bool erase(const INDEX &idx)
const_iterator begin() 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:1631
bool contains(const INDEX &idx, INDEX &contained_idx) const
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:695
int64 exint
Definition: SYS_Types.h:125
int64 getMemoryUsage(bool inclusive=false) const
Definition: UT_Array.h:657
void append(const INDEX &idx)
void clear()
Definition: UT_Map.h:184
exint size() const
Definition: UT_Array.h:646
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:986
GLdouble GLdouble GLint GLint order
Definition: glad.h:2676
long long int64
Definition: SYS_Types.h:116
Base::iterator iterator
Definition: UT_Map.h:117
void dump(std::ostream &os) const
exint append()
Definition: UT_Array.h:142
bool operator!=(const const_iterator &it)
std::forward_iterator_tag iterator_category
const_iterator end() const
bool contains(const INDEX &idx) const
bool operator==(const const_iterator &it)
base_iterator< const INDEX, true > const_iterator
Definition: UT_Array.h:979
void truncate(exint maxsize)
Decreases, but never expands, to the given maxsize.
Definition: UT_Array.h:710
Base::value_type value_type
Definition: UT_Map.h:114
void clear()
Resets list to an empty list.
Definition: UT_Array.h:716
Base::const_iterator const_iterator
Definition: UT_Map.h:118
void swap(UT_Array< T > &other)
Definition: UT_ArrayImpl.h:676
iterator end()
End iterator.
Definition: UT_Array.h:991