hb-null.hh (7992B)
1 /* 2 * Copyright © 2018 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_NULL_HH 28 #define HB_NULL_HH 29 30 #include "hb.hh" 31 #include "hb-meta.hh" 32 33 34 /* 35 * Static pools 36 */ 37 38 /* Global nul-content Null pool. Enlarge as necessary. */ 39 40 #define HB_NULL_POOL_SIZE 640 41 42 template <typename T, typename> 43 struct _hb_has_min_size : hb_false_type {}; 44 template <typename T> 45 struct _hb_has_min_size<T, hb_void_t<decltype (T::min_size)>> 46 : hb_true_type {}; 47 template <typename T> 48 using hb_has_min_size = _hb_has_min_size<T, void>; 49 #define hb_has_min_size(T) hb_has_min_size<T>::value 50 51 template <typename T, typename> 52 struct _hb_has_null_size : hb_false_type {}; 53 template <typename T> 54 struct _hb_has_null_size<T, hb_void_t<decltype (T::null_size)>> 55 : hb_true_type {}; 56 template <typename T> 57 using hb_has_null_size = _hb_has_null_size<T, void>; 58 #define hb_has_null_size(T) hb_has_null_size<T>::value 59 60 /* Use SFINAE to sniff whether T has min_size; in which case return the larger 61 * of sizeof(T) and T::null_size, otherwise return sizeof(T). 62 * 63 * The main purpose of this is to let structs communicate that they are not nullable, 64 * by defining min_size but *not* null_size. */ 65 66 /* The hard way... 67 * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol 68 */ 69 70 template <typename T, typename> 71 struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {}; 72 template <typename T> 73 struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> 74 : hb_integral_constant<unsigned, 75 (sizeof (T) > T::null_size ? sizeof (T) : T::null_size)> {}; 76 template <typename T> 77 using hb_null_size = _hb_null_size<T, void>; 78 #define hb_null_size(T) hb_null_size<T>::value 79 80 /* These doesn't belong here, but since is copy/paste from above, put it here. */ 81 82 /* hb_static_size (T) 83 * Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */ 84 85 template <typename T, typename> 86 struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {}; 87 template <typename T> 88 struct _hb_static_size<T, hb_void_t<decltype (T::static_size)>> : hb_integral_constant<unsigned, T::static_size> {}; 89 template <typename T> 90 using hb_static_size = _hb_static_size<T, void>; 91 #define hb_static_size(T) hb_static_size<T>::value 92 93 template <typename T, typename> 94 struct _hb_min_size : hb_integral_constant<unsigned, sizeof (T)> {}; 95 template <typename T> 96 struct _hb_min_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::min_size> {}; 97 template <typename T> 98 using hb_min_size = _hb_min_size<T, void>; 99 #define hb_min_size(T) hb_min_size<T>::value 100 101 102 /* 103 * Null() 104 */ 105 106 extern HB_INTERNAL 107 uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)]; 108 109 /* Generic nul-content Null objects. */ 110 template <typename Type> 111 struct Null { 112 static Type const & get_null () 113 { 114 static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); 115 return *reinterpret_cast<Type const *> (_hb_NullPool); 116 } 117 }; 118 template <typename QType> 119 struct NullHelper 120 { 121 typedef hb_remove_const<hb_remove_reference<QType>> Type; 122 static const Type & get_null () { return Null<Type>::get_null (); } 123 }; 124 #define Null(Type) NullHelper<Type>::get_null () 125 126 /* Specializations for arbitrary-content Null objects expressed in bytes. */ 127 #define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \ 128 } /* Close namespace. */ \ 129 extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]; \ 130 template <> \ 131 struct Null<Namespace::Type> { \ 132 static Namespace::Type const & get_null () { \ 133 return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \ 134 } \ 135 }; \ 136 namespace Namespace { \ 137 static_assert (true, "") /* Require semicolon after. */ 138 #define DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1(Namespace, Type, Size) \ 139 } /* Close namespace. */ \ 140 extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Size]; \ 141 template <typename Spec> \ 142 struct Null<Namespace::Type<Spec>> { \ 143 static Namespace::Type<Spec> const & get_null () { \ 144 return *reinterpret_cast<const Namespace::Type<Spec> *> (_hb_Null_##Namespace##_##Type); \ 145 } \ 146 }; \ 147 namespace Namespace { \ 148 static_assert (true, "") /* Require semicolon after. */ 149 #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ 150 const unsigned char _hb_Null_##Namespace##_##Type[sizeof (_hb_Null_##Namespace##_##Type)] 151 152 /* Specializations for arbitrary-content Null objects expressed as struct initializer. */ 153 #define DECLARE_NULL_INSTANCE(Type) \ 154 extern HB_INTERNAL const Type _hb_Null_##Type; \ 155 template <> \ 156 struct Null<Type> { \ 157 static Type const & get_null () { \ 158 return _hb_Null_##Type; \ 159 } \ 160 }; \ 161 static_assert (true, "") /* Require semicolon after. */ 162 #define DEFINE_NULL_INSTANCE(Type) \ 163 const Type _hb_Null_##Type 164 165 /* Global writable pool. Enlarge as necessary. */ 166 167 /* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool 168 * for correct operation. It only exist to catch and divert program logic bugs instead of 169 * causing bad memory access. So, races there are not actually introducing incorrectness 170 * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */ 171 extern HB_INTERNAL 172 /*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)]; 173 174 /* CRAP pool: Common Region for Access Protection. */ 175 template <typename Type> 176 static inline Type& Crap () { 177 static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); 178 Type *obj = reinterpret_cast<Type *> (_hb_CrapPool); 179 memcpy (reinterpret_cast<void*>(obj), std::addressof (Null (Type)), sizeof (*obj)); 180 return *obj; 181 } 182 template <typename QType> 183 struct CrapHelper 184 { 185 typedef hb_remove_const<hb_remove_reference<QType>> Type; 186 static Type & get_crap () { return Crap<Type> (); } 187 }; 188 #define Crap(Type) CrapHelper<Type>::get_crap () 189 190 template <typename Type> 191 struct CrapOrNullHelper { 192 static Type & get () { return Crap (Type); } 193 }; 194 template <typename Type> 195 struct CrapOrNullHelper<const Type> { 196 static const Type & get () { return Null (Type); } 197 }; 198 #define CrapOrNull(Type) CrapOrNullHelper<Type>::get () 199 200 201 /* 202 * hb_nonnull_ptr_t 203 */ 204 205 template <typename P> 206 struct hb_nonnull_ptr_t 207 { 208 typedef hb_remove_pointer<P> T; 209 210 hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {} 211 T * operator = (T *v_) { return v = v_; } 212 T * operator -> () const { return get (); } 213 T & operator * () const { return *get (); } 214 T ** operator & () const { return std::addressof (v); } 215 /* Only auto-cast to const types. */ 216 template <typename C> operator const C * () const { return get (); } 217 operator const char * () const { return (const char *) get (); } 218 T * get () const { return v ? v : const_cast<T *> (std::addressof (Null (T))); } 219 T * get_raw () const { return v; } 220 221 private: 222 T *v; 223 }; 224 225 226 #endif /* HB_NULL_HH */