Evo C++ Library v0.5.1
atomic.h
Go to the documentation of this file.
1 // Evo C++ Library
2 /* Copyright 2019 Justin Crowell
3 Distributed under the BSD 2-Clause License -- see included file LICENSE.txt for details.
4 */
6 
7 #pragma once
8 #ifndef INCL_evo_atomic_h
9 #define INCL_evo_atomic_h
10 
11 // Includes/Defines
12 #include "impl/sys.h"
13 #include "type.h"
14 #if defined(EVO_CPP11) || (defined(EVO_MSVC_YEAR) && EVO_MSVC_YEAR >= 2012) || defined(EVO_INTEL_VER)
15  #include <atomic>
16  #define EVO_INTRINSIC_ATOMICS 1 // 1 when compiler supports atomic operations
17  #define EVO_STD_ATOMIC 1 // 1 when compiler supports std::atomic and std::atomic_flag
18  #define EVO_ATOMIC_PTRMATH 1 // 1 when pointer math works correctly with AtomicPtr, i.e. increment uses sizeof()
19 
21  #define EVO_ATOMIC_RELAXED std::memory_order_relaxed
22 
24  #define EVO_ATOMIC_CONSUME std::memory_order_consume
25 
27  #define EVO_ATOMIC_ACQUIRE std::memory_order_acquire
28 
30  #define EVO_ATOMIC_RELEASE std::memory_order_release
31 
33  #define EVO_ATOMIC_ACQ_REL std::memory_order_acq_rel
34 
36  #define EVO_ATOMIC_SYNC std::memory_order_seq_cst
37 
52  #define EVO_ATOMIC_FENCE(MEM_ORDER) std::atomic_thread_fence(MEM_ORDER)
53 #elif defined(EVO_GCC_VER) && EVO_GCC_VER >= 407
54  // gcc 4.7+ has __atomic built-ins
55  #define EVO_INTRINSIC_ATOMICS 1
56  #define EVO_GCC_ATOMICS 1
57 
58  #define EVO_ATOMIC_RELAXED __ATOMIC_RELAXED
59  #define EVO_ATOMIC_CONSUME __ATOMIC_CONSUME
60  #define EVO_ATOMIC_ACQUIRE __ATOMIC_ACQUIRE
61  #define EVO_ATOMIC_RELEASE __ATOMIC_RELEASE
62  #define EVO_ATOMIC_ACQ_REL __ATOMIC_ACQ_REL
63  #define EVO_ATOMIC_SYNC __ATOMIC_SEQ_CST
64 
65  #define EVO_ATOMIC_FENCE(MEM_ORDER) __atomic_thread_fence(MEM_ORDER)
66 
67  #define EVO_ATOMIC_FETCH_OP(OP, PTR, VAL, MEM_ORDER) __atomic_fetch_ ## OP (PTR, VAL, MEM_ORDER)
68  #define EVO_ATOMIC_OP_FETCH(OP, PTR, VAL, MEM_ORDER) __atomic_ ## OP ## _fetch(PTR, VAL, MEM_ORDER)
69 #else
70  // Legacy
71  #define EVO_ATOMIC_RELAXED 0
72  #define EVO_ATOMIC_CONSUME 0
73  #define EVO_ATOMIC_ACQUIRE 0
74  #define EVO_ATOMIC_RELEASE 0
75  #define EVO_ATOMIC_ACQ_REL 0
76  #define EVO_ATOMIC_SYNC 0
77 
78  #if defined(EVO_MSVC_YEAR) || (defined(EVO_GCC_VER) && EVO_GCC_VER < 401)
79  // MSVC doesn't support atomics before 2012
80  // gcc doesn't support atomics before 4.1
81  #define EVO_INTRINSIC_ATOMICS 0
82  #else
83  // Legacy __sync built-ins, supported by older gcc and clang, possibly others
84  #define EVO_INTRINSIC_ATOMICS 1
85  #define EVO_ATOMIC_FENCE(MEM_ORDER) __sync_synchronize()
86 
87  #define EVO_ATOMIC_FETCH_OP(OP, PTR, VAL, MEM_ORDER) __sync_fetch_and_ ## OP (PTR, VAL)
88  #define EVO_ATOMIC_OP_FETCH(OP, PTR, VAL, MEM_ORDER) __sync_ ## OP ## _and_fetch(PTR, VAL)
89  #endif
90 #endif
91 #if !EVO_INTRINSIC_ATOMICS
92  // Emulate atomics with SysMutex
93  #include "impl/systhread.h"
94  #define EVO_ATOMIC_PTRMATH 1
95 #endif
96 
97 // Check if static initialization is thread safe ("magic statics")
98 #if defined(EVO_ATOMIC_SAFE_STATICS)
99  // Already defined, allow user to override
100 #else
101  #if defined(EVO_MSVC_YEAR)
102  #if EVO_MSVC_YEAR >= 2015 // No thread-safe static init until MSVC 2015
103  #define EVO_ATOMIC_SAFE_STATICS 1
104  #endif
105  #elif defined(EVO_CPP11) // C++11 requires thread-safe static init
106  #define EVO_ATOMIC_SAFE_STATICS 1
107  #elif defined(EVO_CLANG_VER) // clang 2.9+
108  #if EVO_CLANG_VER >= 209
109  #define EVO_ATOMIC_SAFE_STATICS 1
110  #endif
111  #elif defined(EVO_GCC_VER) // gcc 4.3+
112  #if EVO_GCC_VER >= 403
113  #define EVO_ATOMIC_SAFE_STATICS 1
114  #endif
115  #endif
116 
117  #if !defined(EVO_ATOMIC_SAFE_STATICS)
118 
122  #define EVO_ATOMIC_SAFE_STATICS 0
123  #endif
124 #endif
125 
126 // Disable certain MSVC warnings for this file, if !EVO_INTRINSIC_ATOMICS
127 #if defined(EVO_MSVC_YEAR) && !EVO_INTRINSIC_ATOMICS
128  #pragma warning(push)
129  #pragma warning(disable:4800 4100)
130 #endif
131 
132 // Namespace: evo
133 namespace evo {
134 
137 
139 #if defined(EVO_STD_ATOMIC)
140 
153  typedef std::memory_order MemOrder;
154 #else
155  typedef int MemOrder;
156 #endif
157 
158 // Temp macro to emulate atomic op with mutex
159 #if !EVO_INTRINSIC_ATOMICS
160  #define EVO_TMP_ATOMIC_OP(CODE) { T val; mutex_.lock(); CODE; mutex_.unlock(); return val; }
161 #endif
162 
164 
171 #if defined(EVO_STD_ATOMIC)
172 struct AtomicFlag : public std::atomic_flag {
173  #if defined(EVO_CLANG_VER) || defined(EVO_MSVC_YEAR)
174  AtomicFlag() // some compilers don't support ATOMIC_FLAG_INIT init here
175  { clear(); }
176  #else
177 
178  AtomicFlag() : atomic_flag(ATOMIC_FLAG_INIT)
179  { }
180  #endif
181 
182  #if defined(DOXYGEN)
183 
184  void clear(MemOrder mem_order=EVO_ATOMIC_SYNC);
185 
189  bool test_and_set(MemOrder mem_order=EVO_ATOMIC_SYNC);
190  #endif
191 #else
192 struct AtomicFlag {
193  AtomicFlag()
194  { clear(); }
195 
196  void clear(int mem_order=EVO_ATOMIC_SYNC) {
197  #if !EVO_INTRINSIC_ATOMICS
198  mutex_.lock();
199  val_ = 0;
200  mutex_.unlock();
201  #elif defined(EVO_GCC_ATOMICS)
202  __atomic_clear(&val_, mem_order);
203  #else
204  val_ = 0;
205  EVO_ATOMIC_FENCE(mem_order);
206  #endif
207  }
208 
209  bool test_and_set(int mem_order=EVO_ATOMIC_SYNC) {
210  #if !EVO_INTRINSIC_ATOMICS
211  typedef int T;
212  EVO_TMP_ATOMIC_OP(val = val_; val_ = 1)
213  #elif defined(EVO_GCC_ATOMICS)
214  return __atomic_test_and_set(&val_, mem_order);
215  #else
216  return !__sync_bool_compare_and_swap(&val_, 0, 1);
217  #endif
218  }
219 
220 private:
221  #if defined(EVO_GCC_ATOMICS)
222  bool val_;
223  #else
224  int val_;
225  #endif
226 
227 public:
228 #endif
229 
234  void lock() {
236  { }
237  }
238 
247  void sleeplock(ulong ms=1) {
248  assert(ms > 0);
250  sleepms(ms);
251  }
252 
256  void unlock()
258 
259 private:
260 #if !EVO_INTRINSIC_ATOMICS
261  mutable SysMutex mutex_;
262 #endif
263 
264  // Disable copying
265  AtomicFlag(const AtomicFlag&);
266  AtomicFlag& operator=(const AtomicFlag&);
267 };
268 
270 
309 #if defined(EVO_STD_ATOMIC)
310 template<class T>
311 class Atomic : public std::atomic<T>, public SafeBool<Atomic<T> > {
312 public:
313  typedef Atomic<T> This;
314 
319  This& operator=(T num) {
320  this->store(num);
321  return *this;
322  }
323 
332  bool compare_set(T cmpval, T newval, MemOrder mem_order_success=EVO_ATOMIC_SYNC, MemOrder mem_order_failure=EVO_ATOMIC_ACQUIRE)
333  { T oldval = cmpval; return this->compare_exchange_strong(oldval, newval, mem_order_success, mem_order_failure); }
334 
335  #if defined(DOXYGEN)
336 
340  T load(MemOrder mem_order=EVO_ATOMIC_SYNC) const;
341 
347  T exchange(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
348 
353  void store(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
354 
360  T fetch_add(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
361 
367  T fetch_sub(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
368 
374  T fetch_and(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
375 
381  T fetch_or(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
382 
388  T fetch_xor(T num, MemOrder mem_order=EVO_ATOMIC_SYNC);
389 
393  T operator++();
394 
398  T operator++(int);
399 
403  T operator--();
404 
408  T operator--(int);
409 
413  T operator+=(T num);
414 
418  T operator-=(T num);
419 
423  T operator&=(T num);
424 
428  T operator|=(T num);
429 
433  T operator^=(T num);
434  #endif
435 #else
436 template<class T>
437 struct Atomic : public SafeBool<Atomic<T> > {
438  typedef Atomic<T> This;
439 
440  T load(int mem_order=EVO_ATOMIC_SYNC) const {
441  #if !EVO_INTRINSIC_ATOMICS
442  EVO_TMP_ATOMIC_OP(val = val_)
443  #elif defined(EVO_GCC_ATOMICS)
444  return __atomic_load_n(&val_, mem_order);
445  #else
446  T val;
447  __sync_synchronize();
448  val = val_;
449  __sync_synchronize();
450  return val;
451  #endif
452  }
453 
454  T exchange(T num, int mem_order=EVO_ATOMIC_SYNC) {
455  #if !EVO_INTRINSIC_ATOMICS
456  EVO_TMP_ATOMIC_OP(val = val_; val_ = num)
457  #elif defined(EVO_GCC_ATOMICS)
458  return __atomic_exchange_n(&val_, num, mem_order);
459  #else
460  T prev_val;
461  do {
462  __sync_synchronize();
463  prev_val = val_;
464  } while (!__sync_bool_compare_and_swap(&val_, prev_val, num));
465  return prev_val;
466  #endif
467  }
468 
469  void store(T num, int mem_order=EVO_ATOMIC_SYNC) {
470  #if !EVO_INTRINSIC_ATOMICS
471  mutex_.lock();
472  val_ = num;
473  mutex_.unlock();
474  #elif defined(EVO_GCC_ATOMICS)
475  __atomic_store_n(&val_, num, mem_order);
476  #else
477  val_ = num;
478  __sync_synchronize();
479  #endif
480  }
481 
482  This& operator=(T num) {
483  store(num);
484  return *this;
485  }
486 
487  bool compare_set(T cmpval, T newval, int mem_order_success=EVO_ATOMIC_SYNC, int mem_order_failure=EVO_ATOMIC_SYNC) {
488  #if !EVO_INTRINSIC_ATOMICS
489  bool replaced = false;
490  mutex_.lock();
491  if (val_ == cmpval) {
492  val_ = newval;
493  replaced = true;
494  }
495  mutex_.unlock();
496  return replaced;
497  #elif defined(EVO_GCC_ATOMICS)
498  return __atomic_compare_exchange_n(&val_, &cmpval, newval, false, mem_order_success, mem_order_failure);
499  #else
500  return __sync_bool_compare_and_swap(&val_, cmpval, newval);
501  #endif
502  }
503 
504 #if EVO_INTRINSIC_ATOMICS
505  T fetch_add(T num, int mem_order=EVO_ATOMIC_SYNC)
506  { return EVO_ATOMIC_FETCH_OP(add, &val_, num, mem_order); }
507 
508  T fetch_sub(T num, int mem_order=EVO_ATOMIC_SYNC)
509  { return EVO_ATOMIC_FETCH_OP(sub, &val_, num, mem_order); }
510 
511  T fetch_and(T num, int mem_order=EVO_ATOMIC_SYNC)
512  { return EVO_ATOMIC_FETCH_OP(and, &val_, num, mem_order); }
513 
514  T fetch_or(T num, int mem_order=EVO_ATOMIC_SYNC)
515  { return EVO_ATOMIC_FETCH_OP(or, &val_, num, mem_order); }
516 
517  T fetch_xor(T num, int mem_order=EVO_ATOMIC_SYNC)
518  { return EVO_ATOMIC_FETCH_OP(xor, &val_, num, mem_order); }
519 
520  T operator++()
521  { return EVO_ATOMIC_OP_FETCH(add, &val_, (T)1, EVO_ATOMIC_SYNC); }
522 
523  T operator++(int)
524  { return EVO_ATOMIC_FETCH_OP(add, &val_, (T)1, EVO_ATOMIC_SYNC); }
525 
526  T operator--()
527  { return EVO_ATOMIC_OP_FETCH(sub, &val_, (T)1, EVO_ATOMIC_SYNC); }
528 
529  T operator--(int)
530  { return EVO_ATOMIC_FETCH_OP(sub, &val_, (T)1, EVO_ATOMIC_SYNC); }
531 
532  T operator+=(T num)
533  { return EVO_ATOMIC_OP_FETCH(add, &val_, num, EVO_ATOMIC_SYNC); }
534 
535  T operator-=(T num)
536  { return EVO_ATOMIC_OP_FETCH(sub, &val_, num, EVO_ATOMIC_SYNC); }
537 
538  T operator&=(T num)
539  { return EVO_ATOMIC_OP_FETCH(and, &val_, num, EVO_ATOMIC_SYNC); }
540 
541  T operator|=(T num)
542  { return EVO_ATOMIC_OP_FETCH(or, &val_, num, EVO_ATOMIC_SYNC); }
543 
544  T operator^=(T num)
545  { return EVO_ATOMIC_OP_FETCH(xor, &val_, num, EVO_ATOMIC_SYNC); }
546 
547 #else
548  // Emulate atomic type with mutex
549  typedef typename StaticIf<IsPointer<T>::value,ulong,T>::Type NumType;
550 
551  T fetch_add(T num, int mem_order=EVO_ATOMIC_SYNC)
552  { EVO_TMP_ATOMIC_OP(val = val_; val_ += (NumType)num) }
553 
554  T fetch_sub(T num, int mem_order=EVO_ATOMIC_SYNC)
555  { EVO_TMP_ATOMIC_OP(val = val_; val_ -= (NumType)num) }
556 
557  T fetch_and(T num, int mem_order=EVO_ATOMIC_SYNC)
558  { EVO_TMP_ATOMIC_OP(val = val_; val_ &= (NumType)num) }
559 
560  T fetch_or(T num, int mem_order=EVO_ATOMIC_SYNC)
561  { EVO_TMP_ATOMIC_OP(val = val_; val_ |= (NumType)num) }
562 
563  T fetch_xor(T num, int mem_order=EVO_ATOMIC_SYNC)
564  { EVO_TMP_ATOMIC_OP(val = val_; val_ ^= (NumType)num) }
565 
566  T operator++()
567  { EVO_TMP_ATOMIC_OP(val = ++val_) }
568 
569  T operator++(int)
570  { EVO_TMP_ATOMIC_OP(val = val_; ++val_) }
571 
572  T operator--()
573  { EVO_TMP_ATOMIC_OP(val = --val_) }
574 
575  T operator--(int)
576  { EVO_TMP_ATOMIC_OP(val = val_; --val_) }
577 
578  T operator+=(T num)
579  { EVO_TMP_ATOMIC_OP(val = val_ += (NumType)num) }
580 
581  T operator-=(T num)
582  { EVO_TMP_ATOMIC_OP(val = val_ -= (NumType)num) }
583 
584  T operator&=(T num)
585  { EVO_TMP_ATOMIC_OP(val = val_ &= (NumType)num) }
586 
587  T operator|=(T num)
588  { EVO_TMP_ATOMIC_OP(val = val_ |= (NumType)num) }
589 
590  T operator^=(T num)
591  { EVO_TMP_ATOMIC_OP(val = val_ ^= (NumType)num) }
592 #endif
593 
594 protected:
595  T val_;
596 #endif
597 
598 public:
601  { this->store(0); }
602 
606  Atomic(T num)
607  { this->store(num); }
608 
613  operator T() const
614  { return this->load(); }
615 
622  const T operator->() const
623  { return this->load(); }
624 
632  { return this->load(); }
633 
637  bool operator!() const
638  { return !this->load(); }
639 
644  bool operator==(const This& num) const
645  { return (this == &num || this->load() == num.load()); }
646 
651  bool operator==(T num) const
652  { return this->load() == num; }
653 
658  bool operator!=(const This& num) const
659  { return (this != &num && this->load() != num.load()); }
660 
665  bool operator!=(T num) const
666  { return this->load() != num; }
667 
672  bool operator<(T num) const
673  { return this->load() < num; }
674 
679  bool operator<=(T num) const
680  { return this->load() <= num; }
681 
686  bool operator>(T num) const
687  { return this->load() > num; }
688 
693  bool operator>=(T num) const
694  { return this->load() >= num; }
695 
696 private:
697 #if !EVO_INTRINSIC_ATOMICS
698  mutable SysMutex mutex_;
699 #endif
700 
701  // Disable copying
702  Atomic(const This&);
703  This& operator=(const This&);
704 };
705 
707 
714 
719 
721 
722 // Undef temp macro
723 #if defined(EVO_TMP_ATOMIC_OP)
724  #undef EVO_TMP_ATOMIC_OP
725 #endif
726 
727 #if defined(_MSC_VER) && !EVO_INTRINSIC_ATOMICS
728  #pragma warning(pop)
729 #endif
730 
732 
742 template<class T>
743 class AtomicPtr : public PtrBase<T, Atomic<T*> > {
744 protected:
745  using PtrBase<T, Atomic<T*> >::ptr_;
746 
747 public:
748  typedef AtomicPtr<T> This;
751 
754  { }
755 
759  AtomicPtr(T* ptr)
760  { ptr_.store(ptr); }
761 
765  AtomicPtr(const T* ptr)
766  { ptr_.store((T*)ptr); }
767 
771  AtomicPtr(const This& src)
772  { ptr_.store(src.ptr_.load()); }
773 
777  AtomicPtr(const Base& src)
778  { ptr_.store(src.ptr_); }
779 
783  AtomicPtr(const PtrBaseT& src)
784  { ptr_.store(src.ptr_); }
785 
790  This& operator=(const This& src)
791  { ptr_.store(src.ptr_.load()); return *this; }
792 
797  This& operator=(const Base& src)
798  { ptr_.store(src.ptr_); return *this; }
799 
804  This& operator=(const PtrBaseT& src)
805  { ptr_.store(src.ptr_); return *this; }
806 
811  This& operator=(T* ptr)
812  { ptr_.store(ptr); return *this; }
813 
818  This& operator=(const T* ptr)
819  { ptr_.store((T*)ptr); return *this; }
820 
824  This& clear()
825  { ptr_.store(NULL); return *this; }
826 
832  T* detach()
833  { return ptr_.exchange(NULL); }
834 
838  T* operator++() {
839  #if defined(EVO_ATOMIC_PTRMATH)
840  return ++ptr_;
841  #else
842  return ptr_ += (T*)sizeof(T);
843  #endif
844  }
845 
849  T* operator++(int) {
850  #if defined(EVO_ATOMIC_PTRMATH)
851  return ptr_++;
852  #else
853  return ptr_.fetch_add((T*)sizeof(T));
854  #endif
855  }
856 
861  This& operator+=(int count) {
862  #if defined(EVO_STD_ATOMIC)
863  ptr_ += count;
864  #elif defined(EVO_ATOMIC_PTRMATH)
865  ptr_ += (T*)count;
866  #else
867  ptr_ += (T*)(count * sizeof(T));
868  #endif
869  return *this;
870  }
871 
875  T* operator--() {
876  #if defined(EVO_ATOMIC_PTRMATH)
877  return --ptr_;
878  #else
879  return ptr_ -= (T*)sizeof(T);
880  #endif
881  }
882 
886  T* operator--(int) {
887  #if defined(EVO_ATOMIC_PTRMATH)
888  return ptr_--;
889  #else
890  return ptr_.fetch_sub((T*)sizeof(T));
891  #endif
892  }
893 
898  This& operator-=(int count) {
899  #if defined(EVO_STD_ATOMIC)
900  ptr_ -= count;
901  #elif defined(EVO_ATOMIC_PTRMATH)
902  ptr_ -= (T*)count;
903  #else
904  ptr_ -= (T*)(count * sizeof(T));
905  #endif
906  return *this;
907  }
908 
909  using Base::operator==;
910  using Base::operator!=;
911  using Base::operator<;
912  using Base::operator<=;
913  using Base::operator>;
914  using Base::operator>=;
915 
920  bool operator==(const PtrBaseT& ptr) const
921  { return ptr_.load() == ptr.ptr_; }
922 
927  bool operator!=(const PtrBaseT& ptr) const
928  { return ptr_.load() != ptr.ptr_; }
929 
934  bool operator<(const PtrBaseT& ptr) const
935  { return ptr_.load() < ptr.ptr_; }
936 
941  bool operator<=(const PtrBaseT& ptr) const
942  { return ptr_.load() <= ptr.ptr_; }
943 
948  bool operator>(const PtrBaseT& ptr) const
949  { return ptr_.load() > ptr.ptr_; }
950 
955  bool operator>=(const PtrBaseT& ptr) const
956  { return ptr_.load() >= ptr.ptr_; }
957 };
958 
968 template<class T>
969 class AtomicPtr<T[]> : public PtrBase<T, Atomic<T*> > {
970 protected:
971  using PtrBase<T, Atomic<T*> >::ptr_;
972 
973 public:
977 
980  { }
981 
985  AtomicPtr(T* ptr)
986  { ptr_.store(ptr); }
987 
991  AtomicPtr(const T* ptr)
992  { ptr_.store((T*)ptr); }
993 
997  AtomicPtr(const This& src)
998  { ptr_.store(src.ptr_.load()); }
999 
1003  AtomicPtr(const Base& src)
1004  { ptr_.store(src.ptr_); }
1005 
1009  AtomicPtr(const PtrBaseT& src)
1010  { ptr_.store(src.ptr_); }
1011 
1016  This& operator=(const This& src)
1017  { ptr_.store(src.ptr_.load()); return *this; }
1018 
1023  This& operator=(const Base& src)
1024  { ptr_.store(src.ptr_); return *this; }
1025 
1030  This& operator=(const PtrBaseT& src)
1031  { ptr_.store(src.ptr_); return *this; }
1032 
1037  This& operator=(T* ptr)
1038  { ptr_.store(ptr); return *this; }
1039 
1044  This& operator=(const T* ptr)
1045  { ptr_.store((T*)ptr); return *this; }
1046 
1050  This& clear()
1051  { ptr_.store(NULL); return *this; }
1052 
1058  T* detach()
1059  { return ptr_.exchange(NULL); }
1060 
1064  T* operator++() {
1065  #if defined(EVO_ATOMIC_PTRMATH)
1066  return ++ptr_;
1067  #else
1068  return ptr_ += (T*)sizeof(T);
1069  #endif
1070  }
1071 
1075  T* operator++(int) {
1076  #if defined(EVO_ATOMIC_PTRMATH)
1077  return ptr_++;
1078  #else
1079  return ptr_.fetch_add((T*)sizeof(T));
1080  #endif
1081  }
1082 
1087  This& operator+=(int count) {
1088  #if defined(EVO_STD_ATOMIC)
1089  ptr_ += count;
1090  #elif defined(EVO_ATOMIC_PTRMATH)
1091  ptr_ += (T*)count;
1092  #else
1093  ptr_ += (T*)(count * sizeof(T));
1094  #endif
1095  return *this;
1096  }
1097 
1101  T* operator--() {
1102  #if defined(EVO_ATOMIC_PTRMATH)
1103  return --ptr_;
1104  #else
1105  return ptr_ -= (T*)sizeof(T);
1106  #endif
1107  }
1108 
1112  T* operator--(int) {
1113  #if defined(EVO_ATOMIC_PTRMATH)
1114  return ptr_--;
1115  #else
1116  return ptr_.fetch_sub((T*)sizeof(T));
1117  #endif
1118  }
1119 
1124  This& operator-=(int count) {
1125  #if defined(EVO_STD_ATOMIC)
1126  ptr_ -= count;
1127  #elif defined(EVO_ATOMIC_PTRMATH)
1128  ptr_ -= (T*)count;
1129  #else
1130  ptr_ -= (T*)(count * sizeof(T));
1131  #endif
1132  return *this;
1133  }
1134 
1135  using Base::operator==;
1136  using Base::operator!=;
1137  using Base::operator<;
1138  using Base::operator<=;
1139  using Base::operator>;
1140  using Base::operator>=;
1141 
1146  bool operator==(const PtrBaseT& ptr) const
1147  { return ptr_.load() == ptr.ptr_; }
1148 
1153  bool operator!=(const PtrBaseT& ptr) const
1154  { return ptr_.load() != ptr.ptr_; }
1155 
1160  bool operator<(const PtrBaseT& ptr) const
1161  { return ptr_.load() < ptr.ptr_; }
1162 
1167  bool operator<=(const PtrBaseT& ptr) const
1168  { return ptr_.load() <= ptr.ptr_; }
1169 
1174  bool operator>(const PtrBaseT& ptr) const
1175  { return ptr_.load() > ptr.ptr_; }
1176 
1181  bool operator>=(const PtrBaseT& ptr) const
1182  { return ptr_.load() >= ptr.ptr_; }
1183 };
1184 
1186 
1192 template<class T>
1193 inline bool operator==(const PtrBase<T>& ptr1, const PtrBase<T, Atomic<T*> >& ptr2)
1194  { return ptr1.ptr_ == ptr2.ptr_.load(); }
1195 
1201 template<class T>
1202 inline bool operator!=(const PtrBase<T>& ptr1, const PtrBase<T, Atomic<T*> >& ptr2)
1203  { return ptr1.ptr_ != ptr2.ptr_.load(); }
1204 
1210 template<class T>
1211 inline bool operator<(const PtrBase<T>& ptr1, const PtrBase<T, Atomic<T*> >& ptr2)
1212  { return ptr1.ptr_ < ptr2.ptr_.load(); }
1213 
1219 template<class T>
1220 inline bool operator<=(const PtrBase<T>& ptr1, const PtrBase<T, Atomic<T*> >& ptr2)
1221  { return ptr1.ptr_ <= ptr2.ptr_.load(); }
1222 
1228 template<class T>
1229 inline bool operator>(const PtrBase<T>& ptr1, const PtrBase<T, Atomic<T*> >& ptr2)
1230  { return ptr1.ptr_ > ptr2.ptr_.load(); }
1231 
1237 template<class T>
1238 inline bool operator>=(const PtrBase<T>& ptr1, const PtrBase<T, Atomic<T*> >& ptr2)
1239  { return ptr1.ptr_ >= ptr2.ptr_.load(); }
1240 
1242 } // Namespace: evo
1244 #endif
bool operator>=(T num) const
Compare whether current value is greater than or equal to number.
Definition: atomic.h:693
bool operator<(T num) const
Compare whether current value is less than number.
Definition: atomic.h:672
AtomicPtr(const Base &src)
Copy constructor to reference pointer.
Definition: atomic.h:777
AtomicPtr(T *ptr)
Constructor.
Definition: atomic.h:759
AtomicPtr< T > This
This type.
Definition: atomic.h:748
Atomic< long > AtomicLong
Atomic signed long.
Definition: atomic.h:710
T * operator--(int)
Postfix decrement operator.
Definition: atomic.h:886
AtomicPtr(const T *ptr)
Constructor.
Definition: atomic.h:765
Atomic()
Constructor, initializes with 0.
Definition: atomic.h:600
This & operator=(T num)
Store new value.
Definition: atomic.h:319
Atomic signalling flag.
Definition: atomic.h:172
Atomic integer type.
Definition: atomic.h:311
#define EVO_ATOMIC_SYNC
Full sync (sequentially consistent) memory barrier.
Definition: atomic.h:36
This & operator=(const This &src)
Copy/Assignment operator.
Definition: atomic.h:790
bool test_and_set(MemOrder mem_order=std::memory_order_seq_cst)
Atomically set flag (to true) and return the previous value.
PtrBase< T, Atomic< T * > > Base
Base type.
Definition: atomic.h:749
Static conditional type.
Definition: meta.h:134
T * operator++(int)
Prefix increment operator.
Definition: atomic.h:849
Atomic< ulongl > AtomicULongL
Atomic unsigned long long.
Definition: atomic.h:713
This & operator=(const T *ptr)
Assignment operator for raw pointer.
Definition: atomic.h:818
Definition: systhread.h:165
T * operator--()
Prefix decrement operator.
Definition: atomic.h:875
Atomic< int32 > AtomicInt32
Atomic 32-bit signed int.
Definition: atomic.h:715
This & operator-=(int count)
Decrement by count operator.
Definition: atomic.h:898
Evo implementation detail for system portability – this is included by most Evo headers, include this via: include <evo/type.h>.
bool operator!() const
Negation operator checks if NULL/false (0).
Definition: atomic.h:637
Atomic dumb pointer to single object.
Definition: atomic.h:743
PtrBase< T > PtrBaseT
Managed pointer base type.
Definition: atomic.h:750
bool operator!=(T num) const
Compare whether current value is not equal to number.
Definition: atomic.h:665
bool operator==(const PtrBaseT &ptr) const
Equality operator.
Definition: atomic.h:920
bool operator>=(const PtrBase< T > &ptr1, const PtrBase< T, Atomic< T *> > &ptr2)
Greater-than-or-equals operator for managed pointer base and atomic pointer base. ...
Definition: atomic.h:1238
AtomicFlag()
Definition: atomic.h:174
#define EVO_ATOMIC_FENCE(MEM_ORDER)
Sets a memory fence/barrier.
Definition: atomic.h:52
Evo system threads implementation.
const T operator->() const
Member access operator (const).
Definition: atomic.h:622
Atomic< int64 > AtomicInt64
Atomic 64-bit signed int.
Definition: atomic.h:717
bool operator>=(const PtrBaseT &ptr) const
Greater-than-or-equals operator.
Definition: atomic.h:955
bool operator>(T num) const
Compare whether current value is greater than number.
Definition: atomic.h:686
This & operator=(T *ptr)
Assignment operator for raw pointer.
Definition: atomic.h:811
AtomicPtr< T[]> This
This type.
Definition: atomic.h:974
void clear(MemOrder mem_order=std::memory_order_seq_cst)
Clear flag (set to false).
bool operator!=(const This &num) const
Compare whether current value is not equal to number.
Definition: atomic.h:658
bool compare_set(T cmpval, T newval, MemOrder mem_order_success=std::memory_order_seq_cst, MemOrder mem_order_failure=std::memory_order_acquire)
Compare and set, storing new value if comparison matches.
Definition: atomic.h:332
Safe bool base class.
Definition: type.h:73
bool operator==(const PtrBase< T > &ptr1, const PtrBase< T, Atomic< T *> > &ptr2)
Equality operator for managed pointer base and atomic pointer base.
Definition: atomic.h:1193
This & clear()
Clear pointer, setting as null.
Definition: atomic.h:824
void sleeplock(ulong ms=1)
Spin-lock flag with a sleep.
Definition: atomic.h:247
Atomic dumb pointer to array.
Definition: atomic.h:969
AtomicPtr(const PtrBaseT &src)
Copy constructor to reference pointer.
Definition: atomic.h:783
bool operator!=(const PtrBaseT &ptr) const
Inequality operator.
Definition: atomic.h:927
#define EVO_ATOMIC_ACQUIRE
Start "acquire" memory ordering barrier, usually followed by a matching "release" barrier...
Definition: atomic.h:27
bool operator<=(const PtrBaseT &ptr) const
Less-than-or-equals operator.
Definition: atomic.h:941
bool operator==(T num) const
Compare whether current value is equal to number.
Definition: atomic.h:651
T * detach()
Detach and return pointer.
Definition: atomic.h:832
bool operator!=(const PtrBase< T > &ptr1, const PtrBase< T, Atomic< T *> > &ptr2)
Inequality operator for managed pointer base and atomic pointer base.
Definition: atomic.h:1202
bool operator>(const PtrBaseT &ptr) const
Greater-than operator.
Definition: atomic.h:948
Atomic< T > This
This type.
Definition: atomic.h:313
Atomic< int > AtomicInt
Atomic signed int.
Definition: atomic.h:708
AtomicPtr()
Default constructor sets as NULL.
Definition: atomic.h:753
void lock()
Spin-lock flag.
Definition: atomic.h:234
Evo C++ Library namespace.
Definition: alg.h:11
#define EVO_ATOMIC_RELEASE
Release (end) memory ordering barrier started with "consume" or "acquire" barrier.
Definition: atomic.h:30
std::memory_order MemOrder
Atomic memory order (fence) type.
Definition: atomic.h:153
Atomic< ulong > AtomicULong
Atomic unsigned long.
Definition: atomic.h:711
Atomic(T num)
Constructor.
Definition: atomic.h:606
Atomic< uint32 > AtomicUInt32
Atomic 32-bit unsigned int.
Definition: atomic.h:716
void unlock()
Spin-unlock flag.
Definition: atomic.h:256
bool sleepms(ulong msec)
Sleep for number of milliseconds.
Definition: sys.h:654
P ptr_
Pointer.
Definition: type.h:1566
T operator->()
Member access operator.
Definition: atomic.h:631
Atomic< longl > AtomicLongL
Atomic signed long long.
Definition: atomic.h:712
This & operator=(const Base &src)
Assignment operator to reference pointer.
Definition: atomic.h:797
T * operator++()
Prefix increment operator.
Definition: atomic.h:838
bool operator>(const PtrBase< T > &ptr1, const PtrBase< T, Atomic< T *> > &ptr2)
Greater-than operator for managed pointer base and atomic pointer base.
Definition: atomic.h:1229
Base managed pointer.
Definition: type.h:1562
bool operator==(const This &num) const
Compare whether current value is equal to number.
Definition: atomic.h:644
bool operator<(const PtrBaseT &ptr) const
Less-than operator.
Definition: atomic.h:934
T load(MemOrder mem_order=std::memory_order_seq_cst) const
Load and return current value.
Atomic< uint > AtomicUInt
Atomic unsigned int.
Definition: atomic.h:709
This & operator+=(int count)
Increment by count operator.
Definition: atomic.h:861
bool operator<=(T num) const
Compare whether current value is less than or equal to number.
Definition: atomic.h:679
AtomicPtr(const This &src)
Copy constructor.
Definition: atomic.h:771
Evo basic types and traits.
This & operator=(const PtrBaseT &src)
Assignment operator to reference pointer.
Definition: atomic.h:804
Atomic< uint64 > AtomicUInt64
Atomic 64-bit unsigned int.
Definition: atomic.h:718