1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_ 18 #define ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_ 19 20 #include "base/bit_utils.h" 21 #include "globals.h" 22 23 #include <type_traits> 24 25 // Implementation details for bit_struct.h 26 // Not intended to be used stand-alone. 27 28 namespace art { 29 30 template <typename T> 31 static constexpr size_t BitStructSizeOf(); 32 33 namespace detail { 34 // Select the smallest uintX_t that will fit kBitSize bits. 35 template <size_t kBitSize> 36 struct MinimumTypeUnsignedHelper { 37 using type = 38 typename std::conditional<kBitSize == 0, void, // NOLINT [whitespace/operators] [3] 39 typename std::conditional<kBitSize <= 8, uint8_t, // NOLINT [whitespace/operators] [3] 40 typename std::conditional<kBitSize <= 16, uint16_t, // NOLINT [whitespace/operators] [3] 41 typename std::conditional<kBitSize <= 32, uint32_t, 42 typename std::conditional<kBitSize <= 64, uint64_t, 43 typename std::conditional<kBitSize <= BitSizeOf<uintmax_t>(), uintmax_t, 44 void>::type>::type>::type>::type>::type>::type; 45 }; 46 47 // Select the smallest [u]intX_t that will fit kBitSize bits. 48 // Automatically picks intX_t or uintX_t based on the sign-ness of T. 49 template <typename T, size_t kBitSize> 50 struct MinimumTypeHelper { 51 using type_unsigned = typename MinimumTypeUnsignedHelper<kBitSize>::type; 52 53 using type = 54 typename std::conditional</* if */ std::is_signed<T>::value, 55 /* then */ typename std::make_signed<type_unsigned>::type, 56 /* else */ type_unsigned>::type; 57 }; 58 59 // Denotes the beginning of a bit struct. 60 // 61 // This marker is required by the C++ standard in order to 62 // have a "common initial sequence". 63 // 64 // See C++ 9.5.1 [class.union]: 65 // If a standard-layout union contains several standard-layout structs that share a common 66 // initial sequence ... it is permitted to inspect the common initial sequence of any of 67 // standard-layout struct members. 68 template <size_t kSize> 69 struct DefineBitStructSize { 70 private: 71 typename MinimumTypeUnsignedHelper<kSize>::type _; 72 }; 73 74 // Check if type "T" has a member called _ in it. 75 template <typename T> 76 struct HasUnderscoreField { 77 private: 78 using TrueT = std::integral_constant<bool, true>::type; 79 using FalseT = std::integral_constant<bool, false>::type; 80 81 template <typename C> 82 static constexpr auto Test(void*) -> decltype(std::declval<C>()._, TrueT{}); 83 84 template <typename> 85 static constexpr FalseT Test(...); 86 87 public: 88 static constexpr bool value = decltype(Test<T>(0))::value; 89 }; 90 91 // Infer the type of the member of &T::M. 92 template <typename T, typename M> 93 M GetMemberType(M T:: *); 94 95 // Ensure the minimal type storage for 'T' matches its declared BitStructSizeOf. 96 // Nominally used by the BITSTRUCT_DEFINE_END macro. 97 template <typename T> 98 static constexpr bool ValidateBitStructSize() { 99 static_assert(std::is_union<T>::value, "T must be union"); 100 static_assert(std::is_standard_layout<T>::value, "T must be standard-layout"); 101 static_assert(HasUnderscoreField<T>::value, "T must have the _ DefineBitStructSize"); 102 103 const size_t kBitStructSizeOf = BitStructSizeOf<T>(); 104 static_assert(std::is_same<decltype(GetMemberType(&T::_)), 105 DefineBitStructSize<kBitStructSizeOf>>::value, 106 "T::_ must be a DefineBitStructSize of the same size"); 107 108 const size_t kExpectedSize = (BitStructSizeOf<T>() < kBitsPerByte) 109 ? kBitsPerByte 110 : RoundUpToPowerOfTwo(kBitStructSizeOf); 111 112 // Ensure no extra fields were added in between START/END. 113 const size_t kActualSize = sizeof(T) * kBitsPerByte; 114 return kExpectedSize == kActualSize; 115 } 116 } // namespace detail 117 } // namespace art 118 119 #endif // ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_ 120