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