annotate win32-mingw/include/kj/memory.h @ 75:8f7fd4420df7

Add some cross-platform Boost headers
author Chris Cannam
date Sat, 16 Feb 2019 16:31:25 +0000
parents eccd51b72864
children
rev   line source
Chris@64 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
Chris@64 2 // Licensed under the MIT License:
Chris@64 3 //
Chris@64 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
Chris@64 5 // of this software and associated documentation files (the "Software"), to deal
Chris@64 6 // in the Software without restriction, including without limitation the rights
Chris@64 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Chris@64 8 // copies of the Software, and to permit persons to whom the Software is
Chris@64 9 // furnished to do so, subject to the following conditions:
Chris@64 10 //
Chris@64 11 // The above copyright notice and this permission notice shall be included in
Chris@64 12 // all copies or substantial portions of the Software.
Chris@64 13 //
Chris@64 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Chris@64 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Chris@64 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Chris@64 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Chris@64 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Chris@64 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Chris@64 20 // THE SOFTWARE.
Chris@64 21
Chris@64 22 #ifndef KJ_MEMORY_H_
Chris@64 23 #define KJ_MEMORY_H_
Chris@64 24
Chris@64 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
Chris@64 26 #pragma GCC system_header
Chris@64 27 #endif
Chris@64 28
Chris@64 29 #include "common.h"
Chris@64 30
Chris@64 31 namespace kj {
Chris@64 32
Chris@64 33 // =======================================================================================
Chris@64 34 // Disposer -- Implementation details.
Chris@64 35
Chris@64 36 class Disposer {
Chris@64 37 // Abstract interface for a thing that "disposes" of objects, where "disposing" usually means
Chris@64 38 // calling the destructor followed by freeing the underlying memory. `Own<T>` encapsulates an
Chris@64 39 // object pointer with corresponding Disposer.
Chris@64 40 //
Chris@64 41 // Few developers will ever touch this interface. It is primarily useful for those implementing
Chris@64 42 // custom memory allocators.
Chris@64 43
Chris@64 44 protected:
Chris@64 45 // Do not declare a destructor, as doing so will force a global initializer for each HeapDisposer
Chris@64 46 // instance. Eww!
Chris@64 47
Chris@64 48 virtual void disposeImpl(void* pointer) const = 0;
Chris@64 49 // Disposes of the object, given a pointer to the beginning of the object. If the object is
Chris@64 50 // polymorphic, this pointer is determined by dynamic_cast<void*>(). For non-polymorphic types,
Chris@64 51 // Own<T> does not allow any casting, so the pointer exactly matches the original one given to
Chris@64 52 // Own<T>.
Chris@64 53
Chris@64 54 public:
Chris@64 55
Chris@64 56 template <typename T>
Chris@64 57 void dispose(T* object) const;
Chris@64 58 // Helper wrapper around disposeImpl().
Chris@64 59 //
Chris@64 60 // If T is polymorphic, calls `disposeImpl(dynamic_cast<void*>(object))`, otherwise calls
Chris@64 61 // `disposeImpl(implicitCast<void*>(object))`.
Chris@64 62 //
Chris@64 63 // Callers must not call dispose() on the same pointer twice, even if the first call throws
Chris@64 64 // an exception.
Chris@64 65
Chris@64 66 private:
Chris@64 67 template <typename T, bool polymorphic = __is_polymorphic(T)>
Chris@64 68 struct Dispose_;
Chris@64 69 };
Chris@64 70
Chris@64 71 template <typename T>
Chris@64 72 class DestructorOnlyDisposer: public Disposer {
Chris@64 73 // A disposer that merely calls the type's destructor and nothing else.
Chris@64 74
Chris@64 75 public:
Chris@64 76 static const DestructorOnlyDisposer instance;
Chris@64 77
Chris@64 78 void disposeImpl(void* pointer) const override {
Chris@64 79 reinterpret_cast<T*>(pointer)->~T();
Chris@64 80 }
Chris@64 81 };
Chris@64 82
Chris@64 83 template <typename T>
Chris@64 84 const DestructorOnlyDisposer<T> DestructorOnlyDisposer<T>::instance = DestructorOnlyDisposer<T>();
Chris@64 85
Chris@64 86 class NullDisposer: public Disposer {
Chris@64 87 // A disposer that does nothing.
Chris@64 88
Chris@64 89 public:
Chris@64 90 static const NullDisposer instance;
Chris@64 91
Chris@64 92 void disposeImpl(void* pointer) const override {}
Chris@64 93 };
Chris@64 94
Chris@64 95 // =======================================================================================
Chris@64 96 // Own<T> -- An owned pointer.
Chris@64 97
Chris@64 98 template <typename T>
Chris@64 99 class Own {
Chris@64 100 // A transferrable title to a T. When an Own<T> goes out of scope, the object's Disposer is
Chris@64 101 // called to dispose of it. An Own<T> can be efficiently passed by move, without relocating the
Chris@64 102 // underlying object; this transfers ownership.
Chris@64 103 //
Chris@64 104 // This is much like std::unique_ptr, except:
Chris@64 105 // - You cannot release(). An owned object is not necessarily allocated with new (see next
Chris@64 106 // point), so it would be hard to use release() correctly.
Chris@64 107 // - The deleter is made polymorphic by virtual call rather than by template. This is much
Chris@64 108 // more powerful -- it allows the use of custom allocators, freelists, etc. This could
Chris@64 109 // _almost_ be accomplished with unique_ptr by forcing everyone to use something like
Chris@64 110 // std::unique_ptr<T, kj::Deleter>, except that things get hairy in the presence of multiple
Chris@64 111 // inheritance and upcasting, and anyway if you force everyone to use a custom deleter
Chris@64 112 // then you've lost any benefit to interoperating with the "standard" unique_ptr.
Chris@64 113
Chris@64 114 public:
Chris@64 115 KJ_DISALLOW_COPY(Own);
Chris@64 116 inline Own(): disposer(nullptr), ptr(nullptr) {}
Chris@64 117 inline Own(Own&& other) noexcept
Chris@64 118 : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
Chris@64 119 inline Own(Own<RemoveConstOrDisable<T>>&& other) noexcept
Chris@64 120 : disposer(other.disposer), ptr(other.ptr) { other.ptr = nullptr; }
Chris@64 121 template <typename U, typename = EnableIf<canConvert<U*, T*>()>>
Chris@64 122 inline Own(Own<U>&& other) noexcept
Chris@64 123 : disposer(other.disposer), ptr(other.ptr) {
Chris@64 124 static_assert(__is_polymorphic(T),
Chris@64 125 "Casting owned pointers requires that the target type is polymorphic.");
Chris@64 126 other.ptr = nullptr;
Chris@64 127 }
Chris@64 128 inline Own(T* ptr, const Disposer& disposer) noexcept: disposer(&disposer), ptr(ptr) {}
Chris@64 129
Chris@64 130 ~Own() noexcept(false) { dispose(); }
Chris@64 131
Chris@64 132 inline Own& operator=(Own&& other) {
Chris@64 133 // Move-assingnment operator.
Chris@64 134
Chris@64 135 // Careful, this might own `other`. Therefore we have to transfer the pointers first, then
Chris@64 136 // dispose.
Chris@64 137 const Disposer* disposerCopy = disposer;
Chris@64 138 T* ptrCopy = ptr;
Chris@64 139 disposer = other.disposer;
Chris@64 140 ptr = other.ptr;
Chris@64 141 other.ptr = nullptr;
Chris@64 142 if (ptrCopy != nullptr) {
Chris@64 143 disposerCopy->dispose(const_cast<RemoveConst<T>*>(ptrCopy));
Chris@64 144 }
Chris@64 145 return *this;
Chris@64 146 }
Chris@64 147
Chris@64 148 inline Own& operator=(decltype(nullptr)) {
Chris@64 149 dispose();
Chris@64 150 return *this;
Chris@64 151 }
Chris@64 152
Chris@64 153 template <typename U>
Chris@64 154 Own<U> downcast() {
Chris@64 155 // Downcast the pointer to Own<U>, destroying the original pointer. If this pointer does not
Chris@64 156 // actually point at an instance of U, the results are undefined (throws an exception in debug
Chris@64 157 // mode if RTTI is enabled, otherwise you're on your own).
Chris@64 158
Chris@64 159 Own<U> result;
Chris@64 160 if (ptr != nullptr) {
Chris@64 161 result.ptr = &kj::downcast<U>(*ptr);
Chris@64 162 result.disposer = disposer;
Chris@64 163 ptr = nullptr;
Chris@64 164 }
Chris@64 165 return result;
Chris@64 166 }
Chris@64 167
Chris@64 168 #define NULLCHECK KJ_IREQUIRE(ptr != nullptr, "null Own<> dereference")
Chris@64 169 inline T* operator->() { NULLCHECK; return ptr; }
Chris@64 170 inline const T* operator->() const { NULLCHECK; return ptr; }
Chris@64 171 inline T& operator*() { NULLCHECK; return *ptr; }
Chris@64 172 inline const T& operator*() const { NULLCHECK; return *ptr; }
Chris@64 173 #undef NULLCHECK
Chris@64 174 inline T* get() { return ptr; }
Chris@64 175 inline const T* get() const { return ptr; }
Chris@64 176 inline operator T*() { return ptr; }
Chris@64 177 inline operator const T*() const { return ptr; }
Chris@64 178
Chris@64 179 private:
Chris@64 180 const Disposer* disposer; // Only valid if ptr != nullptr.
Chris@64 181 T* ptr;
Chris@64 182
Chris@64 183 inline explicit Own(decltype(nullptr)): disposer(nullptr), ptr(nullptr) {}
Chris@64 184
Chris@64 185 inline bool operator==(decltype(nullptr)) { return ptr == nullptr; }
Chris@64 186 inline bool operator!=(decltype(nullptr)) { return ptr != nullptr; }
Chris@64 187 // Only called by Maybe<Own<T>>.
Chris@64 188
Chris@64 189 inline void dispose() {
Chris@64 190 // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
Chris@64 191 // dispose again.
Chris@64 192 T* ptrCopy = ptr;
Chris@64 193 if (ptrCopy != nullptr) {
Chris@64 194 ptr = nullptr;
Chris@64 195 disposer->dispose(const_cast<RemoveConst<T>*>(ptrCopy));
Chris@64 196 }
Chris@64 197 }
Chris@64 198
Chris@64 199 template <typename U>
Chris@64 200 friend class Own;
Chris@64 201 friend class Maybe<Own<T>>;
Chris@64 202 };
Chris@64 203
Chris@64 204 namespace _ { // private
Chris@64 205
Chris@64 206 template <typename T>
Chris@64 207 class OwnOwn {
Chris@64 208 public:
Chris@64 209 inline OwnOwn(Own<T>&& value) noexcept: value(kj::mv(value)) {}
Chris@64 210
Chris@64 211 inline Own<T>& operator*() & { return value; }
Chris@64 212 inline const Own<T>& operator*() const & { return value; }
Chris@64 213 inline Own<T>&& operator*() && { return kj::mv(value); }
Chris@64 214 inline const Own<T>&& operator*() const && { return kj::mv(value); }
Chris@64 215 inline Own<T>* operator->() { return &value; }
Chris@64 216 inline const Own<T>* operator->() const { return &value; }
Chris@64 217 inline operator Own<T>*() { return value ? &value : nullptr; }
Chris@64 218 inline operator const Own<T>*() const { return value ? &value : nullptr; }
Chris@64 219
Chris@64 220 private:
Chris@64 221 Own<T> value;
Chris@64 222 };
Chris@64 223
Chris@64 224 template <typename T>
Chris@64 225 OwnOwn<T> readMaybe(Maybe<Own<T>>&& maybe) { return OwnOwn<T>(kj::mv(maybe.ptr)); }
Chris@64 226 template <typename T>
Chris@64 227 Own<T>* readMaybe(Maybe<Own<T>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; }
Chris@64 228 template <typename T>
Chris@64 229 const Own<T>* readMaybe(const Maybe<Own<T>>& maybe) { return maybe.ptr ? &maybe.ptr : nullptr; }
Chris@64 230
Chris@64 231 } // namespace _ (private)
Chris@64 232
Chris@64 233 template <typename T>
Chris@64 234 class Maybe<Own<T>> {
Chris@64 235 public:
Chris@64 236 inline Maybe(): ptr(nullptr) {}
Chris@64 237 inline Maybe(Own<T>&& t) noexcept: ptr(kj::mv(t)) {}
Chris@64 238 inline Maybe(Maybe&& other) noexcept: ptr(kj::mv(other.ptr)) {}
Chris@64 239
Chris@64 240 template <typename U>
Chris@64 241 inline Maybe(Maybe<Own<U>>&& other): ptr(mv(other.ptr)) {}
Chris@64 242 template <typename U>
Chris@64 243 inline Maybe(Own<U>&& other): ptr(mv(other)) {}
Chris@64 244
Chris@64 245 inline Maybe(decltype(nullptr)) noexcept: ptr(nullptr) {}
Chris@64 246
Chris@64 247 inline operator Maybe<T&>() { return ptr.get(); }
Chris@64 248 inline operator Maybe<const T&>() const { return ptr.get(); }
Chris@64 249
Chris@64 250 inline Maybe& operator=(Maybe&& other) { ptr = kj::mv(other.ptr); return *this; }
Chris@64 251
Chris@64 252 inline bool operator==(decltype(nullptr)) const { return ptr == nullptr; }
Chris@64 253 inline bool operator!=(decltype(nullptr)) const { return ptr != nullptr; }
Chris@64 254
Chris@64 255 Own<T>& orDefault(Own<T>& defaultValue) {
Chris@64 256 if (ptr == nullptr) {
Chris@64 257 return defaultValue;
Chris@64 258 } else {
Chris@64 259 return ptr;
Chris@64 260 }
Chris@64 261 }
Chris@64 262 const Own<T>& orDefault(const Own<T>& defaultValue) const {
Chris@64 263 if (ptr == nullptr) {
Chris@64 264 return defaultValue;
Chris@64 265 } else {
Chris@64 266 return ptr;
Chris@64 267 }
Chris@64 268 }
Chris@64 269
Chris@64 270 template <typename Func>
Chris@64 271 auto map(Func&& f) & -> Maybe<decltype(f(instance<Own<T>&>()))> {
Chris@64 272 if (ptr == nullptr) {
Chris@64 273 return nullptr;
Chris@64 274 } else {
Chris@64 275 return f(ptr);
Chris@64 276 }
Chris@64 277 }
Chris@64 278
Chris@64 279 template <typename Func>
Chris@64 280 auto map(Func&& f) const & -> Maybe<decltype(f(instance<const Own<T>&>()))> {
Chris@64 281 if (ptr == nullptr) {
Chris@64 282 return nullptr;
Chris@64 283 } else {
Chris@64 284 return f(ptr);
Chris@64 285 }
Chris@64 286 }
Chris@64 287
Chris@64 288 template <typename Func>
Chris@64 289 auto map(Func&& f) && -> Maybe<decltype(f(instance<Own<T>&&>()))> {
Chris@64 290 if (ptr == nullptr) {
Chris@64 291 return nullptr;
Chris@64 292 } else {
Chris@64 293 return f(kj::mv(ptr));
Chris@64 294 }
Chris@64 295 }
Chris@64 296
Chris@64 297 template <typename Func>
Chris@64 298 auto map(Func&& f) const && -> Maybe<decltype(f(instance<const Own<T>&&>()))> {
Chris@64 299 if (ptr == nullptr) {
Chris@64 300 return nullptr;
Chris@64 301 } else {
Chris@64 302 return f(kj::mv(ptr));
Chris@64 303 }
Chris@64 304 }
Chris@64 305
Chris@64 306 private:
Chris@64 307 Own<T> ptr;
Chris@64 308
Chris@64 309 template <typename U>
Chris@64 310 friend class Maybe;
Chris@64 311 template <typename U>
Chris@64 312 friend _::OwnOwn<U> _::readMaybe(Maybe<Own<U>>&& maybe);
Chris@64 313 template <typename U>
Chris@64 314 friend Own<U>* _::readMaybe(Maybe<Own<U>>& maybe);
Chris@64 315 template <typename U>
Chris@64 316 friend const Own<U>* _::readMaybe(const Maybe<Own<U>>& maybe);
Chris@64 317 };
Chris@64 318
Chris@64 319 namespace _ { // private
Chris@64 320
Chris@64 321 template <typename T>
Chris@64 322 class HeapDisposer final: public Disposer {
Chris@64 323 public:
Chris@64 324 virtual void disposeImpl(void* pointer) const override { delete reinterpret_cast<T*>(pointer); }
Chris@64 325
Chris@64 326 static const HeapDisposer instance;
Chris@64 327 };
Chris@64 328
Chris@64 329 template <typename T>
Chris@64 330 const HeapDisposer<T> HeapDisposer<T>::instance = HeapDisposer<T>();
Chris@64 331
Chris@64 332 } // namespace _ (private)
Chris@64 333
Chris@64 334 template <typename T, typename... Params>
Chris@64 335 Own<T> heap(Params&&... params) {
Chris@64 336 // heap<T>(...) allocates a T on the heap, forwarding the parameters to its constructor. The
Chris@64 337 // exact heap implementation is unspecified -- for now it is operator new, but you should not
Chris@64 338 // assume this. (Since we know the object size at delete time, we could actually implement an
Chris@64 339 // allocator that is more efficient than operator new.)
Chris@64 340
Chris@64 341 return Own<T>(new T(kj::fwd<Params>(params)...), _::HeapDisposer<T>::instance);
Chris@64 342 }
Chris@64 343
Chris@64 344 template <typename T>
Chris@64 345 Own<Decay<T>> heap(T&& orig) {
Chris@64 346 // Allocate a copy (or move) of the argument on the heap.
Chris@64 347 //
Chris@64 348 // The purpose of this overload is to allow you to omit the template parameter as there is only
Chris@64 349 // one argument and the purpose is to copy it.
Chris@64 350
Chris@64 351 typedef Decay<T> T2;
Chris@64 352 return Own<T2>(new T2(kj::fwd<T>(orig)), _::HeapDisposer<T2>::instance);
Chris@64 353 }
Chris@64 354
Chris@64 355 // =======================================================================================
Chris@64 356 // SpaceFor<T> -- assists in manual allocation
Chris@64 357
Chris@64 358 template <typename T>
Chris@64 359 class SpaceFor {
Chris@64 360 // A class which has the same size and alignment as T but does not call its constructor or
Chris@64 361 // destructor automatically. Instead, call construct() to construct a T in the space, which
Chris@64 362 // returns an Own<T> which will take care of calling T's destructor later.
Chris@64 363
Chris@64 364 public:
Chris@64 365 inline SpaceFor() {}
Chris@64 366 inline ~SpaceFor() {}
Chris@64 367
Chris@64 368 template <typename... Params>
Chris@64 369 Own<T> construct(Params&&... params) {
Chris@64 370 ctor(value, kj::fwd<Params>(params)...);
Chris@64 371 return Own<T>(&value, DestructorOnlyDisposer<T>::instance);
Chris@64 372 }
Chris@64 373
Chris@64 374 private:
Chris@64 375 union {
Chris@64 376 T value;
Chris@64 377 };
Chris@64 378 };
Chris@64 379
Chris@64 380 // =======================================================================================
Chris@64 381 // Inline implementation details
Chris@64 382
Chris@64 383 template <typename T>
Chris@64 384 struct Disposer::Dispose_<T, true> {
Chris@64 385 static void dispose(T* object, const Disposer& disposer) {
Chris@64 386 // Note that dynamic_cast<void*> does not require RTTI to be enabled, because the offset to
Chris@64 387 // the top of the object is in the vtable -- as it obviously needs to be to correctly implement
Chris@64 388 // operator delete.
Chris@64 389 disposer.disposeImpl(dynamic_cast<void*>(object));
Chris@64 390 }
Chris@64 391 };
Chris@64 392 template <typename T>
Chris@64 393 struct Disposer::Dispose_<T, false> {
Chris@64 394 static void dispose(T* object, const Disposer& disposer) {
Chris@64 395 disposer.disposeImpl(static_cast<void*>(object));
Chris@64 396 }
Chris@64 397 };
Chris@64 398
Chris@64 399 template <typename T>
Chris@64 400 void Disposer::dispose(T* object) const {
Chris@64 401 Dispose_<T>::dispose(object, *this);
Chris@64 402 }
Chris@64 403
Chris@64 404 } // namespace kj
Chris@64 405
Chris@64 406 #endif // KJ_MEMORY_H_