1 #pragma once 2 3 #include "common/platform.h" 4 5 #include "master/hstring.h" 6 7 namespace hstorage { 8 /*! \brief Class representing type of String storage 9 * 10 * This class is used as a container for global String storage options. 11 */ 12 13 class Handle; 14 15 class Storage { 16 template <int N> 17 struct static_wrapper { 18 static ::std::unique_ptr<Storage> instance_; 19 }; 20 public: ~Storage()21 virtual ~Storage() { 22 } 23 instance()24 static Storage &instance() { 25 return *static_wrapper<0>::instance_; 26 } 27 reset()28 static void reset() { 29 static_wrapper<0>::instance_.reset(); 30 } 31 reset(Storage * storage)32 static void reset(Storage *storage) { 33 static_wrapper<0>::instance_.reset(storage); 34 } 35 36 /*! 37 * \brief Compares handle and string 38 * 39 * Expected behaviour: like operator== 40 * As a dominant operation, it should be efficient (e.g. hash comparison). 41 * Passed handle is required to be bound to a valid string. 42 */ 43 virtual bool compare(const Handle &handle, const HString &str) = 0; 44 45 /*! 46 * \brief Extracts standard string from handle 47 */ 48 virtual ::std::string get(const Handle &handle) = 0; 49 50 /*! 51 * \brief Creates a deep copy of handle 52 * 53 * Passed handle is required to be bound to a valid string. 54 */ 55 virtual void copy(Handle &handle, const Handle &other) = 0; 56 57 /*! 58 * \brief Binds hstring to handle 59 * 60 * Passed handle is required to be unbound. 61 */ 62 virtual void bind(Handle &handle, const HString &str) = 0; 63 64 /*! 65 * \brief Unbinds hstring from handle 66 * 67 * Passed handle is required to be bound to a valid string. 68 */ 69 virtual void unbind(Handle &handle) = 0; 70 virtual ::std::string name() const = 0; 71 72 private: 73 static ::std::unique_ptr<Storage> instance_; 74 }; 75 76 template<int N> 77 ::std::unique_ptr<Storage> Storage::static_wrapper<N>::instance_; 78 79 80 /*! \brief Class representing handle to String 81 * 82 * This class represents a generic handle for String kept in storage. 83 * Data kept inside a handle should be interpreted by storage implementations. 84 */ 85 class Handle { 86 public: 87 typedef uint64_t ValueType; 88 typedef uint16_t HashType; 89 90 constexpr static ValueType kHashShift = 8 * (sizeof(ValueType) - sizeof(HashType)); 91 constexpr static ValueType kMask = ((static_cast<ValueType>(1) << kHashShift) - static_cast<ValueType>(1)); 92 Handle()93 Handle() : data_() { 94 } 95 Handle(ValueType data)96 explicit Handle(ValueType data) noexcept : data_(data) { 97 } 98 Handle(const Handle & handle)99 Handle(const Handle &handle) : data_() { 100 if (handle.data_) { 101 Storage::instance().copy(*this, handle); 102 } 103 } 104 Handle(Handle && handle)105 Handle(Handle &&handle) noexcept : data_(handle.data_) { 106 handle.data_ = 0; 107 } 108 Handle(const HString & str)109 explicit Handle(const HString &str) : data_() { 110 Storage::instance().bind(*this, str); 111 } 112 Handle(const::std::string & str)113 explicit Handle(const ::std::string &str) : data_() { 114 Storage::instance().bind(*this, HString(str)); 115 } 116 ~Handle()117 ~Handle() { 118 if (data_) { 119 Storage::instance().unbind(*this); 120 } 121 } 122 123 Handle &operator=(const Handle &handle) { 124 if (handle.data_) { 125 if (data_) { 126 Storage::instance().unbind(*this); 127 data_ = 0; 128 } 129 Storage::instance().copy(*this, handle); 130 } else if (data_) { 131 Storage::instance().unbind(*this); 132 data_ = 0; 133 } 134 return *this; 135 } 136 137 Handle &operator=(Handle &&handle) noexcept { 138 data_ = handle.data_; 139 handle.data_ = 0; 140 return *this; 141 } 142 143 Handle &operator=(const HString &str) { 144 set(str); 145 return *this; 146 } 147 string()148 explicit operator ::std::string() const { 149 if (data_) { 150 return Storage::instance().get(*this); 151 } 152 return ::std::string(); 153 } 154 HString()155 explicit operator HString() const { 156 return get(); 157 } 158 empty()159 bool empty() const { 160 return data_ == 0; 161 } 162 get()163 HString get() const { 164 if (data_) { 165 return HString{Storage::instance().get(*this)}; 166 } 167 return HString(); 168 } 169 set(const HString & str)170 Handle &set(const HString &str) { 171 if (data_) { 172 Storage::instance().unbind(*this); 173 data_ = 0; 174 } 175 Storage::instance().bind(*this, str); 176 return *this; 177 } 178 data()179 ValueType &data() { 180 return data_; 181 } 182 data()183 const ValueType &data() const { 184 return data_; 185 } 186 unlink()187 void unlink() { 188 data_ = 0; 189 } 190 191 /*! 192 * \brief Extracts hash from handle 193 * 194 * This function expects hash to be encoded on first 16 bits 195 * of data_ field. 196 */ hash()197 HashType hash() const { 198 return data_ >> kHashShift; 199 } 200 201 protected: 202 ValueType data_; 203 }; 204 205 /* Operators using fast hash comparison */ 206 inline bool operator==(const Handle &handle, const HString &str) { 207 if (handle.empty()) { 208 return false; 209 } 210 return Storage::instance().compare(handle, str); 211 } 212 213 inline bool operator==(const HString &str, const Handle &handle) { 214 if (handle.empty()) { 215 return false; 216 } 217 return Storage::instance().compare(handle, str); 218 } 219 220 inline bool operator!=(const Handle &handle, const HString &str) { 221 if (handle.empty()) { 222 return true; 223 } 224 return !Storage::instance().compare(handle, str); 225 } 226 227 inline bool operator!=(const HString &str, const Handle &handle) { 228 if (handle.empty()) { 229 return true; 230 } 231 return !Storage::instance().compare(handle, str); 232 } 233 234 /* Operators using deep comparison */ 235 inline bool operator<(const Handle &handle, const HString &str) { 236 return static_cast< ::std::string>(handle) < str; 237 } 238 239 inline bool operator<(const HString &str, const Handle &handle) { 240 return static_cast< ::std::string>(handle) > str; 241 } 242 243 inline bool operator<=(const Handle &handle, const HString &str) { 244 return static_cast< ::std::string>(handle) <= str; 245 } 246 247 inline bool operator<=(const HString &str, const Handle &handle) { 248 return static_cast< ::std::string>(handle) >= str; 249 } 250 251 inline bool operator>(const Handle &handle, const HString &str) { 252 return static_cast< ::std::string>(handle) > str; 253 } 254 255 inline bool operator>(const HString &str, const Handle &handle) { 256 return static_cast< ::std::string>(handle) < str; 257 } 258 259 inline bool operator>=(const Handle &handle, const HString &str) { 260 return static_cast< ::std::string>(handle) >= str; 261 } 262 263 inline bool operator>=(const HString &str, const Handle &handle) { 264 return static_cast< ::std::string>(handle) <= str; 265 } 266 267 } // hstorage 268