rcolyer.net
RC Lib  Version 202403231100
RCBits.h
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////
2 //
3 // RC Library, (c) 2011-2019, Ryan A. Colyer
4 // Distributed under the Boost Software License, v1.0. (LICENSE.txt)
5 //
6 /// \file RCBits.h
7 /// Provides short convenience classes and functions.
8 /////////////////////////////////////////////////////////////////////
9 
10 #ifndef RC_RCBITS_H
11 #define RC_RCBITS_H
12 
13 #include "RCconfig.h"
14 #include "Errors.h"
15 #ifdef CPP11
16 #include "Tuple.h"
17 #endif
18 #include "Types.h"
19 #include <iostream>
20 #include <sstream>
21 #include <string>
22 
23 namespace RC {
24 
25 /// @cond UNDOC
26 template<class T>
27 class BetwCompare {
28  protected:
29  const T& x;
30  bool ans;
31  public:
32  inline explicit BetwCompare(const T& x) : x(x), ans(true) { }
33 #define RC_BETW_HELP(REL) \
34  template<class T2> \
35  inline BetwCompare operator REL (const T2& other) { \
36  ans &= x REL other; \
37  return *this; \
38  }
39  RC_BETW_HELP(<)
40  RC_BETW_HELP(>)
41  RC_BETW_HELP(<=)
42  RC_BETW_HELP(>=)
43  RC_BETW_HELP(==)
44  RC_BETW_HELP(!=)
45  inline operator bool () const { return ans; }
46 };
47 
48 #define RC_BETW_HELP2(REL1, REL2) \
49 template<class T, class T2> \
50 inline BetwCompare<T> operator REL1 (const T2& other, BetwCompare<T> betw) { \
51  return betw REL2 other; \
52 }
53 
54 RC_BETW_HELP2(<, >)
55 RC_BETW_HELP2(>, <)
56 RC_BETW_HELP2(<=, >=)
57 RC_BETW_HELP2(>=, <=)
58 RC_BETW_HELP2(==, ==)
59 RC_BETW_HELP2(!=, !=)
60 
61 /// @endcond
62 
63 /// Returns a comparator that can be used for range comparisons.
64 /** Usage exmple: if (3.14 < Betw(5) <= 7) { cout << "Yes\n"; }
65  * Works for any comparable types, as long as one of the left-most two in
66  * the chain is wrapped in Betw.
67  */
68 template<class T>
69 BetwCompare<T> Betw(const T& x) { return BetwCompare<T>(x); }
70 
71 #ifdef CPP11
72 
73 /// @cond UNDOC
74 template<class... Args>
75 class OneOfCompare {
76  protected:
77  Tuple<Args...> compare;
78  public:
79  OneOfCompare(Tuple<Args...>&& tup) : compare(tup) { }
80  template<class T, class... Args2>
81  friend bool operator==(const T& item, const OneOfCompare<Args2...>& list);
82  template<class T, class... Args2>
83  friend bool operator!=(const T& item, const OneOfCompare<Args2...>& list);
84 };
85 
86 template<class T, class... Args>
87 bool operator== (const T& item, const OneOfCompare<Args...>& list) {
88  Data1D<T> arr = list.compare.template AsData<T>();
89  for (T& elem : arr) {
90  if (item == elem) {
91  return true;
92  }
93  }
94  return false;
95 }
96 template<class T, class... Args>
97 bool operator!= (const T& item, const OneOfCompare<Args...>& list) {
98  return ! (item == list);
99 }
100 /// @endcond
101 
102 /// Returns a comparator that can be used to check if something is in a list.
103 /** Each element given as a parameter to OneOf is constructed with the type
104  * of the object left of the == or != operator. Usage exmple:
105  * RStr str = "foo"; if (str != OneOf("bar", -3.54, "blah")) {
106  * cout << "Not Found\n"; } int x = 8; if (5 == OneOf(3.14, 5, x)) {
107  * cout << "Found\n"; }
108  */
109 template<class... Args>
110 OneOfCompare<Args...> OneOf(Args... args) {
111  return OneOfCompare<Args...>(Tuple<Args...>(args...));
112 }
113 #endif
114 
115 
116 /// A size_t like integer class which automatically stays within its range.
117 /** Use this for circular buffers or anywhere modulo arithmetic is needed.
118  */
119 class LoopIndex {
120  public:
121  /// Defines the range of of the object. The index is always less than this.
122  inline LoopIndex(size_t range) : index(0), range(range) { }
123  /// Returns the set range.
124  inline size_t Range() const { return range; }
125  /// Sets a new range.
126  inline void SetRange(size_t new_range) { range = new_range; *this = index; }
127  /// Assigns a new index value, forcing it in the range. Signed indices are
128  /// handled properly.
129  inline LoopIndex& operator= (size_t new_index) {
130  if (new_index > (size_t(-1)/2)) {
131  index = range - ((0-new_index) % range);
132  }
133  else {
134  index = new_index % range;
135  }
136  return *this;
137  }
138  /// Implicitly returns the size_t index.
139  inline operator size_t () const { return index; }
140  /// Increment by one, looping within range.
141  inline LoopIndex& operator++ () {
142  index++;
143  if (index>=range) { index=0; }
144  return *this;
145  }
146  /// Postfix increment by one, looping within range.
147  inline LoopIndex operator++ (int) {
148  LoopIndex tmp(*this);
149  ++(*this);
150  return tmp;
151  }
152  /// Decrement by one, looping within range.
153  inline LoopIndex& operator-- () {
154  if (index==0) { index = range-1; }
155  else { index--; }
156  return *this;
157  }
158  /// Postfix decrement by one, looping within range.
159  inline LoopIndex operator-- (int) {
160  LoopIndex tmp(*this);
161  --(*this);
162  return tmp;
163  }
164  /// Increment by offset, looping within range, and handling negative offsets
165  /// correctly.
166  inline LoopIndex& operator+= (size_t offset) {
167  if (offset > (size_t(-1)/2)) {
168  size_t negoff = (0-offset)%range;
169  if (index < negoff) {
170  index = range - (negoff - index);
171  }
172  else {
173  index = index - negoff;
174  }
175  }
176  else {
177  index = (index + offset) % range;
178  }
179  return *this;
180  }
181  /// Decrement by offset, looping within range, and handling negative offsets
182  /// correctly.
183  inline LoopIndex& operator-= (size_t offset) {
184  return (*this += 0-offset);
185  }
186 
187  protected:
188  /// @cond PROTECTED
189  size_t index;
190  size_t range;
191  /// @endcond
192 };
193 
194 
195 /// @cond UNDOC
196 
197 template<class T>
198 class DerefIncrement {
199  protected:
200  T val;
201  public:
202  inline DerefIncrement(const T& val) : val(val) { }
203  inline T operator* () const { return val; }
204  inline DerefIncrement& operator++ () { ++val; return *this; }
205  inline DerefIncrement& operator-- () { --val; return *this; }
206  inline bool operator== (const DerefIncrement& other) const {
207  return val == other.val;
208  }
209  inline bool operator!= (const DerefIncrement& other) const {
210  return val != other.val;
211  }
212 };
213 
214 template<class T>
215 class RangeHelper {
216  protected:
217  T start;
218  T past_the_end;
219  public:
220  inline RangeHelper(const T& start, const T& past_the_end) :
221  start(start), past_the_end(past_the_end) { }
222  inline DerefIncrement<T> begin() const { return start; }
223  inline DerefIncrement<T> cbegin() const { return start; }
224  inline DerefIncrement<T> end() const { return past_the_end; }
225  inline DerefIncrement<T> cend() const { return past_the_end; }
226  inline DerefIncrement<T> rbegin() const { return past_the_end-1; }
227  inline DerefIncrement<T> crbegin() const { return past_the_end-1; }
228  inline DerefIncrement<T> rend() const { return start-1; }
229  inline DerefIncrement<T> crend() const { return start-1; }
230 };
231 /// @endcond
232 
233 /// Provides an iterator which dereferences to the iterated values
234 /// [start,past_the_end).
235 /** Usage example, outputs 5 through 9:
236  * for (auto i : Range(5, 10)) { cout << i << endl; }
237  * This is a generalization, since:
238  * for (auto iter : Range(cont.begin(), cont.end())) { ... }
239  * is equivalent to the canonical:
240  * for (auto iter : cont) { ... }
241  */
242 template<class T>
243 inline RangeHelper<T> Range(const T& start, const T& past_the_end) {
244  return RangeHelper<T>(start, past_the_end);
245 }
246 
247 #ifdef CPP11
248 
249 /// Provides an iterator which dereferences to the indices of cont from
250 /// [0,cont.size()).
251 /** Usage example: for (auto i : IndexOf(cont)) { cout << cont[i]; }
252  */
253 template<class T2>
254 inline auto IndexOf(const T2& cont) -> RangeHelper<decltype(cont.size())> {
255  return RangeHelper<decltype(cont.size())>(0, cont.size());
256 }
257 
258 #endif
259 
260 /// Stores the value of type Hold while providing access via type Provide.
261 /** @see RStr::ToLPCWSTR()
262  */
263 template<class Hold, class Provide>
264 class HoldRelated {
265  protected:
266  /// @cond PROTECTED
267  Hold held;
268  Provide give;
269  /// @endcond
270  public:
271 #ifdef CPP11
272  /// Stores held, but implicitly casts to related value give.
273  HoldRelated(Hold held, Provide give)
274  : held(std::move(held)), give(std::move(give)) { }
275  /// Stores held. Use with Set to set the give value later.
276  HoldRelated(Hold held) : held(std::move(held)) { }
277  /// Sets the implicitly cast value of type Provide to give.
278  void Set(Provide new_give) { give = std::move(new_give); }
279 #else
280  HoldRelated(Hold held, Provide give) : held(held), give(give) { }
281  HoldRelated(Hold held) : held(held) { }
282  void Set(Provide new_give) { give = new_give; }
283 #endif
284  /// Implicitly casts to the give value set.
285  operator Provide() { return give; }
286  /// Implicitly casts to the give value set.
287  operator const Provide() const { return give; }
288  /// Explicitly access the value set as give.
289  const Provide Get() const { return give; }
290  /// Explicitly access the value set as give.
291  Provide Get() { return give; }
292  /// Access the full held value.
293  const Hold& Held() const { return held; }
294  /// Access the full held value.
295  Hold& Held() { return held; }
296 };
297 
298 /// Inherit this class to add construction, destruction, and assignment
299 /// output tracking.
300 /** Set ClassTracking to the class which is inheriting this. If
301  * stack_trace is true, a stack trace is output at each event. See
302  * ErrorMsg for stack trace usage details.
303  */
304 template<class ClassTracking, bool stack_trace=false>
305 class DebugTrack {
306  public:
307 /// @cond UNDOC
308 #define RC_DEBUG_TRACK_OUT(label) \
309  std::string name = typeid(ClassTracking).name(); \
310  std::stringstream sstr; \
311  sstr << "[" << this << "] -> "; \
312  sstr << label; \
313  if (stack_trace) { \
314  ErrorMsg e(sstr.str().c_str()); \
315  sstr.str(std::string()); \
316  sstr << e.what(); \
317  } \
318  sstr << "\n"; \
319  RC_DEBOUT_STREAM << sstr.str();
320 
321  DebugTrack() {
322  RC_DEBUG_TRACK_OUT(name + "() [Construct]");
323  }
324  ~DebugTrack() {
325  RC_DEBUG_TRACK_OUT("~" + name + "() [Destruct]");
326  }
327  DebugTrack(const DebugTrack&) {
328  RC_DEBUG_TRACK_OUT(name + "(const "+name+"&) [Copy Construct]");
329  }
330  DebugTrack& operator=(const DebugTrack&) {
331  RC_DEBUG_TRACK_OUT(name+"& operator=(const "+name+"&) [Copy Assignment]");
332  return *this;
333  }
334 #ifdef CPP11
336  RC_DEBUG_TRACK_OUT(name + "(" + name + "&&) [Move Construct]");
337  }
338  DebugTrack& operator=(DebugTrack&&) {
339  RC_DEBUG_TRACK_OUT(name + "& operator=("+name+"&&) [Move Assignment]");
340  return *this;
341  }
342 #endif
343 /// @endcond
344 };
345 
346 
347 /// Opens a dynamic library filename and stores a handle to it.
348 /// Use as second parameter for RC_DYNAMIC_LOAD_FUNC(FuncName,DynLib)
349 /** ErrorMsgFile is thrown in the event of a loading error.
350  */
352  public:
353 #ifdef unix
354  /// Direct access to the loaded library.
355  void* library;
356 #elif defined(WIN32)
357  HMODULE library;
358 #endif
359  /// Loads the library of the given name.
360  template<size_t N>
361  DynamicLibrary(const char (&libname)[N]) {
362 #ifdef unix
363  library = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
364 #elif defined(WIN32)
365  library = LoadLibrary(libname);
366 #endif
367  if (!library) {
368  Throw_RC_Type(File, libname);
369  }
370  }
371 };
372 
373 
374 /// @cond UNDOC
375 template<class T>
376 class DynamicFunction {
377  T func;
378  public:
379  template<size_t N>
380  DynamicFunction(DynamicLibrary& dyn_lib, const char (&funcname)[N]) {
381 #ifdef unix
382  func = T(dlsym(dyn_lib.library, funcname));
383 #elif defined(WIN32)
384  func = T(GetProcAddress(dyn_lib.library, funcname));
385 #endif
386  if (!func) {
387  Throw_RC_Type(File, funcname);
388  }
389  }
390 
391  template<class... Args>
392  auto operator()(Args... args) -> decltype((*func)(args...)) {
393  return (*func)(args...);
394  }
395 };
396 /// @endcond
397 
398 
399 /// \def RC_DYNAMIC_LOAD_FUNC
400 /// Use as RC_DYNAMIC_LOAD_FUNC(FuncName,DynLib) to load FuncName from the
401 /// dynamic library file opened by a constructor of the DynamicLibrary class.
402 /** This creates a static function object named FuncName in-place to provide
403  * access to the loaded library. As it overrides FuncName, the previous
404  * declaration of FuncName MUST be in an outer scope (outside of the function
405  * where this is called). For example, include the original definition from a
406  * header, and use this inside of a function or namespace. After this macro,
407  * call FuncName with the same syntax as you would the previously declared
408  * FuncName. This macro uses classes defined for both Linux and Windows.
409  * ErrorMsgFile is thrown in the event of a loading error.
410  */
411 #define RC_DYNAMIC_LOAD_FUNC(FuncName,DynLib) \
412  static RC::DynamicFunction<decltype(FuncName)> FuncName{DynLib, #FuncName};
413 
414 
415 #ifdef CPP11
416 /// For integer and floating point types, Throws RC::ErrorMsgBounds if
417 /// the value of x does not fit into T. Use as CheckedCast<T>(x)
418 template<class T, class T2>
419 inline T CheckedCast(const T2 &x) {
420  bool out_of_bounds = false;
421 
422  if (IsIntegerType<T>()) {
423  if (intmax_t(x) < intmax_t(LOW_VAL<T>())) {
424  out_of_bounds = true;
425  }
426  else if (x > 0 && uintmax_t(x) > uintmax_t(MAX_VAL<T>())) {
427  out_of_bounds = true;
428  }
429  }
430  else {
431  if (fBIGGEST(x) < fBIGGEST(LOW_VAL<T>())) {
432  out_of_bounds = true;
433  }
434  else if (fBIGGEST(x) > fBIGGEST(MAX_VAL<T>())) {
435  out_of_bounds = true;
436  }
437  }
438  if (out_of_bounds) {
439  Throw_RC_Type(Bounds, "Cast out of bounds");
440  }
441  return T(x);
442 }
443 
444 /// For integer and floating point types, caps the cast value of x to
445 /// be within bounds of type T. Use as CappedCast<T>(x)
446 template<class T, class T2>
447 inline T CappedCast(const T2 &x) {
448  if (IsIntegerType<T>()) {
449  if (intmax_t(x) < intmax_t(LOW_VAL<T>())) {
450  return LOW_VAL<T>();
451  }
452  if (x > 0 && uintmax_t(x) > uintmax_t(MAX_VAL<T>())) {
453  return MAX_VAL<T>();
454  }
455  }
456  else {
457  if (fBIGGEST(x) < fBIGGEST(LOW_VAL<T>())) {
458  return LOW_VAL<T>();
459  }
460  if (fBIGGEST(x) > fBIGGEST(MAX_VAL<T>())) {
461  return MAX_VAL<T>();
462  }
463  }
464  return T(x);
465 }
466 #endif
467 
468 }
469 
470 #endif // RC_RCBITS_H
471 
Provides informative exception handling.
#define Throw_RC_Type(Type, err)
Use this to throw an RC:ErrorMsg subtype exception.
Definition: Errors.h:282
T & operator*()
Dereferences the pointer, or throws an exception if null.
Definition: PtrCommon.h:38
The version information and configuration settings for RC Lib.
Provides a Tuple class which can apply its contents as function parameters.
Provides typedefs and routines for working with primitives.
f128 fBIGGEST
The biggest float type available.
Definition: Types.h:49
Inherit this class to add construction, destruction, and assignment output tracking.
Definition: RCBits.h:305
Opens a dynamic library filename and stores a handle to it. Use as second parameter for RC_DYNAMIC_LO...
Definition: RCBits.h:351
void * library
Direct access to the loaded library.
Definition: RCBits.h:355
DynamicLibrary(const char(&libname)[N])
Loads the library of the given name.
Definition: RCBits.h:361
A class with static methods for file and directory info and manipulation.
Definition: File.h:1214
Stores the value of type Hold while providing access via type Provide.
Definition: RCBits.h:264
const Hold & Held() const
Access the full held value.
Definition: RCBits.h:293
Provide Get()
Explicitly access the value set as give.
Definition: RCBits.h:291
Hold & Held()
Access the full held value.
Definition: RCBits.h:295
const Provide Get() const
Explicitly access the value set as give.
Definition: RCBits.h:289
HoldRelated(Hold held, Provide give)
Stores held, but implicitly casts to related value give.
Definition: RCBits.h:273
void Set(Provide new_give)
Sets the implicitly cast value of type Provide to give.
Definition: RCBits.h:278
HoldRelated(Hold held)
Stores held. Use with Set to set the give value later.
Definition: RCBits.h:276
A size_t like integer class which automatically stays within its range.
Definition: RCBits.h:119
LoopIndex & operator++()
Increment by one, looping within range.
Definition: RCBits.h:141
size_t Range() const
Returns the set range.
Definition: RCBits.h:124
LoopIndex & operator=(size_t new_index)
Assigns a new index value, forcing it in the range. Signed indices are handled properly.
Definition: RCBits.h:129
LoopIndex(size_t range)
Defines the range of of the object. The index is always less than this.
Definition: RCBits.h:122
LoopIndex & operator-=(size_t offset)
Decrement by offset, looping within range, and handling negative offsets correctly.
Definition: RCBits.h:183
LoopIndex & operator--()
Decrement by one, looping within range.
Definition: RCBits.h:153
LoopIndex & operator+=(size_t offset)
Increment by offset, looping within range, and handling negative offsets correctly.
Definition: RCBits.h:166
void SetRange(size_t new_range)
Sets a new range.
Definition: RCBits.h:126
An efficient Tuple class with Set, Get, and an Apply function to pass the tuple contents on to any fu...
Definition: Tuple.h:62
Definition: APtr.h:25
T CheckedCast(const T2 &x)
For integer and floating point types, Throws RC::ErrorMsgBounds if the value of x does not fit into T...
Definition: RCBits.h:419
BetwCompare< T > Betw(const T &x)
Returns a comparator that can be used for range comparisons.
Definition: RCBits.h:69
bool operator!=(const RStr &lhs, const RStr &rhs)
True if lhs does not equal rhs.
Definition: RStr.h:2276
OneOfCompare< Args... > OneOf(Args... args)
Returns a comparator that can be used to check if something is in a list.
Definition: RCBits.h:110
auto IndexOf(const T2 &cont) -> RangeHelper< decltype(cont.size())>
Provides an iterator which dereferences to the indices of cont from [0,cont.size()).
Definition: RCBits.h:254
T CappedCast(const T2 &x)
For integer and floating point types, caps the cast value of x to be within bounds of type T....
Definition: RCBits.h:447
bool operator==(const RStr &lhs, const RStr &rhs)
True if lhs equals rhs.
Definition: RStr.h:2271
RangeHelper< T > Range(const T &start, const T &past_the_end)
Provides an iterator which dereferences to the iterated values [start,past_the_end).
Definition: RCBits.h:243
email address
— (c) 2015