1 /* 2 * Copyright (C) 2013-2017 Max Kellermann <max.kellermann@gmail.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 27 * OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #ifndef MANUAL_HXX 31 #define MANUAL_HXX 32 33 #include <cassert> 34 #include <new> 35 #include <utility> 36 37 #if defined(__GNUC__) || defined(__clang__) 38 #pragma GCC diagnostic push 39 #pragma GCC diagnostic ignored "-Wstrict-aliasing" 40 #endif 41 42 /** 43 * Container for an object that gets constructed and destructed 44 * manually. The object is constructed in-place, and therefore 45 * without allocation overhead. It can be constructed and destructed 46 * repeatedly. 47 */ 48 template<class T> 49 class Manual { 50 alignas(T) 51 char data[sizeof(T)]; 52 53 #ifndef NDEBUG 54 bool initialized = false; 55 #endif 56 57 public: 58 #ifndef NDEBUG ~Manual()59 ~Manual() { 60 assert(!initialized); 61 } 62 #endif 63 64 /** 65 * Cast a value reference to the containing Manual instance. 66 */ Cast(T & value)67 static constexpr Manual<T> &Cast(T &value) { 68 return reinterpret_cast<Manual<T> &>(value); 69 } 70 71 template<typename... Args> Construct(Args &&...args)72 void Construct(Args&&... args) { 73 assert(!initialized); 74 75 void *p = data; 76 new(p) T(std::forward<Args>(args)...); 77 78 #ifndef NDEBUG 79 initialized = true; 80 #endif 81 } 82 Destruct()83 void Destruct() { 84 assert(initialized); 85 86 T &t = Get(); 87 t.T::~T(); 88 89 #ifndef NDEBUG 90 initialized = false; 91 #endif 92 } 93 Get()94 T &Get() { 95 assert(initialized); 96 97 void *p = static_cast<void *>(data); 98 return *static_cast<T *>(p); 99 } 100 Get() const101 const T &Get() const { 102 assert(initialized); 103 104 const void *p = static_cast<const void *>(data); 105 return *static_cast<const T *>(p); 106 } 107 operator T&()108 operator T &() { 109 return Get(); 110 } 111 operator const T&() const112 operator const T &() const { 113 return Get(); 114 } 115 operator ->()116 T *operator->() { 117 return &Get(); 118 } 119 operator ->() const120 const T *operator->() const { 121 return &Get(); 122 } 123 }; 124 125 #if defined(__GNUC__) || defined(__clang__) 126 #pragma GCC diagnostic pop 127 #endif 128 129 #endif 130