HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GA_OffsetList.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: GA_OffsetList.h ( GA Library, C++)
7  *
8  * COMMENTS: Class to store a list of offsets/indices based on the
9  * GA_Offset/GA_Index types.
10  */
11 
12 #ifndef __GA_OffsetList__
13 #define __GA_OffsetList__
14 
15 #include "GA_API.h"
16 
17 #include "GA_Types.h"
18 
19 #include <UT/UT_ArrayHelp.h>
20 #include <UT/UT_Array.h>
21 #include <UT/UT_VectorTypes.h>
22 
23 #include <SYS/SYS_AtomicInt.h>
24 #include <SYS/SYS_Inline.h>
25 #include <SYS/SYS_Math.h>
26 #include <SYS/SYS_Types.h>
27 
28 class GA_Defragment;
29 class GA_LoadMap;
30 class GA_SaveMap;
31 class GA_IndexMap;
32 class UT_JSONParser;
33 class UT_JSONWriter;
34 class UT_MemoryCounter;
35 
36 #define GA_OFFSETLIST_VERBOSE_DEBUG 0
37 
38 // Forward declaration of subclass for use in superclass
39 template<typename FromType,typename ToType,typename INT_TYPE>
41 
42 /// GA_OffsetList implements an array of GA_Offsets.
43 /// Copy-on-write is used to reduce memory usage and make the copying of a
44 /// GA_OffsetList an inexpensive operation.
45 ///
46 /// See also: @ref JSON-GA_OffsetList
47 template <typename FromType, typename ToType, typename INT_TYPE=exint>
49 {
50 protected:
51  // These friend declarations are needed for accessing data in related types.
52  template<typename FromType2,typename ToType2,typename INT_TYPE2>
53  friend class GA_ListTypeRef;
54  template<typename FromType2,typename ToType2,typename INT_TYPE2>
55  friend class GA_ListType;
56 public:
57  typedef INT_TYPE theIntType;
58 protected:
59 
60  // The shareable data stored in a GA_OffsetList
62  {
63  public:
64  static ListTypeData *allocate(exint capacity)
65  {
66  // NOTE: We should really try to fix the cases where we're
67  // allocating this with capacity zero, but we have to
68  // validate that it's safe to switch it to trivial instead,
69  // given the comment in changeSize() about it needing to be
70  // safe to call GA_IndexMap::compactIndices() and
71  // GA_IndexMap::isTrivial() at the same time, and needing
72  // for isTrivial() to return false.
73  //UT_ASSERT_MSG_P(capacity >= 1, "Why are we allocating something empty?");
74  exint bytes = sizeof(ListTypeData) + sizeof(INT_TYPE)*capacity;
75  ListTypeData *data = (ListTypeData *)malloc(bytes);
76  data->myRefCount.relaxedStore(1);
77  data->myCapacity = capacity;
78 #if GA_OFFSETLIST_VERBOSE_DEBUG
79  printf("Allocating %p with ref count 1 and capacity %d\n", data, int(capacity));
80  fflush(stdout);
81 #endif
82  return data;
83  }
84  ListTypeData *reallocate(exint new_capacity)
85  {
86  // See NOTE above about fixing cases where we're allocating this
87  // with capacity zero.
88  //UT_ASSERT_MSG_P(new_capacity >= 1, "Why are we allocating something empty?");
89  UT_ASSERT_P(myRefCount.relaxedLoad() == 1);
90 
91  ListTypeData *that = (ListTypeData *)realloc(this, sizeof(ListTypeData) + sizeof(INT_TYPE)*new_capacity);
92  // NOTE: this may no longer be valid, so we can't use it after this point.
93 
94 #if GA_OFFSETLIST_VERBOSE_DEBUG
95  printf("Reallocating %p to %p with ref count %d from capacity %d to %d\n", this, that, int(that->myRefCount.relaxedLoad()), int(that->myCapacity), int(new_capacity));
96  fflush(stdout);
97 #endif
98 
99  that->myCapacity = new_capacity;
100  return that;
101  }
103  {
104  UT_ASSERT_P(myRefCount.relaxedLoad() == 1);
105  if (myCapacity >= mincapacity)
106  return this;
107 
108  mincapacity = SYSmax(mincapacity, UTbumpAlloc(myCapacity));
109  ListTypeData *that = reallocate(mincapacity);
110  // NOTE: this may no longer be valid, so we can't use it after this point.
111  return that;
112  }
114  {
115  UT_ASSERT_P(myRefCount.relaxedLoad() == 1);
116  if (myCapacity == new_capacity)
117  return this;
118 
119  ListTypeData *that = reallocate(new_capacity);
120  // NOTE: this may no longer be valid, so we can't use it after this point.
121  return that;
122  }
123  ListTypeData *copy(exint size,exint new_capacity) const
124  {
125  ListTypeData *that = allocate(new_capacity);
126  INT_TYPE *dest = that->getRawData();
127  const INT_TYPE *src = getRawData();
128  if (new_capacity < size)
129  size = new_capacity;
130  for (exint i = 0; i < size; ++i)
131  dest[i] = src[i];
132  return that;
133  }
134 
135  // methods to manage sharing
136  void ref() const
137  {
138 #if GA_OFFSETLIST_VERBOSE_DEBUG
139  exint new_count =
140 #endif
141  myRefCount.add(1);
142 #if GA_OFFSETLIST_VERBOSE_DEBUG
143  printf("Incrementing ref of %p with capacity %d from %d to %d\n", this, int(myCapacity), int(new_count-1), int(new_count));
144  fflush(stdout);
145  if (new_count < 0)
146  {
147  printf("!!! ERROR: NEGATIVE REF COUNT INCREMENTED on %p !!!", this);
148  fflush(stdout);
149  }
150 #endif
151  }
152  void unref()
153  {
154  exint new_count = myRefCount.add(-1);
155 #if GA_OFFSETLIST_VERBOSE_DEBUG
156  printf("Decrementing ref of %p with capacity %d from %d to %d\n", this, int(myCapacity), int(new_count+1), int(new_count));
157  fflush(stdout);
158  if (new_count < 0)
159  {
160  printf("!!! ERROR: NEGATIVE REF COUNT DECREMENTED on %p !!!", this);
161  fflush(stdout);
162  }
163 #endif
164  UT_ASSERT_P(new_count >= 0);
165  if (new_count == 0)
166  {
167  free(this);
168  }
169  }
170  bool isShared() const
171  { return myRefCount.relaxedLoad() != 1; }
172 
174  int64 getMemoryUsage(bool inclusive) const
175  { return (inclusive ? sizeof(*this) : 0) + sizeof(INT_TYPE)*myCapacity; }
176 
177  void countMemory(UT_MemoryCounter &counter, bool inclusive) const;
178 
181  { return myCapacity; }
182 
183  bool isTrivial(exint size) const
184  {
185  if (size > 1)
186  {
187  const INT_TYPE *start = getRawData();
188  const INT_TYPE offset = start[0];
189  for (INT_TYPE i = 1; i < size; i++)
190  {
191  if (start[i] != offset+i)
192  return false;
193  }
194  }
195  return true;
196  }
197 
198  bool isAscending(exint size) const
199  {
200  if (size > 1)
201  {
202  const INT_TYPE *data = getRawData();
203  INT_TYPE prev = data[0];
204  for (exint i = 1; i < size; i++)
205  {
206  INT_TYPE cur = data[i];
207  if (cur < prev)
208  return false;
209  prev = cur;
210  }
211  }
212  return true;
213  }
214 
215  // Set the entries...
216  // in a bizarre way whose motivations I don't really understand.
217  // Maybe someday I'll clean up the changing of size/capacity for GA_ListType.
218  ListTypeData *setEntries(GA_Size sz, exint old_size, bool doresize=true);
219 
220  // adding and removing elements
221  FromType insert(FromType index, ToType value, FromType size);
222  FromType multipleInsert(FromType index, GA_Size count, FromType size);
223  FromType remove(FromType i, FromType size)
224  {
225  if (i < FromType(0) || i >= size)
226  return FromType(-1);
227 
228  INT_TYPE *start = getRawData();
229  for (FromType j = i+1; j < size; ++j)
230  {
231  start[j-1] = start[j];
232  }
233  return i;
234  }
235  FromType findAndRemove(ToType v, FromType size)
236  {
237  INT_TYPE *array = getRawData();
238  INT_TYPE *p = array;
239  const INT_TYPE *end = array + size;
240  for (; p != end; ++p)
241  {
242  if (ToType(*p) == v)
243  {
244  FromType idx(p - array);
245  for (FromType j = idx+1; j < size; ++j)
246  {
247  array[j-1] = array[j];
248  }
249  return idx;
250  }
251  }
252  return FromType(-1);
253  }
254  GA_Size removeAll(ToType v, FromType size)
255  {
256  INT_TYPE *start = getRawData();
257  const INT_TYPE *src = start;
258  const INT_TYPE *end = start + size;
259  INT_TYPE *dest = start;
260  for (; src != end; ++src)
261  {
262  if (*src != INT_TYPE(v))
263  {
264  if (dest != src)
265  *dest = *src;
266  ++dest;
267  }
268  }
269  return dest-start;
270  }
271  FromType find(ToType v, FromType s, FromType size) const
272  {
273  const INT_TYPE *array = getRawData();
274  const INT_TYPE *p = array + s;
275  const INT_TYPE *end = array + size;
276  for (; p != end; ++p)
277  {
278  if (ToType(*p) == v)
279  return FromType(p - array);
280  }
281  return FromType(-1);
282  }
283  FromType findSorted(ToType v, FromType s, FromType size) const;
284 
285  // basic accessors
287  INT_TYPE &operator()(exint index)
288  {
289  return ((INT_TYPE *)(this+1))[index];
290  }
292  const INT_TYPE &operator()(exint index) const
293  {
294  return ((const INT_TYPE *)(this+1))[index];
295  }
297  void set(FromType index, ToType value)
298  { (*this)(index) = value; }
300  ToType get(FromType index) const
301  { return ToType((*this)(index)); }
302  void constant(ToType value, FromType size)
303  {
304  INT_TYPE *start = getRawData();
305  for (INT_TYPE i = 0; i < INT_TYPE(size); ++i)
306  start[i] = INT_TYPE(value);
307  }
308 
309  template<typename S>
310  void set(const S *data, exint size, ToType offset)
311  {
312  UT_ASSERT_P(myCapacity >= size);
313  INT_TYPE *array = getRawData();
314  if (offset == ToType(0))
315  {
316  for (exint i = 0; i < size; ++i)
317  array[i] = ToType(data[i]);
318  }
319  else
320  {
321  for (exint i = 0; i < size; ++i)
322  array[i] = ToType(data[i]) + offset;
323  }
324  }
325  template<typename S>
326  void copyAdd(FromType destindex, const S *values, GA_Size srcindex, GA_Size n, ToType offset)
327  {
328  INT_TYPE *array = getRawData();
329  for (GA_Size i = 0; i < n; ++i)
330  array[i + destindex] = values[i + srcindex] + offset;
331  }
332  template<typename S>
333  void copyAdd(FromType destindex, const GA_ListTypeRef<FromType, ToType, S> &values, FromType srcindex, GA_Size n, ToType offset)
334  {
335  INT_TYPE *array = getRawData();
336  if (values.isTrivial())
337  {
338  ToType combined = values.myTrivialOffset + GA_Size(srcindex) + offset;
339  for (GA_Size i = 0; i < n; ++i)
340  array[i + destindex] = combined + i;
341  }
342  else
343  {
344  const S *src = values.myData->getRawData();
345  for (GA_Size i = 0; i < n; ++i)
346  array[i + destindex] = src[i + srcindex] + offset;
347  }
348  }
349 
350  void cycle(GA_Size howMany, FromType size)
351  {
352  // This looks silly, I know, but I didn't want to have to
353  // verify that UT_Array::cycle goes in the same direction
354  // as std::rotate, and cycle has some edge case handling,
355  // e.g. for negative values.
356  UT_Array<INT_TYPE> array;
357  array.unsafeShareData(getRawData(), size);
358  array.cycle(howMany);
359  array.unsafeClearData();
360  }
361  void reverse(FromType size)
362  {
363  INT_TYPE *array = getRawData();
364  std::reverse(array, array+size);
365  }
366 
367  void sortAscending(FromType size)
368  {
369  INT_TYPE *array = getRawData();
370  std::sort(array, array+size, std::less<INT_TYPE>());
371  }
372 
373  FromType sortAndRemoveDuplicates(FromType size)
374  {
375  if (size <= FromType(1))
376  return size;
377 
378  INT_TYPE *array = getRawData();
379  INT_TYPE *end = array + size;
380  std::sort(array, end, std::less<INT_TYPE>());
381 
382  // Sorted remove duplicates
383  const INT_TYPE *src = array+1;
384  INT_TYPE *dest = array+1;
385  INT_TYPE prev = array[0];
386  for (; src != end; ++src)
387  {
388  INT_TYPE cur = *src;
389  if (cur != prev)
390  {
391  if (dest != src)
392  *dest = cur;
393  prev = cur;
394  ++dest;
395  }
396  }
397  return FromType(dest-array);
398  }
399 
400  FromType findInRange(FromType start, FromType end, ToType search) const
401  {
402  const INT_TYPE *array = getRawData();
403  for ( ; start < end; start++)
404  {
405  if (ToType(array[start]) == search)
406  return start;
407  }
408  return end;
409  }
410  FromType findInRangeNotEqual(FromType start, FromType end, ToType search) const
411  {
412  const INT_TYPE *array = getRawData();
413  for ( ; start < end; start++)
414  {
415  if (ToType(array[start]) != search)
416  return start;
417  }
418  return end;
419  }
420 
421  FromType findValidInRange(FromType start, FromType end) const
422  {
423  const INT_TYPE *array = getRawData();
424  for ( ; start < end; start++)
425  {
426  if (GAisValid(GA_Size(array[start])))
427  return start;
428  }
429  return end;
430  }
431  FromType findInvalidInRange(FromType start, FromType end) const
432  {
433  const INT_TYPE *array = getRawData();
434  for ( ; start < end; start++)
435  {
436  if (!GAisValid(GA_Size(array[start])))
437  return start;
438  }
439  return end;
440  }
441 
443  const INT_TYPE *getRawData() const
444  {
445  return (const INT_TYPE *)(this+1);
446  }
448  INT_TYPE *getRawData()
449  {
450  return (INT_TYPE *)(this+1);
451  }
452 
453  private:
454  // We use a SYS_AtomicCounter to avoid losing references when multiple
455  // threads add and remove references to the shared values
456  mutable SYS_AtomicCounter myRefCount;
457  exint myCapacity;
458  };
459 
460 public:
461  /// Default constructor
463  explicit GA_ListTypeRef()
464  {
465  // Unlike in subclass, leave the data uninitialized until assigned,
466  // because this class doesn't need to own its data.
467  }
468 
469  /// Copy constructor
472  {
473 #if GA_OFFSETLIST_VERBOSE_DEBUG
474  if (!src.isTrivial())
475  {
476  printf("%p listref copy constructor with data %p from %p\n", this, src.myData, &src);
477  fflush(stdout);
478  }
479 #endif
480  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
481  memcpy(this, &src, sizeof(*this));
482  }
483 
484  /// Move constructor
487  {
488 #if GA_OFFSETLIST_VERBOSE_DEBUG
489  if (!src.isTrivial())
490  {
491  printf("%p listref move constructor with data %p from %p\n", this, src.myData, &src);
492  fflush(stdout);
493  }
494 #endif
495  memcpy(this, &src, sizeof(*this));
496  }
497 private:
498  /// Move constructor from subclass owning myData is forbidden
500  {
501  UT_ASSERT_MSG(0,"GA_ListTypeRef cannot be move-constructed from GA_ListType, because the data will be invalid momentarily.");
502  }
503 public:
504 
505  /// Trivial list constructor
507  GA_ListTypeRef(ToType startvalue, GA_Size size, bool flag_set=false)
508  {
509  myIsTrivial = true;
510  myTrivialOffset = startvalue;
511  myIsFlagSet = flag_set;
512  mySize = size;
513  }
514 
515  /// Destructor
518  {
519  // Nothing to do, since this class doesn't own its data;
520  // only the subclass does.
521  }
522 
523  /// Copy assignment operator
526  {
527 #if GA_OFFSETLIST_VERBOSE_DEBUG
528  if (!src.isTrivial())
529  {
530  printf("%p listref copy constructor with data %p from %p\n", this, src.myData, &src);
531  fflush(stdout);
532  }
533 #endif
534  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
535  memcpy(this, &src, sizeof(*this));
536  return *this;
537  }
538 
539  /// Move assignment operator
542  {
543 #if GA_OFFSETLIST_VERBOSE_DEBUG
544  if (!src.isTrivial())
545  {
546  printf("%p listref move constructor with data %p from %p\n", this, src.myData, &src);
547  fflush(stdout);
548  }
549 #endif
550  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
551  memcpy(this, &src, sizeof(*this));
552  return *this;
553  }
554 private:
555  /// Move constructor from subclass owning myData is forbidden
557  {
558  UT_ASSERT_MSG(0,"GA_ListTypeRef cannot be move-assigned from GA_ListType, because the data will be invalid momentarily.");
559  return *this;
560  }
561 public:
562 
563  /// clear removes all of the entries
565  void clear()
566  {
567  // NOTE: Subclass clear will unref myData if non-trivial.
568  myIsTrivial = true;
569  // NOTE: DON'T set myIsFlagSet, since it's independent of whether
570  // this list is clear.
571  myTrivialOffset = 0;
572  mySize = 0;
573  }
574 
575  /// Makes the list a trivial list with the specified start value and size
577  void setTrivial(ToType startvalue, GA_Size size)
578  {
579  UT_ASSERT(size >= 0);
580  myIsTrivial = true;
581  myTrivialOffset = startvalue;
582  mySize = size;
583  }
584 
585  /// Makes the list a trivial list with the specified start value and size,
586  /// and also sets the extra flag.
588  void setTrivial(ToType startvalue, GA_Size size, bool flag)
589  {
590  UT_ASSERT(size >= 0);
591  myIsTrivial = true;
592  myTrivialOffset = startvalue;
593  mySize = size;
594  myIsFlagSet = flag;
595  }
596 
597  /// Returns the allocated capacity of the list
600  {
601  return isTrivial() ? 0 : myData->capacity();
602  }
603  /// Returns the number of used elements in the list (always <= capacity())
605  FromType entries() const
606  { return size(); }
607  /// Returns the number of used elements in the list (always <= capacity())
609  FromType size() const
610  {
611  return FromType(mySize);
612  }
613  /// Check whether this offset list is stored in a compact
614  /// (non-allocated) form.
615  /// NOTE: It *must* be threadsafe to call this while hardening
616  /// a non-trivial list and get false as a return value.
617  /// GA_IndexMap::compactIndices() may be called at the same
618  /// time as GA_IndexMap::isTrivial(), and this *must*
619  /// return false, no matter what the race.
621  bool isTrivial() const { return myIsTrivial != 0; }
623  bool getExtraFlag() const { return myIsFlagSet != 0; }
625  void setExtraFlag(bool v) { myIsFlagSet = v; }
626 
627  // Returns true iff this and that are either both trivial and equal
628  // or if both are not trivial and share the same ListTypeData pointer.
629  // This does not fully check for equality!
630  bool isSame(const GA_ListTypeRef &that) const
631  {
632  if (isTrivial())
633  {
634  return (that.isTrivial() &&
635  (mySize == that.mySize) &&
636  (myTrivialOffset == that.myTrivialOffset));
637  }
638  return (myData == that.myData);
639  }
640 
641  /// Identifies whether the data is in ascending order
642  bool isAscending() const;
643 
644  /// Linearly search for the specified entry. Returns the index of first
645  /// matching element found, -1 otherwise. An optional starting index can
646  /// be specified in s.
647  FromType find(ToType value, FromType s = FromType(0)) const;
648 
649  /// Find the target in a sorted list.
650  FromType findSorted(ToType value, FromType s=FromType(0)) const;
651 
652  /// Get the the value at the index
654  ToType get(FromType index) const
655  {
656  UT_ASSERT_P(index >= FromType(0) && index < size());
657  return isTrivial()
658  ? ToType(GA_Size(index)+myTrivialOffset)
659  : myData->get(index);
660  }
661 
662  /// Returns the start, assuming this list is trivial.
664  ToType trivialStart() const
665  {
666  UT_ASSERT_P(isTrivial());
667  return ToType(myTrivialOffset);
668  }
669 
670  /// Test a sub-block for equality with another list
671  bool isEqual(const GA_ListTypeRef &other,
672  FromType start, FromType end) const;
673 
674  /// Return the value of the last element
675  ToType last() const
676  {
677  exint last_index = mySize-1;
678  return isTrivial()
679  ? ToType(myTrivialOffset+last_index)
680  : myData->get(FromType(last_index));
681  }
682 
683  /// Convenience () operator to access the list entries
685  ToType operator()(FromType i) const { return get(i); }
686 
687  /// Finds the first instance of the search pattern in the given
688  /// range. Returns end if not found.
689  FromType findInRange(FromType start, FromType end, ToType search) const
690  {
691  if (isTrivial())
692  {
693  FromType matchingindex = FromType(GA_Size(search) - GA_Size(myTrivialOffset));
694  if (matchingindex >= start && matchingindex < end)
695  return matchingindex;
696  // No match.
697  return end;
698  }
699  return myData->findInRange(start, end, search);
700  }
701  FromType findInRangeNotEqual(FromType start, FromType end, ToType search) const
702  {
703  if (isTrivial())
704  {
705  FromType matchingindex = FromType(GA_Size(search) - GA_Size(myTrivialOffset));
706  // start is always a match. If not, start+1 is.
707  if (matchingindex != start)
708  return start;
709  start += 1;
710  if (start > end)
711  return end;
712  return start;
713  }
714  return myData->findInRangeNotEqual(start, end, search);
715  }
716  FromType findValidInRange(FromType start, FromType end) const
717  {
718  if (isTrivial())
719  {
720  // NOTE: We can have trivial lists with negative offsets!
721  // If we have a valid trivial offset, everything matches.
722  if (GAisValid(myTrivialOffset))
723  return start;
724  if (GAisValid(ToType(GA_Size(start)) + ToType(myTrivialOffset)))
725  return start;
726  return SYSmin(end, FromType(-GA_Size(myTrivialOffset)));
727  }
728  return myData->findValidInRange(start, end);
729  }
730  FromType findInvalidInRange(FromType start, FromType end) const
731  {
732  if (isTrivial())
733  {
734  // NOTE: We can have trivial lists with negative offsets!
735  // If we have a valid trivial offset or start, nothing matches.
736  if (GAisValid(myTrivialOffset))
737  return end;
738  if (GAisValid(ToType(GA_Size(start)) + ToType(myTrivialOffset)))
739  return end;
740  return start;
741  }
742  return myData->findInvalidInRange(start, end);
743  }
744 
745  /// Calls a functor (e.g. a lambda) for each entry, only checking
746  /// for triviality once, to reduce overhead.
747  template<typename FUNCTOR>
749  void forEach(FUNCTOR &&functor) const
750  {
751  if (myIsTrivial)
752  {
753  ToType value(myTrivialOffset);
754  const ToType end(value + mySize);
755  for (; value != end; ++value)
756  {
757  functor(value);
758  }
759  }
760  else
761  {
762  const INT_TYPE *data = myData->getRawData();
763  const INT_TYPE *const end = data + mySize;
764  for (; data != end; ++data)
765  {
766  functor(ToType(*data));
767  }
768  }
769  }
770 
771  /// Report memory usage (includes all shared memory)
773  int64 getMemoryUsage(bool inclusive) const
774  {
775  return (inclusive ? sizeof(*this) : 0) + (!isTrivial() ? myData->getMemoryUsage(true) : 0);
776  }
777 
778 protected:
779  static const intptr_t POINTER_MASK = ~0x1;
780  static const intptr_t TRIVIAL_MASK = 0x1;
781  static const intptr_t FLAG_MASK = 0x1;
782 #ifndef SESI_LITTLE_ENDIAN
783 #error "Make sure the bitfields in the union work on big endian platforms!"
784 #endif
785  union {
786  ListTypeData *myData;
787  struct {
788  // NOTE: myTrivialOffset must be signed to support
789  // GA_INVALID_OFFSET and GA_INVALID_INDEX, but
790  // mySize can be unsigned.
791  int64 myIsTrivial:1;
792  int64 myTrivialOffset:63;
793  // Make sure that this flag doesn't overlap with the
794  // pointer, so that it doesn't need to be considered
795  // when reading/writing myData. myIsTrivial
796  // can overlap with myData, because it's
797  // mutually exclusive with using myData.
798  uint64 myIsFlagSet:1;
799  uint64 mySize:63;
800  };
801  };
802 };
803 
804 template <typename FromType, typename ToType, typename INT_TYPE=exint>
805 class GA_API GA_ListType : public GA_ListTypeRef<FromType, ToType, INT_TYPE>
806 {
807 private:
808  // These friend declarations are needed for accessing data in related types.
809  template<typename FromType2,typename ToType2,typename INT_TYPE2>
810  friend class GA_ListTypeRef;
811  template<typename FromType2,typename ToType2,typename INT_TYPE2>
812  friend class GA_ListType;
813 
815 protected:
816  using Base::myData;
817  using Base::myIsTrivial;
818  using Base::myTrivialOffset;
819  using Base::myIsFlagSet;
820  using Base::mySize;
821  using Base::POINTER_MASK;
822  using Base::TRIVIAL_MASK;
823  using Base::FLAG_MASK;
824  // I don't know why one build machine running GCC 4.8 needed
825  // "ListTypeData =" and the other didn't, but I've put it here
826  // anyway, because it should keep everyone happy.
827  using ListTypeData = typename Base::ListTypeData;
828 public:
829  using Base::get;
830  using Base::isTrivial;
831  using Base::size;
832  using Base::capacity;
833  using typename Base::theIntType;
834 public:
835  /// Default constructor
837  explicit GA_ListType()
838  : Base()
839  {
840  myIsTrivial = true;
841  myTrivialOffset = 0;
842  myIsFlagSet = false;
843  mySize = 0;
844  }
845 
846  /// Copy constructor
849  : Base()
850  {
851  if (!src.isTrivial())
852  {
853 #if GA_OFFSETLIST_VERBOSE_DEBUG
854  printf("%p adding reference to %p (orig reference by list %p) in copy constructor\n", this, src.myData, &src);
855  fflush(stdout);
856 #endif
857  src.myData->ref();
858  }
859  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
860  memcpy(this, &src, sizeof(*this));
861  }
862 
863  /// Move constructor
866  : Base()
867  {
868 #if GA_OFFSETLIST_VERBOSE_DEBUG
869  if (!src.isTrivial())
870  {
871  printf("%p stealing reference to %p (orig reference by list %p) in move constructor\n", this, src.myData, &src);
872  fflush(stdout);
873  }
874 #endif
875  memcpy(this, &src, sizeof(*this));
876  src.myIsTrivial = true;
877  }
878 
879  /// Copy constructor from GA_ListTypeRef.
880  /// Although it may seem strange to have this at all, it should be
881  /// safe, since the destination does take (shared) ownership of any
882  /// non-trivial data. There should be a GA_ListType somewhere else
883  /// that already owns this.
885  explicit GA_ListType(const Base &src)
886  : Base()
887  {
888  if (!src.isTrivial())
889  {
890 #if GA_OFFSETLIST_VERBOSE_DEBUG
891  printf("%p adding reference to %p (orig reference by listref %p) in list(listref) type conversion constructor\n", this, src.myData, &src);
892  fflush(stdout);
893 #endif
894  src.myData->ref();
895  UT_ASSERT_MSG_P(src.myData->isShared(), "Something should have already owned this data.");
896  }
897  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
898  memcpy(this, &src, sizeof(*this));
899  }
900 
901  /// Trivial list constructor
903  GA_ListType(ToType startvalue, GA_Size size, bool flag_set=false)
904  : Base(startvalue, size, flag_set)
905  {}
906 
907  // This will construct a GA_ListType by copying a portion of the array.
908  GA_ListType(const UT_Array<ToType> &src, FromType start=FromType(0), FromType end=FromType(-1));
909 
910  /// Destructor
913  {
914  if (!isTrivial())
915  {
916 #if GA_OFFSETLIST_VERBOSE_DEBUG
917  printf("%p removing reference to %p in desctructor\n", this, myData);
918  fflush(stdout);
919 #endif
920  myData->unref();
921  }
922  }
923 
924  /// Copy assignment operator
927  {
928  if (!isTrivial())
929  {
930 #if GA_OFFSETLIST_VERBOSE_DEBUG
931  printf("%p removing reference to %p in copy assignment operator\n", this, myData);
932  fflush(stdout);
933 #endif
934  myData->unref();
935  }
936  if (!src.isTrivial())
937  {
938 #if GA_OFFSETLIST_VERBOSE_DEBUG
939  printf("%p adding reference to %p (orig reference by list %p) in copy assignment operator\n", this, src.myData, &src);
940  fflush(stdout);
941 #endif
942  src.myData->ref();
943  }
944  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
945  memcpy(this, &src, sizeof(*this));
946  return *this;
947  }
948 
949  /// Move assignment operator
952  {
953  if (!isTrivial())
954  {
955 #if GA_OFFSETLIST_VERBOSE_DEBUG
956  printf("%p removing reference to %p in move assignment operator\n", this, myData);
957  fflush(stdout);
958 #endif
959  myData->unref();
960  }
961 #if GA_OFFSETLIST_VERBOSE_DEBUG
962  if (!src.isTrivial())
963  {
964  printf("%p stealing reference to %p (orig reference by list %p) in move assignment operator\n", this, src.myData, &src);
965  fflush(stdout);
966  }
967 #endif
968  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
969  memcpy(this, &src, sizeof(*this));
970  src.myIsTrivial = true;
971  return *this;
972  }
973 
974  /// Copy assignment operator from GA_ListTypeRef.
975  /// Although it may seem strange to have this at all, it should be
976  /// safe, since the destination does take (shared) ownership of any
977  /// non-trivial data. There should be a GA_ListType somewhere else
978  /// that already owns this.
981  {
982  if (!isTrivial())
983  {
984 #if GA_OFFSETLIST_VERBOSE_DEBUG
985  printf("%p removing reference to %p in copy-from-listref assignment operator\n", this, myData);
986  fflush(stdout);
987 #endif
988  myData->unref();
989  }
990  if (!src.isTrivial())
991  {
992 #if GA_OFFSETLIST_VERBOSE_DEBUG
993  printf("%p adding reference to %p (orig reference by listref %p) in copy-from-listref assignment operator\n", this, src.myData, &src);
994  fflush(stdout);
995 #endif
996  src.myData->ref();
997  UT_ASSERT_MSG_P(src.myData->isShared(), "Something should have already owned this data.");
998  }
999  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
1000  memcpy(this, &src, sizeof(*this));
1001  return *this;
1002  }
1003 
1004  /// Count memory usage using a UT_MemoryCounter in order to count
1005  /// shared memory correctly.
1006  /// If inclusive is true, the size of this object is counted,
1007  /// else only memory owned by this object is counted.
1008  /// If this is pointed to by the calling object, inclusive should be true.
1009  /// If this is contained in the calling object, inclusive should be false.
1010  /// (Its memory was already counted in the size of the calling object.)
1011  void countMemory(UT_MemoryCounter &counter, bool inclusive) const;
1012 
1013  /// clear removes all of the entries
1015  void clear()
1016  {
1017  if (!isTrivial())
1018  {
1019 #if GA_OFFSETLIST_VERBOSE_DEBUG
1020  printf("%p removing reference to %p in clear function\n", this, myData);
1021  fflush(stdout);
1022 #endif
1023  myData->unref();
1024  }
1025  myIsTrivial = true;
1026  // NOTE: DON'T set myIsFlagSet, since it's independent of whether
1027  // this list is clear.
1028  myTrivialOffset = 0;
1029  mySize = 0;
1030  }
1031 
1032  /// Identifies whether the data is a trivial mapping and if so,
1033  /// eliminates storage for the map.
1034  void computeTrivial();
1035 
1036  /// Makes the list a trivial list with the specified start value and size
1037  void setTrivial(ToType startvalue, GA_Size size)
1038  {
1039  UT_ASSERT(size >= 0);
1040  if (!isTrivial())
1041  {
1042 #if GA_OFFSETLIST_VERBOSE_DEBUG
1043  printf("%p removing reference to %p in setTrivial(start,size)\n", this, myData);
1044  fflush(stdout);
1045 #endif
1046  myData->unref();
1047  myIsTrivial = true;
1048  }
1049  myTrivialOffset = startvalue;
1050  mySize = size;
1051  }
1052 
1053  /// Makes the list a trivial list with the specified start value and size,
1054  /// and also sets the extra flag.
1055  void setTrivial(ToType startvalue, GA_Size size, bool flag)
1056  {
1057  UT_ASSERT(size >= 0);
1058  if (!isTrivial())
1059  {
1060 #if GA_OFFSETLIST_VERBOSE_DEBUG
1061  printf("%p removing reference to %p in setTrivial(start,size,flag)\n", this, myData);
1062  fflush(stdout);
1063 #endif
1064  myData->unref();
1065  myIsTrivial = true;
1066  }
1067  myTrivialOffset = startvalue;
1068  mySize = size;
1069  myIsFlagSet = flag;
1070  }
1071 
1072  /// Set the number of entries - if the number is smaller than the current
1073  /// entries, the capacity may be decreased. If doresize is false,
1074  /// only the number of entries is changed, not the size.
1075  void setEntries(FromType sz, bool doresize=true);
1076  /// Reserve capacity for a number of entries (prevents reallocation as
1077  /// elements are appended).
1078  /// This does nothing if the list is currently trivial.
1079  void reserve(FromType mincapacity); // Reserve capacity
1080 
1081  /// If trivial, this sets the size to the minimum of the current size and new_capacity.
1082  /// If not trivial, this sets the capacity to new_capacity, (also correctly decreasing
1083  /// the size if currently greater than new_capacity.)
1084  void changeSize(FromType new_capacity);
1085 
1086  /// Add a single entry (may grow array)
1087  FromType append(ToType value)
1088  {
1089  if (isTrivial())
1090  {
1091  if (!mySize)
1092  {
1094  mySize = 1;
1095  return FromType(0);
1096  }
1097  if (value == ToType(myTrivialOffset) + mySize)
1098  {
1099  ++mySize;
1100  return FromType(mySize-1);
1101  }
1102  }
1103  harden(mySize+1);
1104  myData->set(FromType(mySize), value);
1105  ++mySize;
1106  return FromType(mySize-1);
1107  }
1108 
1109  /// Append all the entries from the source list. The offset will be added
1110  /// to each value in the source list.
1111  void append(const GA_ListType &src);
1112 
1113  /// Insert a single entry (may grow array)
1114  FromType insert(FromType i, ToType value);
1115 
1116  /// Insert count entries at the given index (may grow array). The new
1117  /// entries will be uninitialized.
1118  FromType multipleInsert(FromType i, GA_Size count);
1119 
1120  /// Remove the entry at the given offset
1121  FromType remove(FromType i);
1122  /// Find an entry and remove it from the list
1123  FromType findAndRemove(ToType i);
1124  /// Alias for remove to match UT array types
1125  FromType removeIndex(FromType i) { return remove(i); }
1126  /// Remove all matching entries from the list
1127  GA_Size removeAll(ToType i);
1128  /// Remove the last entry
1129  void removeLast()
1130  {
1131  UT_ASSERT_P(mySize > 0);
1132  --mySize;
1133  }
1134 
1135  /// Sort entries into ascending order
1136  void sortAscending();
1137 
1138  /// Sort entries into ascending order and remove duplicates
1139  void sortAndRemoveDuplicates();
1140 
1141  /// Set the index to the value
1142  void set(FromType index, ToType value)
1143  {
1144  UT_ASSERT_P(index >= FromType(0) && index < FromType(mySize));
1145  if (isTrivial())
1146  {
1147  if (myTrivialOffset+GA_Size(index) == GA_Size(value))
1148  return;
1149  if (mySize==1)
1150  {
1151  myTrivialOffset = GA_Size(value);
1152  return;
1153  }
1154  }
1155 
1156  harden();
1157  myData->set(index, value);
1158  }
1159 
1160  template<typename S>
1161  void set(const S *data, exint size, ToType offset)
1162  {
1163  clear();
1164 
1165  if (size == 0)
1166  return;
1167 
1168  // Check for triviality first
1169  ToType first = ToType(data[0]);
1170  bool istrivial = true;
1171  for (int64 i = 1; i < size; ++i)
1172  {
1173  if (ToType(data[i]) != first + ToType(i))
1174  {
1175  istrivial = false;
1176  break;
1177  }
1178  }
1179 
1180  if (istrivial)
1181  setTrivial(first+offset, FromType(size));
1182  else
1183  {
1185  ListTypeData *newdata = ListTypeData::allocate(size);
1186  UT_ASSERT_P((intptr_t(newdata) & TRIVIAL_MASK) == 0);
1187  newdata->set(data, size, offset);
1188  mySize = size;
1189  myData = newdata;
1190  }
1191  }
1192 
1193  void copyAdd(FromType destindex, const int *values, GA_Size srcindex, GA_Size n, ToType offset)
1194  {
1195  if (isTrivial())
1196  {
1197  bool ismatch = true;
1198  for (GA_Size i = 0; i < n; ++i)
1199  {
1200  if (myTrivialOffset + GA_Size(destindex) + i != values[srcindex + i] + GA_Size(offset))
1201  {
1202  ismatch = false;
1203  break;
1204  }
1205  }
1206  if (ismatch)
1207  return;
1208  }
1209  harden();
1210  myData->copyAdd(destindex, values, srcindex, n, offset);
1211  }
1212  void copyAdd(FromType destindex, const GA_ListTypeRef<FromType, ToType> &values, FromType srcindex, GA_Size n, ToType offset)
1213  {
1214  if (isTrivial())
1215  {
1216  if (values.isTrivial() && myTrivialOffset + destindex == values.myTrivialOffset + srcindex)
1217  return;
1218 
1219  bool ismatch = true;
1220  for (GA_Size i = 0; i < n; ++i)
1221  {
1222  if (myTrivialOffset + GA_Size(destindex) + i != GA_Size(values(srcindex + i)) + GA_Size(offset))
1223  {
1224  ismatch = false;
1225  break;
1226  }
1227  }
1228  if (ismatch)
1229  return;
1230  }
1231  harden();
1232  myData->copyAdd(destindex, values, srcindex, n, offset);
1233  }
1234  void setTrivialRange(FromType startindex, ToType startvalue, GA_Size nelements)
1235  {
1236  FromType endindex = startindex + nelements;
1237  if (isTrivial())
1238  {
1239  if (startindex == FromType(0) && nelements >= mySize)
1240  {
1241  myTrivialOffset = startvalue;
1242  mySize = nelements;
1243  return;
1244  }
1245  if (myTrivialOffset+GA_Size(startindex) == GA_Size(startvalue))
1246  {
1247  if (endindex > FromType(mySize))
1248  mySize = endindex;
1249  return;
1250  }
1251  }
1252  else if (startindex == FromType(0) && nelements >= mySize)
1253  {
1254  setTrivial(startvalue, nelements);
1255  return;
1256  }
1257 
1258  exint new_size = SYSmax(exint(endindex), exint(mySize));
1259  harden(new_size);
1260  mySize = new_size;
1262  for (GA_Size i = 0; i < nelements; ++i)
1263  data->set(startindex + i, startvalue + i);
1264  }
1265 
1266  /// Set all entries to a constant value
1267  void constant(ToType value);
1268 
1269  /// Cyclically shift the entire array by howMany
1270  void cycle(GA_Size howMany);
1271 
1272  /// Reverse the entire array
1273  void reverse();
1274 
1275  void harden()
1276  {
1277  if (isTrivial())
1278  {
1281  UT_ASSERT_P((intptr_t(data) & TRIVIAL_MASK) == 0);
1282  INT_TYPE *array = data->getRawData();
1283  for (exint i = 0; i < exint(mySize); i++)
1284  array[i] = ToType(myTrivialOffset+i);
1285 #if GA_OFFSETLIST_VERBOSE_DEBUG
1286  printf("%p taking ownership of new %p in harden()\n", this, data);
1287  fflush(stdout);
1288 #endif
1289  myData = data;
1290  }
1291  else if (myData->isShared())
1292  {
1293  // ensure we have a ListTypeData and that isn't referenced by
1294  // any other GA_ListType
1296 #if GA_OFFSETLIST_VERBOSE_DEBUG
1297  printf("%p removing reference to %p in harden(), and taking ownership of new %p\n", this, myData, data);
1298  fflush(stdout);
1299 #endif
1300  myData->unref();
1301 
1302  // NOTE: DO NOT set myData to NULL, even temporarily, because it
1303  // *must* be threadsafe to call isTrivial() while hardening
1304  // a non-trivial list and get false as a return value.
1305  // GA_IndexMap::compactIndices() may be called at the same
1306  // time as GA_IndexMap::isTrivial(), and isTrivial() *must*
1307  // return false, no matter what the race.
1308  myData = data;
1309  }
1310  UT_ASSERT_P(!isTrivial() && !myData->isShared());
1311  }
1312 
1313  void harden(exint mincapacity)
1314  {
1315  if (isTrivial())
1316  {
1318  ListTypeData *data = ListTypeData::allocate(mincapacity);
1319  UT_ASSERT_P((intptr_t(data) & TRIVIAL_MASK) == 0);
1320  INT_TYPE *array = data->getRawData();
1321  if (mincapacity < mySize)
1322  mySize = mincapacity;
1323  for (exint i = 0; i < exint(mySize); i++)
1324  array[i] = ToType(myTrivialOffset+i);
1325 #if GA_OFFSETLIST_VERBOSE_DEBUG
1326  printf("%p taking ownership of new %p in harden(mincapacity)\n", this, data);
1327  fflush(stdout);
1328 #endif
1329  myData = data;
1330  }
1331  else if (myData->isShared())
1332  {
1333  // ensure we have a ListTypeData and that isn't referenced by
1334  // any other GA_ListType
1335  ListTypeData *data = myData->copy(mySize, mincapacity);
1336 #if GA_OFFSETLIST_VERBOSE_DEBUG
1337  printf("%p removing reference to %p in harden(mincapacity), and taking ownership of new %p\n", this, myData, data);
1338  fflush(stdout);
1339 #endif
1340  myData->unref();
1341 
1342  // NOTE: DO NOT set myData to NULL, even temporarily, because it
1343  // *must* be threadsafe to call isTrivial() while hardening
1344  // a non-trivial list and get false as a return value.
1345  // GA_IndexMap::compactIndices() may be called at the same
1346  // time as GA_IndexMap::isTrivial(), and isTrivial() *must*
1347  // return false, no matter what the race.
1348  myData = data;
1349 
1350  if (mincapacity < mySize)
1351  mySize = mincapacity;
1352  }
1353  else if (mincapacity > myData->capacity())
1354  {
1355 #if GA_OFFSETLIST_VERBOSE_DEBUG
1356  printf("%p bumping capacity of %p, current capacity = %d in harden(mincapacity=%d)\n", this, myData, int(mincapacity), int(myData->capacity()));
1357 #endif
1358  myData = myData->bumpCapacity(mincapacity);
1359 #if GA_OFFSETLIST_VERBOSE_DEBUG
1360  printf(" now %p new capacity = %d\n", myData, int(myData->capacity()));
1361  fflush(stdout);
1362 #endif
1363  }
1364  UT_ASSERT_P(!isTrivial() && !myData->isShared());
1365  }
1366 
1367  /// WARNING: PLEASE DO NOT CALL THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
1368  /// IF YOU'RE UNSURE, YOU DON'T NEED TO CALL THIS!
1369  /// Only call this if it's necessary to copy a GA_ListType and share
1370  /// its ownership in some way that doesn't correctly update the
1371  /// ref count for non-trivial lists.
1372  /// (This was added for GA_PrimitiveList to represent a GA_OffsetList
1373  /// with a UT_FixedVector<int64,2>.)
1374  void incDataRef()
1375  {
1376  if (!isTrivial())
1377  {
1378 #if GA_OFFSETLIST_VERBOSE_DEBUG
1379  printf("%p adding reference to %p in incDataRef()\n", this, myData);
1380  fflush(stdout);
1381 #endif
1382  myData->ref();
1383  }
1384  }
1385 };
1386 
1387 
1388 // A list of offsets. The index type is still specified as a template
1389 // parameter.
1390 template <typename FromType, typename INT_TYPE=exint>
1391 class GA_API GA_OffsetListType : public GA_ListType<FromType, GA_Offset, INT_TYPE>
1392 {
1393 private:
1394  // Shorthand for the base class
1396  using Base::myData;
1397  using Base::myIsFlagSet;
1398  using Base::myIsTrivial;
1399  using Base::myTrivialOffset;
1400  using Base::mySize;
1401 public:
1402  using Base::clear;
1403  using Base::get;
1404  using Base::isTrivial;
1405  using Base::set;
1406  using Base::size;
1407  using typename Base::theIntType;
1408 
1409  // Default c-tor
1410  explicit GA_OffsetListType() : Base() {}
1411  // Copy c-tor
1413  : Base(src) {}
1415  : Base(src) {}
1416  // A GA_OffsetArray is a UT_Array of offsets. The UT_Array doesn't have
1417  // paged storage, nor COW semantics, it's just a flat list of offsets.
1418  // This will construct a GA_OffsetListType by copying a portion of the array.
1419  GA_OffsetListType(const UT_ValArray<GA_Offset> &src, FromType start=FromType(0), FromType end=FromType(-1))
1420  : Base(src, start, end) {}
1421 
1422  /// Copy assignment operator
1425  {
1426  Base::operator=(src);
1427  return *this;
1428  }
1429 
1430  /// Move assignment operator
1433  {
1434  if (!isTrivial())
1435  {
1436 #if GA_OFFSETLIST_VERBOSE_DEBUG
1437  printf("%p removing reference to %p in GA_OffsetListType move assignment operator\n", this, myData);
1438  fflush(stdout);
1439 #endif
1440  myData->unref();
1441  }
1442 #if GA_OFFSETLIST_VERBOSE_DEBUG
1443  if (!src.isTrivial())
1444  {
1445  printf("%p stealing reference to %p (orig reference by list %p) in GA_OffsetListType move assignment operator\n", this, src.myData, &src);
1446  fflush(stdout);
1447  }
1448 #endif
1449  // NOTE: I'm assuming that it's expected that myIsFlagSet will be copied.
1450  memcpy(this, &src, sizeof(*this));
1451  src.myIsTrivial = true;
1452  return *this;
1453  }
1454 
1455  /// Copy assignment operator from GA_ListTypeRef.
1456  /// Although it may seem strange to have this at all, it should be
1457  /// safe, since the destination does take (shared) ownership of any
1458  /// non-trivial data. There should be a GA_OffsetListType somewhere else
1459  /// that already owns this.
1462  {
1463  Base::operator=(src);
1464  return *this;
1465  }
1466 
1467  /// @{
1468  /// Swap offset values for defragmentation process. When defragmenting,
1469  /// offsets will move. This method will update all references to offsets
1470  /// to their new values. This returns the number of values updated.
1471  GA_Size swapOffsetValues(const GA_Defragment &defrag);
1472  /// @}
1473 
1474  /// @section JSON-GA_OffsetList JSON Schema: GA_OffsetList
1475  /// @code
1476  /// {
1477  /// "name" : "GA_OffsetList",
1478  /// "description" : "An array of offsets/indicies",
1479  /// "type" : "array",
1480  /// "items" : "integer",
1481  /// }
1482  /// @endcode
1483  /// @see @ref JSON_FileFormat
1484 
1485  /// Save the offsets by doing the mapping to the points in the save map
1486  bool jsonPointArray(UT_JSONWriter &w, const GA_SaveMap &save) const;
1487  /// Save the offsets by doing the mapping to the vertices in the save map
1488  bool jsonVertexArray(UT_JSONWriter &w, const GA_SaveMap &save) const;
1489  /// Save the offsets by doing the mapping to the primitives in the save map
1490  bool jsonPrimitiveArray(UT_JSONWriter &w, const GA_SaveMap &save) const;
1491 
1492  /// Load a point list from a JSON stream
1493  bool jsonPointArray(UT_JSONParser &p, const GA_LoadMap &load);
1494  /// Load a vertex list from a JSON stream
1495  bool jsonVertexArray(UT_JSONParser &p, const GA_LoadMap &load);
1496  /// Load a primitive list from a JSON stream
1497  bool jsonPrimitiveArray(UT_JSONParser &p, const GA_LoadMap &load);
1498 
1499  /// Generic load given a load offset
1500  bool jsonLoad(UT_JSONParser &p, GA_Offset load_offset);
1501  /// Load, appending to the current offset list without initial clear
1502  bool jsonLoadAppend(UT_JSONParser &p, GA_Offset load_offset);
1503  /// Generic load from a JSON stream saved by index that maps the ordered
1504  /// index to an offset.
1505  bool jsonLoadByIndex(UT_JSONParser &p, const GA_IndexMap &index_map,
1506  GA_Index load_offset);
1507  /// Load from a JSON stream saved by index, mapping the ordered index to
1508  /// an offset and appending to the current offset list without an initial
1509  /// clear.
1510  bool jsonLoadAppendByIndex(UT_JSONParser &p,
1511  const GA_IndexMap &index_map,
1512  GA_Index load_offset);
1513 
1514 private:
1515  bool jsonSaveTranslatedArray(
1516  UT_JSONWriter &w,
1517  const GA_SaveMap &save,
1518  GA_AttributeOwner xlate) const;
1519 };
1520 
1521 /// GA_OffsetList is a map from index to offset
1523 
1524 /// GA_OffsetListRef is like GA_OffsetList, except that it doesn't own
1525 /// its data. It's useful for making a temporary copy of a GA_OffsetList
1526 /// that isn't going to be changing during the lifetime of the copy,
1527 /// to avoid having to ref and unref myData, among a few related speedups.
1529 
1530 #endif
1531 
SYS_FORCE_INLINE void clear()
clear removes all of the entries
A class to manage an ordered array which has fixed offset handles.
Definition: GA_IndexMap.h:63
ListTypeData * myData
SYS_FORCE_INLINE GA_ListType()
Default constructor.
#define UT_ASSERT_COMPILETIME(expr)
Definition: UT_Assert.h:109
#define SYSmax(a, b)
Definition: SYS_Math.h:1365
GLint first
Definition: glcorearb.h:404
FromType multipleInsert(FromType i, GA_Size count)
void reverse()
Reverse the entire array.
SYS_FORCE_INLINE GA_ListType(const GA_ListType &src)
Copy constructor.
void harden(exint mincapacity)
void copyAdd(FromType destindex, const GA_ListTypeRef< FromType, ToType, S > &values, FromType srcindex, GA_Size n, ToType offset)
SYS_FORCE_INLINE GA_OffsetListType & operator=(const GA_OffsetListType &src)
Copy assignment operator.
SYS_FORCE_INLINE GA_ListType(ToType startvalue, GA_Size size, bool flag_set=false)
Trivial list constructor.
FromType append(ToType value)
Add a single entry (may grow array)
Used to pass options and map offset values during saving.
Definition: GA_SaveMap.h:48
FromType findInRange(FromType start, FromType end, ToType search) const
SYS_FORCE_INLINE void set(FromType index, ToType value)
void copyAdd(FromType destindex, const int *values, GA_Size srcindex, GA_Size n, ToType offset)
SYS_FORCE_INLINE GA_OffsetListType & operator=(GA_OffsetListType &&src)
Move assignment operator.
SYS_FORCE_INLINE void setTrivial(ToType startvalue, GA_Size size)
Makes the list a trivial list with the specified start value and size.
GA_OffsetListType(const GA_OffsetListType &src)
void sortAndRemoveDuplicates()
Sort entries into ascending order and remove duplicates.
const GLdouble * v
Definition: glcorearb.h:836
GA_OffsetListType< GA_Size > GA_OffsetList
GA_OffsetList is a map from index to offset.
GLuint start
Definition: glcorearb.h:474
bool GAisValid(GA_Size v)
Definition: GA_Types.h:625
FromType findInRangeNotEqual(FromType start, FromType end, ToType search) const
SYS_FORCE_INLINE int64 getMemoryUsage(bool inclusive) const
void constant(ToType value)
Set all entries to a constant value.
ListTypeData * reallocate(exint new_capacity)
Definition: GA_OffsetList.h:84
void copyAdd(FromType destindex, const GA_ListTypeRef< FromType, ToType > &values, FromType srcindex, GA_Size n, ToType offset)
SYS_FORCE_INLINE bool getExtraFlag() const
void reserve(FromType mincapacity)
void setTrivial(ToType startvalue, GA_Size size)
Makes the list a trivial list with the specified start value and size.
FromType findInRangeNotEqual(FromType start, FromType end, ToType search) const
void setTrivialRange(FromType startindex, ToType startvalue, GA_Size nelements)
void reverse(FromType size)
JSON reader class which handles parsing of JSON or bJSON files.
Definition: UT_JSONParser.h:72
#define GA_API
Definition: GA_API.h:12
INT_TYPE theIntType
Definition: GA_OffsetList.h:57
Class which writes ASCII or binary JSON streams.
Definition: UT_JSONWriter.h:32
SYS_FORCE_INLINE GA_ListTypeRef(GA_ListTypeRef &&src)
Move constructor.
FromType findInvalidInRange(FromType start, FromType end) const
typename Base::ListTypeData ListTypeData
GA_ListTypeRef< GA_Size, GA_Offset > GA_OffsetListRef
SYS_FORCE_INLINE GA_ListType & operator=(const Base &src)
FromType findValidInRange(FromType start, FromType end) const
void unsafeClearData()
Definition: UT_Array.h:857
png_uint_32 i
Definition: png.h:2877
SYS_FORCE_INLINE GA_ListType & operator=(const GA_ListType &src)
Copy assignment operator.
SYS_FORCE_INLINE void forEach(FUNCTOR &&functor) const
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:211
SYS_FORCE_INLINE GA_ListTypeRef()
Default constructor.
GLsizeiptr size
Definition: glcorearb.h:663
SYS_FORCE_INLINE int64 getMemoryUsage(bool inclusive) const
Report memory usage (includes all shared memory)
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:101
SYS_FORCE_INLINE ~GA_ListTypeRef()
Destructor.
void set(FromType index, ToType value)
Set the index to the value.
GA_Size GA_Offset
Definition: GA_Types.h:617
GA_OffsetListType(const GA_ListTypeRef< FromType, GA_Offset, INT_TYPE > &src)
SYS_FORCE_INLINE INT_TYPE * getRawData()
long long int64
Definition: SYS_Types.h:100
SYS_FORCE_INLINE bool isTrivial() const
GLdouble n
Definition: glcorearb.h:2007
ListTypeData * setCapacity(exint new_capacity)
unsigned long long uint64
Definition: SYS_Types.h:101
void removeLast()
Remove the last entry.
void computeTrivial()
SYS_FORCE_INLINE INT_TYPE & operator()(exint index)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:102
SYS_FORCE_INLINE GA_ListType(const Base &src)
bool isAscending(exint size) const
FromType findAndRemove(ToType i)
Find an entry and remove it from the list.
int64 exint
Definition: SYS_Types.h:109
void cycle(GA_Size howMany)
Cyclically shift the entire array by howMany.
FromType findValidInRange(FromType start, FromType end) const
GLuint GLuint end
Definition: glcorearb.h:474
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
SYS_FORCE_INLINE GA_ListType & operator=(GA_ListType &&src)
Move assignment operator.
void countMemory(UT_MemoryCounter &counter, bool inclusive) const
static const intptr_t POINTER_MASK
ListTypeData * copy(exint size, exint new_capacity) const
SYS_FORCE_INLINE GA_ListTypeRef(ToType startvalue, GA_Size size, bool flag_set=false)
Trivial list constructor.
GLintptr offset
Definition: glcorearb.h:664
SYS_FORCE_INLINE const INT_TYPE & operator()(exint index) const
friend class GA_ListType
Definition: GA_OffsetList.h:55
void changeSize(FromType new_capacity)
Options during loading.
Definition: GA_LoadMap.h:42
SYS_FORCE_INLINE GA_ListTypeRef(const GA_ListTypeRef &src)
Copy constructor.
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1601
Defragmentation of IndexMaps.
Definition: GA_Defragment.h:45
GA_Size removeAll(ToType v, FromType size)
GLboolean * data
Definition: glcorearb.h:130
FromType findAndRemove(ToType v, FromType size)
SYS_FORCE_INLINE const INT_TYPE * getRawData() const
GA_Size GA_Index
Define the strictness of GA_Offset/GA_Index.
Definition: GA_Types.h:611
void unsafeShareData(UT_Array< T > &src)
Definition: UT_Array.h:839
void cycle(exint howMany)
Cyclically shifts the entire array by howMany.
Definition: UT_ArrayImpl.h:646
SYS_FORCE_INLINE ToType operator()(FromType i) const
Convenience () operator to access the list entries.
GLint GLsizei count
Definition: glcorearb.h:404
bool isSame(const GA_ListTypeRef &that) const
ToType last() const
Return the value of the last element.
GA_Size removeAll(ToType i)
Remove all matching entries from the list.
SYS_FORCE_INLINE GA_Size capacity() const
Returns the allocated capacity of the list.
void sortAscending(FromType size)
GLsizei const GLfloat * value
Definition: glcorearb.h:823
GA_AttributeOwner
Definition: GA_Types.h:33
SYS_FORCE_INLINE GA_ListType(GA_ListType &&src)
Move constructor.
#define UT_ASSERT_MSG_P(ZZ, MM)
Definition: UT_Assert.h:104
typedef int
Definition: png.h:1175
FromType insert(FromType i, ToType value)
Insert a single entry (may grow array)
static const intptr_t TRIVIAL_MASK
SYS_FORCE_INLINE void setExtraFlag(bool v)
void setTrivial(ToType startvalue, GA_Size size, bool flag)
SYS_FORCE_INLINE void setTrivial(ToType startvalue, GA_Size size, bool flag)
GLuint index
Definition: glcorearb.h:785
void setEntries(FromType sz, bool doresize=true)
SYS_FORCE_INLINE GA_Size capacity() const
void set(const S *data, exint size, ToType offset)
FromType findInvalidInRange(FromType start, FromType end) const
FromType findInRange(FromType start, FromType end, ToType search) const
SYS_FORCE_INLINE ToType get(FromType index) const
Get the the value at the index.
FromType sortAndRemoveDuplicates(FromType size)
FromType find(ToType v, FromType s, FromType size) const
SYS_FORCE_INLINE GA_ListTypeRef & operator=(GA_ListTypeRef &&src)
Move assignment operator.
GA_OffsetListType(const UT_ValArray< GA_Offset > &src, FromType start=FromType(0), FromType end=FromType(-1))
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
void cycle(GA_Size howMany, FromType size)
SYS_FORCE_INLINE GA_OffsetListType & operator=(const GA_ListTypeRef< FromType, GA_Offset, INT_TYPE > &src)
SYS_FORCE_INLINE ToType trivialStart() const
Returns the start, assuming this list is trivial.
#define FLAG_MASK
SYS_FORCE_INLINE void relaxedStore(T val)
Definition: SYS_AtomicInt.h:68
SYS_FORCE_INLINE ~GA_ListType()
Destructor.
png_infop png_uint_32 flag
Definition: png.h:2242
FromType removeIndex(FromType i)
Alias for remove to match UT array types.
void constant(ToType value, FromType size)
#define SYSmin(a, b)
Definition: SYS_Math.h:1366
void sortAscending()
Sort entries into ascending order.
void copyAdd(FromType destindex, const S *values, GA_Size srcindex, GA_Size n, ToType offset)
void set(const S *data, exint size, ToType offset)
#define UT_ASSERT_MSG(ZZ, MM)
Definition: UT_Assert.h:105
SYS_FORCE_INLINE void clear()
clear removes all of the entries
static ListTypeData * allocate(exint capacity)
Definition: GA_OffsetList.h:64
void incDataRef()
bool isTrivial(exint size) const
SYS_FORCE_INLINE FromType size() const
Returns the number of used elements in the list (always <= capacity())
SYS_FORCE_INLINE GA_ListTypeRef & operator=(const GA_ListTypeRef &src)
Copy assignment operator.
GLenum src
Definition: glcorearb.h:1792
SYS_FORCE_INLINE FromType entries() const
Returns the number of used elements in the list (always <= capacity())
ListTypeData * bumpCapacity(exint mincapacity)