File: bit_struct_detail.h

package info (click to toggle)
android-platform-art 11.0.0%2Br48-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 78,932 kB
  • sloc: cpp: 459,858; java: 163,268; asm: 22,644; python: 9,815; sh: 6,330; ansic: 4,117; xml: 2,855; perl: 77; makefile: 73
file content (163 lines) | stat: -rw-r--r-- 5,929 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_
#define ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_

#include "bit_utils.h"
#include "globals.h"

#include <type_traits>

// Implementation details for bit_struct.h
// Not intended to be used stand-alone.

namespace art {

template <typename T>
static constexpr size_t BitStructSizeOf();

namespace detail {
// Select the smallest uintX_t that will fit kBitSize bits.
template <size_t kBitSize>
struct MinimumTypeUnsignedHelper {
  using type =
    typename std::conditional<kBitSize == 0, void,       // NOLINT [whitespace/operators] [3]
    typename std::conditional<kBitSize <= 8, uint8_t,    // NOLINT [whitespace/operators] [3]
    typename std::conditional<kBitSize <= 16, uint16_t,  // NOLINT [whitespace/operators] [3]
    typename std::conditional<kBitSize <= 32, uint32_t,
    typename std::conditional<kBitSize <= 64, uint64_t,
    typename std::conditional<kBitSize <= BitSizeOf<uintmax_t>(), uintmax_t,
                              void>::type>::type>::type>::type>::type>::type;
};

// Select the smallest [u]intX_t that will fit kBitSize bits.
// Automatically picks intX_t or uintX_t based on the sign-ness of T.
template <typename T, size_t kBitSize>
struct MinimumTypeHelper {
  using type_unsigned = typename MinimumTypeUnsignedHelper<kBitSize>::type;

  using type =
    typename std::conditional</* if */   std::is_signed<T>::value,
                              /* then */ typename std::make_signed<type_unsigned>::type,
                              /* else */ type_unsigned>::type;
};

// Helper for converting to and from T to an integral type.
template <typename T>
union ValueConverter {
  using StorageType = typename MinimumTypeHelper<T, sizeof(T) * kBitsPerByte>::type;

  static constexpr StorageType ToUnderlyingStorage(T value) {
    ValueConverter converter;
    converter.value_.val_ = value;
    return converter.storage_.val_;
  }

  static constexpr T FromUnderlyingStorage(StorageType storage) {
    ValueConverter converter;
    converter.storage_.val_ = storage;
    return converter.value_.val_;
  }

  // Underlying values must be wrapped in separate standard-layout structs.
  // See below for more details.
  struct StorageWrapper {
    StorageType val_;
  };
  struct ValueWrapper {
    T val_;
  };

  // Safely alias storage_ and value_ together.
  //
  // See C++ 9.5.1 [class.union]:
  // If a standard-layout union contains several standard-layout structs that share a common
  // initial sequence ... it is permitted to inspect the common initial sequence of any of
  // standard-layout struct members.
  StorageWrapper storage_;
  ValueWrapper value_;
#if __cplusplus >= 202000L
#error "When upgrading to C++20, remove this error and check that this is OK for all use cases."
  static_assert(std::is_layout_compatible_v<StorageWrapper, ValueWrapper>);
#endif

  // Future work: In theory almost non-standard layout can be supported here,
  // assuming they don't rely on the address of (this).
  // We just have to use memcpy since the union-aliasing would not work.
};

// Denotes the beginning of a bit struct.
//
// This marker is required by the C++ standard in order to
// have a "common initial sequence".
//
// See C++ 9.5.1 [class.union]:
// If a standard-layout union contains several standard-layout structs that share a common
// initial sequence ... it is permitted to inspect the common initial sequence of any of
// standard-layout struct members.
template <size_t kSize>
struct DefineBitStructSize {
 private:
  typename MinimumTypeUnsignedHelper<kSize>::type _;
};

// Check if type "T" has a member called _ in it.
template <typename T>
struct HasUnderscoreField {
 private:
  using TrueT = std::integral_constant<bool, true>::type;
  using FalseT = std::integral_constant<bool, false>::type;

  template <typename C>
  static constexpr auto Test(void*) -> decltype(std::declval<C>()._, TrueT{});

  template <typename>
  static constexpr FalseT Test(...);

 public:
  static constexpr bool value = decltype(Test<T>(nullptr))::value;
};

// Infer the type of the member of &T::M.
template <typename T, typename M>
M GetMemberType(M T:: *);

// Ensure the minimal type storage for 'T' matches its declared BitStructSizeOf.
// Nominally used by the BITSTRUCT_DEFINE_END macro.
template <typename T>
static constexpr bool ValidateBitStructSize() {
  static_assert(std::is_union<T>::value, "T must be union");
  static_assert(std::is_standard_layout<T>::value, "T must be standard-layout");
  static_assert(HasUnderscoreField<T>::value, "T must have the _ DefineBitStructSize");

  const size_t kBitStructSizeOf = BitStructSizeOf<T>();
  static_assert(std::is_same<decltype(GetMemberType(&T::_)),
                             DefineBitStructSize<kBitStructSizeOf>>::value,
                "T::_ must be a DefineBitStructSize of the same size");

  const size_t kExpectedSize = (BitStructSizeOf<T>() < kBitsPerByte)
                                   ? kBitsPerByte
                                   : RoundUpToPowerOfTwo(kBitStructSizeOf);

  // Ensure no extra fields were added in between START/END.
  const size_t kActualSize = sizeof(T) * kBitsPerByte;
  return kExpectedSize == kActualSize;
}
}  // namespace detail
}  // namespace art

#endif  // ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_