libUTL++
util_inl.h
1 #pragma once
2 
4 
5 #include <libutl/Ordering.h>
6 
8 
9 UTL_NS_BEGIN;
10 
12 
19 {
20 public:
22  BoolToggle(bool& b)
23  : _b(b)
24  {
25  _b = !_b;
26  }
27 
30  {
31  _b = !_b;
32  }
33 
34 private:
35  bool& _b;
36 };
37 
39 
41 template <typename T>
42 const T&
43 min(const T& v)
44 {
45  return v;
46 }
47 
49 
59 template <typename T, typename... R>
60 const T&
61 min(const T& a, const T& b, const R&... args)
62 {
63  return utl::min((b < a) ? b : a, args...);
64 }
65 
67 
69 template <typename T>
70 const T&
71 max(const T& v)
72 {
73  return v;
74 }
75 
77 
87 template <typename T, typename... R>
88 const T&
89 max(const T& a, const T& b, const R&... args)
90 {
91  return utl::max((b < a) ? a : b, args...);
92 }
93 
95 
101 inline uint32_t
103 {
104  --n;
105  n |= (n >> 1);
106  n |= (n >> 2);
107  n |= (n >> 4);
108  n |= (n >> 8);
109  n |= (n >> 16);
110  return n + 1;
111 }
112 
114 
120 inline uint64_t
122 {
123  --n;
124  n |= (n >> 1);
125  n |= (n >> 2);
126  n |= (n >> 4);
127  n |= (n >> 8);
128  n |= (n >> 16);
129  n |= (n >> 32);
130  return n + 1;
131 }
132 
134 
140 template <class T>
141 inline T
142 nextMultiple(const T& x, const T& target)
143 {
144  ASSERTD(x != 0);
145  T rem = target % x;
146  return (rem == 0) ? target : target + (x - rem);
147 }
148 
150 
157 inline uint32_t
159 {
160  ASSERTD(x != 0);
161  ASSERTD(x == nextPow2(x));
162  return (target + x - 1) & ~(x - 1);
163 }
164 
166 
173 inline uint64_t
175 {
176  ASSERTD(x != 0);
177  ASSERTD(x == nextPow2(x));
178  return (target + x - 1) & ~(x - 1);
179 }
180 
182 
190 inline size_t
191 allocatedSize(const Object* object)
192 {
193  if (object == nullptr) return 0;
194  return object->allocatedSize();
195 }
196 
198 
209 template <typename T>
210 void
211 arrayGrow(T*& array,
212  size_t& arraySize,
213  size_t minSize = size_t_max,
214  size_t growthIncrement = size_t_max,
215  const T* defVal = nullptr)
216 {
217  // by default, just make room for one more object
218  if (minSize == size_t_max) minSize = (arraySize + 1);
219 
220  // allocation is already big enough -> do nothing
221  if (arraySize >= minSize) return;
222 
223  // compute new allocation size
224  size_t newSize;
225  if (growthIncrement == size_t_max)
226  {
227  newSize = nextPow2(minSize);
228  }
229  else
230  {
231  ASSERTD(growthIncrement == nextPow2(growthIncrement));
232  newSize = nextMultipleOfPow2(growthIncrement, minSize);
233  }
234  ASSERTD(newSize >= minSize);
235 
236  // copy objects from old allocation to new
237  T* newArray = new T[newSize];
238  if (std::is_trivially_copyable<T>())
239  {
240  memcpy(newArray, array, arraySize * sizeof(T));
241  }
242  else
243  {
244  T* lhsPtr = newArray;
245  T* rhsPtr = array;
246  T* rhsLim = array + arraySize;
247  for (; rhsPtr != rhsLim; ++lhsPtr, ++rhsPtr)
248  {
249  *lhsPtr = std::move(*rhsPtr);
250  }
251  }
252 
253  // if caller wants to initialize the objects we added on, do that
254  if (defVal != nullptr)
255  {
256  T* lhsPtr = newArray + arraySize;
257  T* lhsLim = newArray + newSize;
258  for (; lhsPtr != lhsLim; ++lhsPtr)
259  {
260  *lhsPtr = *defVal;
261  }
262  }
263 
264  // clean up the old allocation & set array,arraySize for caller
265  delete[] array;
266  array = newArray;
267  arraySize = newSize;
268 }
269 
271 
282 template <typename T>
283 void
284 arrayGrow(T*& array,
285  T*& arrayPtr,
286  T*& arrayLim,
287  size_t minSize = size_t_max,
288  size_t growthIncrement = size_t_max)
289 {
290  size_t arraySize = arrayLim - array;
291  size_t arrayIdx = arrayPtr - array;
292  arrayGrow(array, arraySize, minSize, growthIncrement, static_cast<T*>(nullptr));
293  arrayPtr = array + arrayIdx;
294  arrayLim = array + arraySize;
295 }
296 
298 
305 template <typename T>
306 inline const T&
307 cast(const utl::Object& object)
308 {
309  ASSERTD(object.isA(T));
310  return static_cast<const T&>(object);
311 }
312 
314 
321 template <typename T>
322 inline T&
324 {
325  ASSERTD(object.isA(T));
326  return static_cast<T&>(object);
327 }
328 
330 
337 template <typename T>
338 inline const T*
339 cast(const utl::Object* object)
340 {
341  ASSERTD((object == nullptr) || object->isA(T));
342  return static_cast<const T*>(object);
343 }
344 
346 
353 template <typename T>
354 inline T*
356 {
357  ASSERTD((object == nullptr) || object->isA(T));
358  return static_cast<T*>(object);
359 }
360 
362 
369 template <typename T>
370 inline T&
371 cast_const(const utl::Object& object)
372 {
373  ASSERTD(object.isA(T));
374  return static_cast<T&>(const_cast<utl::Object&>(object));
375 }
376 
378 
385 template <typename T>
386 inline T*
387 cast_const(const utl::Object* object)
388 {
389  ASSERTD((object == nullptr) || object->isA(T));
390  return static_cast<T*>(const_cast<utl::Object*>(object));
391 }
392 
394 
402 template <typename T>
403 T*
404 clone(const T* object)
405 {
406  if (object == nullptr) return nullptr;
407  return object->clone();
408 }
409 
411 
420 template <typename T>
421 inline int
422 compare(const T& lhs, const T& rhs)
423 {
424  if (lhs < rhs) return -1;
425  if (lhs == rhs) return 0;
426  return 1;
427 }
428 
430 
441 inline int
442 compare(const Object* lhs, const Object* rhs, const Ordering* ordering = nullptr)
443 {
444  ASSERTD(lhs != nullptr);
445  ASSERTD(rhs != nullptr);
446  if (lhs == rhs) return 0;
447  if (ordering == nullptr) return lhs->compare(*rhs);
448  return ordering->cmp(lhs, rhs);
449 }
450 
452 
465 inline int
466 compareNullable(const Object* lhs, const Object* rhs, const Ordering* ordering = nullptr)
467 {
468  if (lhs == rhs) return 0;
469  if ((lhs != nullptr) && (rhs != nullptr))
470  {
471  if (ordering == nullptr) return lhs->compare(*rhs);
472  return ordering->cmp(lhs, rhs);
473  }
474  if (lhs == nullptr) return -1;
475  // rhs must be nullptr
476  return 1;
477 }
478 
480 
490 template <typename T>
491 int
492 compare(const T* lhs, const T* rhs, size_t len)
493 {
494  size_t i;
495  for (i = 0; i < len; i++)
496  {
497  int res = utl::compare(lhs[i], rhs[i]);
498  if (res != 0)
499  {
500  return res;
501  }
502  }
503  return 0;
504 }
505 
507 
518 template <typename T>
519 int
520 compare(const T* lhs, size_t lhsLen, const T* rhs, size_t rhsLen)
521 {
522  size_t i;
523  size_t minLen = utl::min(lhsLen, rhsLen);
524  for (i = 0; i < minLen; i++)
525  {
526  int res = utl::compare(lhs[i], rhs[i]);
527  if (res != 0)
528  {
529  return res;
530  }
531  }
532  if (lhsLen < minLen)
533  return -1;
534  else if (rhsLen < minLen)
535  return 1;
536  return 0;
537 }
538 
540 
552 template <typename InputCont1, typename InputCont2>
553 int
554 compare(typename InputCont1::const_iterator lhsBegin,
555  typename InputCont1::const_iterator lhsEnd,
556  typename InputCont2::const_iterator rhsBegin,
557  typename InputCont2::const_iterator rhsEnd,
558  std::function<int(typename InputCont1::value_type, typename InputCont2::value_type)> comp)
559 {
560  auto lhsIt = lhsBegin;
561  auto rhsIt = rhsBegin;
562  for (;; ++lhsIt, ++rhsIt)
563  {
564  bool lhsDone = (lhsIt == lhsEnd);
565  bool rhsDone = (rhsIt == rhsEnd);
566  if (lhsDone && rhsDone) return 0;
567  if (lhsDone) return -1;
568  if (rhsDone) return 1;
569  int res = comp(*lhsIt, *rhsIt);
570  if (res != 0) return res;
571  }
572  ABORT();
573  return 0;
574 }
575 
577 
586 inline bool
588 {
589  if (cmpRes < 0)
590  {
591  return (cmpOp == cmp_lessThan);
592  }
593  if (cmpRes == 0)
594  {
595  return ((cmpOp != cmp_lessThan) && (cmpOp != cmp_greaterThan));
596  }
597  return (cmpOp == cmp_greaterThan);
598 }
599 
601 
609 template <typename T>
611 {
612  comparisonFunctor(const Ordering* ordering = nullptr)
613  : _ordering(ordering)
614  {
615  }
616 
617  int operator()(const Object* lhs, const Object* rhs) const
618  {
619  return utl::compare(lhs, rhs, _ordering);
620  }
621 
622 private:
623  const Ordering* _ordering;
624 };
625 
627 
635 template <typename T = utl::Object>
636 struct equals
637 {
638  equals(const Ordering* ordering = nullptr)
639  : _ordering(ordering)
640  {
641  }
642 
643  bool operator()(const T* lhs, const T* rhs) const
644  {
645  return (utl::compare(lhs, rhs, _ordering) == 0);
646  }
647 
648 private:
649  const Ordering* _ordering;
650 };
651 
653 
661 template <typename T = utl::Object>
662 struct lessThan
663 {
664  lessThan(const Ordering* ordering = nullptr)
665  : _ordering(ordering)
666  {
667  }
668 
669  bool operator()(const T* lhs, const T* rhs) const
670  {
671  return (utl::compare(lhs, rhs, _ordering) < 0);
672  }
673 
674 private:
675  const Ordering* _ordering;
676 };
677 
679 
688 template <typename T>
689 void
690 copy(T* dest, const T* src, size_t len)
691 {
692  T* destPtr = dest;
693  const T* srcPtr = src;
694  const T* srcLim = src + len;
695  for (; srcPtr != srcLim; ++srcPtr, ++destPtr)
696  {
697  *destPtr = *srcPtr;
698  }
699 }
700 
702 
709 template <class T>
710 inline bool
711 isDivisibleBy(const T& x, const T& n)
712 {
713  return (((x / n) * n) == x);
714 }
715 
717 
726 template <typename T>
727 inline T
728 roundUp(const T& v, const T& m)
729 {
730  T vModm = v % m;
731  if (vModm == 0) return v;
732  return (v - vModm + m);
733 }
734 
736 
745 template <typename T>
746 inline T
747 roundDown(const T& v, const T& m)
748 {
749  return v - (v % m);
750 }
751 
753 
764 template <typename T>
765 void
766 serialize(T* array, size_t len, Stream& stream, uint_t io, uint_t mode = ser_default)
767 {
768  if (mode & ser_default) mode = getSerializeMode();
769  size_t i;
770  for (i = 0; i < len; i++)
771  {
772  serialize(array[i], stream, io, mode);
773  }
774 }
775 
777 
787 template <typename T>
788 inline void
789 serialize(T*& object, Stream& stream, uint_t io, uint_t mode = ser_default)
790 {
791  serializeBoxed(object, stream, io, mode);
792 }
793 
795 
805 template <typename T>
806 inline void
807 serialize(T& object, Stream& stream, uint_t io, uint_t mode = ser_default)
808 {
809  object.serialize(stream, io, mode);
810 }
811 
813 
823 template <typename T>
824 void
825 serializeNullable(T*& object, Stream& stream, uint_t io, uint_t mode = ser_default)
826 {
827  if (io == io_rd)
828  {
829  delete object;
830  object = nullptr;
831  Object* _object = Object::serializeInNullable(stream, mode);
832  object = utl::cast<T>(_object);
833  }
834  else
835  {
836  Object::serializeOutNullable(object, stream, mode);
837  }
838 }
839 
841 
851 template <typename T>
852 void
853 serializeBoxed(T*& object, Stream& stream, uint_t io, uint_t mode = ser_default)
854 {
855  if (io == io_rd)
856  {
857  delete object;
858  object = nullptr;
859  Object* _object = Object::serializeInBoxed(stream, mode);
860  object = utl::cast<T>(_object);
861  }
862  else
863  {
864  object->serializeOutBoxed(stream, mode);
865  }
866 }
867 
869 
877 inline uint16_t
879 {
880  return ((n & 0xff00) >> 8) | ((n & 0x00ff) << 8);
881 }
882 
884 
892 inline uint32_t
894 {
895  n = ((n & 0xffff0000) >> 16) | ((n & 0x0000ffff) << 16);
896  n = ((n & 0xff00ff00) >> 8) | ((n & 0x00ff00ff) << 8);
897  return n;
898 }
899 
901 
909 inline uint64_t
911 {
912  n = ((n & 0xffffffff00000000) >> 32) | ((n & 0x00000000ffffffff) << 32);
913  n = ((n & 0xffff0000ffff0000) >> 16) | ((n & 0x0000ffff0000ffff) << 16);
914  n = ((n & 0xff00ff00ff00ff00) >> 8) | ((n & 0x00ff00ff00ff00ff) << 8);
915  return n;
916 }
917 
919 
928 template <typename T>
929 inline void
930 swap(T* array, size_t lhsIdx, size_t rhsIdx)
931 {
932  T tmp = std::move(array[lhsIdx]);
933  array[lhsIdx] = std::move(array[rhsIdx]);
934  array[rhsIdx] = std::move(tmp);
935 }
936 
938 
948 template <typename T>
949 void
950 swap(T* array, size_t lhsIdx, size_t rhsIdx, size_t size)
951 {
952  T* pi = array + lhsIdx;
953  T* pj = array + rhsIdx;
954  T* piLim = array + lhsIdx + size;
955  T tmp;
956  for (; pi != piLim; ++pi, ++pj)
957  {
958  tmp = std::move(*pi);
959  *pi = std::move(*pj);
960  *pj = std::move(tmp);
961  }
962 }
963 
965 
972 inline void
974 {
975  // volatile -> instruct the optimizer to leave this assembly code alone & not analyze it
976  // memory -> assume that global memory is "clobbered" (affected)
977  asm volatile("" : : : "memory");
978 }
979 
981 
989 inline void
990 escape(void* ptr)
991 {
992  // volatile -> instruct the optimizer to leave this assembly code alone & not analyze it
993  // "g"(ptr) -> the (empty) assembly code uses ptr as an input
994  // memory -> assume that global memory is "clobbered" (affected)
995  asm volatile("" : : "g"(ptr) : "memory");
996 }
997 
999 
1007 constexpr size_t
1008 KB(size_t n)
1009 {
1010  return n * (size_t)1024;
1011 }
1012 
1014 
1022 constexpr size_t
1023 MB(size_t n)
1024 {
1025  return n * (size_t)1024 * (size_t)1024;
1026 }
1027 
1029 
1037 constexpr size_t
1038 GB(size_t n)
1039 {
1040  return n * (size_t)1024 * (size_t)1024 * (size_t)1024;
1041 }
1042 
1044 
1045 UTL_NS_END;
void serializeBoxed(T *&object, Stream &stream, uint_t io, uint_t mode=ser_default)
Serialize a boxed object.
Definition: util_inl.h:853
size_t allocatedSize(const Object *object)
Compute the allocated size of an object.
Definition: util_inl.h:191
T * clone(const T *object)
Create a clone of the given object.
Definition: util_inl.h:404
T roundDown(const T &v, const T &m)
Round the given value v down to the nearest multiple of m.
Definition: util_inl.h:747
constexpr size_t MB(size_t n)
Convert size in megabytes to size in bytes.
Definition: util_inl.h:1023
Object comparison abstraction.
Definition: Ordering.h:30
bool comparisonResultMatchesOp(int cmpRes, uint_t cmpOp)
Determine whether the given comparison result is consistent with the given comparison operator...
Definition: util_inl.h:587
const T & max(const T &a, const T &b, const R &... args)
Return the largest value among two or more provided values of the same type.
Definition: util_inl.h:89
default representation (via getSerializeMode())
Definition: util.h:75
T * cast(utl::Object *object)
Safely cast an object pointer to the desired type.
Definition: util_inl.h:355
const T & max(const T &v)
Base case for utl::max() variadic template.
Definition: util_inl.h:71
uint64_t nextPow2(uint64_t n)
Return the smallest power of 2 which is >= n.
Definition: util_inl.h:121
Object comparison evaluator.
Definition: util_inl.h:610
Toggle a boolean value RAII-style.
Definition: util_inl.h:18
const size_t size_t_max
Maximum size_t value.
unsigned int uint32_t
Unsigned 32-bit integer.
Definition: types.h:115
int compare(typename InputCont1::const_iterator lhsBegin, typename InputCont1::const_iterator lhsEnd, typename InputCont2::const_iterator rhsBegin, typename InputCont2::const_iterator rhsEnd, std::function< int(typename InputCont1::value_type, typename InputCont2::value_type)> comp)
Compare two sequences.
Definition: util_inl.h:554
void copy(T *dest, const T *src, size_t len)
Copy one array of objects to another.
Definition: util_inl.h:690
void serialize(T &object, Stream &stream, uint_t io, uint_t mode=ser_default)
Serialize an object (non-boxed).
Definition: util_inl.h:807
bool isDivisibleBy(const T &x, const T &n)
Determine whether x is evenly divisible by n.
Definition: util_inl.h:711
read
Definition: util.h:58
unsigned long uint64_t
Unsigned 64-bit integer.
Definition: types.h:154
constexpr size_t GB(size_t n)
Convert size in gigabytes to size in bytes.
Definition: util_inl.h:1038
~BoolToggle()
Destructor.
Definition: util_inl.h:29
greater-than
Definition: util.h:31
void swap(T *array, size_t lhsIdx, size_t rhsIdx, size_t size)
Swap two sections of the given array.
Definition: util_inl.h:950
void arrayGrow(T *&array, T *&arrayPtr, T *&arrayLim, size_t minSize=size_t_max, size_t growthIncrement=size_t_max)
Grow an array.
Definition: util_inl.h:284
int compareNullable(const Object *lhs, const Object *rhs, const Ordering *ordering=nullptr)
Compare two objects.
Definition: util_inl.h:466
unsigned int uint_t
Unsigned integer.
Definition: types.h:59
less-than
Definition: util.h:28
#define ABORT()
Immediately terminates the program.
Definition: macros.h:59
Object comparison predicate evaluator that returns the value of (lhs < rhs).
Definition: util_inl.h:662
T * cast_const(const utl::Object *object)
Safely cast an object pointer to the desired type (remove const-qualifier).
Definition: util_inl.h:387
Stream I/O abstraction.
Definition: Stream.h:68
unsigned short uint16_t
Unsigned 16-bit integer.
Definition: types.h:101
void escape(void *ptr)
Fake read/write access to all memory, and require the object at address ptr to exist.
Definition: util_inl.h:990
#define isA(className)
Determine whether the class is derived from the given class.
Definition: RunTimeClass.h:230
const T & min(const T &a, const T &b, const R &... args)
Return the smallest value among two or more provided values of the same type.
Definition: util_inl.h:61
void serializeNullable(T *&object, Stream &stream, uint_t io, uint_t mode=ser_default)
Serialize a nullable object.
Definition: util_inl.h:825
virtual int compare(const Object &rhs) const
Compare with another object.
constexpr size_t KB(size_t n)
Convert size in kilobytes to size in bytes.
Definition: util_inl.h:1008
uint64_t reverseBytes(uint64_t n)
Reverse the byte ordering of a 64-bit unsigned integer.
Definition: util_inl.h:910
uint64_t nextMultipleOfPow2(uint64_t x, uint64_t target)
Return the smallest number n s.t.
Definition: util_inl.h:174
uint_t getSerializeMode()
Get the default serialization mode (see utl::serialize_t).
void clobber()
Fake read/write access to all memory.
Definition: util_inl.h:973
Root of UTL++ class hierarchy.
Definition: Object.h:52
int compare(bool lhs, bool rhs)
Compare two boolean values.
const T & min(const T &v)
Base case for utl::min() variadic template.
Definition: util_inl.h:43
T roundUp(const T &v, const T &m)
Round the given value v up to the nearest multiple of m.
Definition: util_inl.h:728
#define ASSERTD
Do an assertion in DEBUG mode only.
T nextMultiple(const T &x, const T &target)
Return the smallest number n s.t.
Definition: util_inl.h:142
Object comparison predicate evaluator that returns the value of (lhs == rhs).
Definition: util_inl.h:636
BoolToggle(bool &b)
Constructor.
Definition: util_inl.h:22