File indexing completed on 2026-05-10 08:43:07
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_ADT_LAZYATOMICPOINTER_H
0010 #define LLVM_ADT_LAZYATOMICPOINTER_H
0011
0012 #include "llvm/ADT/STLFunctionalExtras.h"
0013 #include "llvm/Support/Compiler.h"
0014 #include <assert.h>
0015 #include <atomic>
0016
0017 namespace llvm {
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 template <class T> class LazyAtomicPointer {
0035 static constexpr uintptr_t getNull() { return 0; }
0036 static constexpr uintptr_t getBusy() { return UINTPTR_MAX; }
0037
0038 static T *makePointer(uintptr_t Value) {
0039 assert(Value != getBusy());
0040 return Value ? reinterpret_cast<T *>(Value) : nullptr;
0041 }
0042 static uintptr_t makeRaw(T *Value) {
0043 uintptr_t Raw = Value ? reinterpret_cast<uintptr_t>(Value) : getNull();
0044 assert(Raw != getBusy());
0045 return Raw;
0046 }
0047
0048 public:
0049
0050 void store(T *Value) { return (void)exchange(Value); }
0051
0052
0053
0054 T *exchange(T *Value) {
0055
0056
0057 T *Old = nullptr;
0058 while (!compare_exchange_weak(Old, Value)) {
0059 }
0060 return Old;
0061 }
0062
0063
0064
0065 bool compare_exchange_weak(T *&ExistingValue, T *NewValue) {
0066 uintptr_t RawExistingValue = makeRaw(ExistingValue);
0067 if (Storage.compare_exchange_weak(RawExistingValue, makeRaw(NewValue)))
0068 return true;
0069
0070
0071 if (RawExistingValue == getBusy())
0072 ExistingValue = nullptr;
0073 else
0074 ExistingValue = makePointer(RawExistingValue);
0075 return false;
0076 }
0077
0078
0079
0080 bool compare_exchange_strong(T *&ExistingValue, T *NewValue) {
0081 uintptr_t RawExistingValue = makeRaw(ExistingValue);
0082 const uintptr_t OriginalRawExistingValue = RawExistingValue;
0083 if (Storage.compare_exchange_strong(RawExistingValue, makeRaw(NewValue)))
0084 return true;
0085
0086
0087 if (LLVM_UNLIKELY(RawExistingValue == getBusy())) {
0088 while (RawExistingValue == getBusy()) {
0089 RawExistingValue = OriginalRawExistingValue;
0090 if (Storage.compare_exchange_weak(RawExistingValue, makeRaw(NewValue)))
0091 return true;
0092 }
0093 }
0094 ExistingValue = makePointer(RawExistingValue);
0095 return false;
0096 }
0097
0098
0099
0100 T *load() const {
0101 uintptr_t RawValue = Storage.load();
0102 return RawValue == getBusy() ? nullptr : makePointer(RawValue);
0103 }
0104
0105
0106
0107
0108
0109 T &loadOrGenerate(function_ref<T *()> Generator) {
0110
0111 uintptr_t Raw = Storage.load();
0112 if (Raw != getNull() && Raw != getBusy())
0113 return *makePointer(Raw);
0114
0115
0116 if (LLVM_LIKELY(Raw == getNull() &&
0117 Storage.compare_exchange_strong(Raw, getBusy()))) {
0118 Raw = makeRaw(Generator());
0119 assert(Raw != getNull() && "Expected non-null from generator");
0120 Storage.store(Raw);
0121 return *makePointer(Raw);
0122 }
0123
0124
0125 while (Raw == getBusy())
0126 Raw = Storage.load();
0127 assert(Raw != getNull() && "Expected non-null from competing generator");
0128 return *makePointer(Raw);
0129 }
0130
0131 explicit operator bool() const { return load(); }
0132 operator T *() const { return load(); }
0133
0134 T &operator*() const {
0135 T *P = load();
0136 assert(P && "Unexpected null dereference");
0137 return *P;
0138 }
0139 T *operator->() const { return &operator*(); }
0140
0141 LazyAtomicPointer() : Storage(0) {}
0142 LazyAtomicPointer(std::nullptr_t) : Storage(0) {}
0143 LazyAtomicPointer(T *Value) : Storage(makeRaw(Value)) {}
0144 LazyAtomicPointer(const LazyAtomicPointer &RHS)
0145 : Storage(makeRaw(RHS.load())) {}
0146
0147 LazyAtomicPointer &operator=(std::nullptr_t) {
0148 store(nullptr);
0149 return *this;
0150 }
0151 LazyAtomicPointer &operator=(T *RHS) {
0152 store(RHS);
0153 return *this;
0154 }
0155 LazyAtomicPointer &operator=(const LazyAtomicPointer &RHS) {
0156 store(RHS.load());
0157 return *this;
0158 }
0159
0160 private:
0161 std::atomic<uintptr_t> Storage;
0162 };
0163
0164 }
0165
0166 #endif