annotate win32-mingw/include/kj/memory.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +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_