File indexing completed on 2025-01-18 09:27:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
0016 #define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
0017
0018 #include <cassert>
0019 #include <cstddef>
0020 #include <cstring>
0021 #include <memory>
0022 #include <new>
0023 #include <tuple>
0024 #include <type_traits>
0025 #include <utility>
0026
0027 #include "absl/base/config.h"
0028 #include "absl/memory/memory.h"
0029 #include "absl/meta/type_traits.h"
0030 #include "absl/utility/utility.h"
0031
0032 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0033 #include <sanitizer/asan_interface.h>
0034 #endif
0035
0036 #ifdef ABSL_HAVE_MEMORY_SANITIZER
0037 #include <sanitizer/msan_interface.h>
0038 #endif
0039
0040 namespace absl {
0041 ABSL_NAMESPACE_BEGIN
0042 namespace container_internal {
0043
0044 template <size_t Alignment>
0045 struct alignas(Alignment) AlignedType {};
0046
0047
0048
0049
0050
0051
0052
0053
0054 template <size_t Alignment, class Alloc>
0055 void* Allocate(Alloc* alloc, size_t n) {
0056 static_assert(Alignment > 0, "");
0057 assert(n && "n must be positive");
0058 using M = AlignedType<Alignment>;
0059 using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
0060 using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
0061
0062
0063
0064 A my_mem_alloc(*alloc);
0065 void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
0066 assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
0067 "allocator does not respect alignment");
0068 return p;
0069 }
0070
0071
0072
0073 template <class Allocator, class ValueType>
0074 constexpr auto IsDestructionTrivial() {
0075 constexpr bool result =
0076 std::is_trivially_destructible<ValueType>::value &&
0077 std::is_same<typename absl::allocator_traits<
0078 Allocator>::template rebind_alloc<char>,
0079 std::allocator<char>>::value;
0080 return std::integral_constant<bool, result>();
0081 }
0082
0083
0084
0085 template <size_t Alignment, class Alloc>
0086 void Deallocate(Alloc* alloc, void* p, size_t n) {
0087 static_assert(Alignment > 0, "");
0088 assert(n && "n must be positive");
0089 using M = AlignedType<Alignment>;
0090 using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
0091 using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
0092
0093
0094
0095 A my_mem_alloc(*alloc);
0096 AT::deallocate(my_mem_alloc, static_cast<M*>(p),
0097 (n + sizeof(M) - 1) / sizeof(M));
0098 }
0099
0100 namespace memory_internal {
0101
0102
0103
0104 template <class Alloc, class T, class Tuple, size_t... I>
0105 void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t,
0106 absl::index_sequence<I...>) {
0107 absl::allocator_traits<Alloc>::construct(
0108 *alloc, ptr, std::get<I>(std::forward<Tuple>(t))...);
0109 }
0110
0111 template <class T, class F>
0112 struct WithConstructedImplF {
0113 template <class... Args>
0114 decltype(std::declval<F>()(std::declval<T>())) operator()(
0115 Args&&... args) const {
0116 return std::forward<F>(f)(T(std::forward<Args>(args)...));
0117 }
0118 F&& f;
0119 };
0120
0121 template <class T, class Tuple, size_t... Is, class F>
0122 decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
0123 Tuple&& t, absl::index_sequence<Is...>, F&& f) {
0124 return WithConstructedImplF<T, F>{std::forward<F>(f)}(
0125 std::get<Is>(std::forward<Tuple>(t))...);
0126 }
0127
0128 template <class T, size_t... Is>
0129 auto TupleRefImpl(T&& t, absl::index_sequence<Is...>)
0130 -> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
0131 return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
0132 }
0133
0134
0135
0136 template <class T>
0137 auto TupleRef(T&& t) -> decltype(TupleRefImpl(
0138 std::forward<T>(t),
0139 absl::make_index_sequence<
0140 std::tuple_size<typename std::decay<T>::type>::value>())) {
0141 return TupleRefImpl(
0142 std::forward<T>(t),
0143 absl::make_index_sequence<
0144 std::tuple_size<typename std::decay<T>::type>::value>());
0145 }
0146
0147 template <class F, class K, class V>
0148 decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct,
0149 std::declval<std::tuple<K>>(), std::declval<V>()))
0150 DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) {
0151 const auto& key = std::get<0>(p.first);
0152 return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
0153 std::move(p.second));
0154 }
0155
0156 }
0157
0158
0159
0160 template <class Alloc, class T, class Tuple>
0161 void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) {
0162 memory_internal::ConstructFromTupleImpl(
0163 alloc, ptr, std::forward<Tuple>(t),
0164 absl::make_index_sequence<
0165 std::tuple_size<typename std::decay<Tuple>::type>::value>());
0166 }
0167
0168
0169
0170 template <class T, class Tuple, class F>
0171 decltype(std::declval<F>()(std::declval<T>())) WithConstructed(Tuple&& t,
0172 F&& f) {
0173 return memory_internal::WithConstructedImpl<T>(
0174 std::forward<Tuple>(t),
0175 absl::make_index_sequence<
0176 std::tuple_size<typename std::decay<Tuple>::type>::value>(),
0177 std::forward<F>(f));
0178 }
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 inline std::pair<std::tuple<>, std::tuple<>> PairArgs() { return {}; }
0192 template <class F, class S>
0193 std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s) {
0194 return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)),
0195 std::forward_as_tuple(std::forward<S>(s))};
0196 }
0197 template <class F, class S>
0198 std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs(
0199 const std::pair<F, S>& p) {
0200 return PairArgs(p.first, p.second);
0201 }
0202 template <class F, class S>
0203 std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p) {
0204 return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second));
0205 }
0206 template <class F, class S>
0207 auto PairArgs(std::piecewise_construct_t, F&& f, S&& s)
0208 -> decltype(std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
0209 memory_internal::TupleRef(std::forward<S>(s)))) {
0210 return std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
0211 memory_internal::TupleRef(std::forward<S>(s)));
0212 }
0213
0214
0215 template <class F, class... Args>
0216 auto DecomposePair(F&& f, Args&&... args)
0217 -> decltype(memory_internal::DecomposePairImpl(
0218 std::forward<F>(f), PairArgs(std::forward<Args>(args)...))) {
0219 return memory_internal::DecomposePairImpl(
0220 std::forward<F>(f), PairArgs(std::forward<Args>(args)...));
0221 }
0222
0223
0224 template <class F, class Arg>
0225 decltype(std::declval<F>()(std::declval<const Arg&>(), std::declval<Arg>()))
0226 DecomposeValue(F&& f, Arg&& arg) {
0227 const auto& key = arg;
0228 return std::forward<F>(f)(key, std::forward<Arg>(arg));
0229 }
0230
0231
0232 inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
0233 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0234 ASAN_POISON_MEMORY_REGION(m, s);
0235 #endif
0236 #ifdef ABSL_HAVE_MEMORY_SANITIZER
0237 __msan_poison(m, s);
0238 #endif
0239 (void)m;
0240 (void)s;
0241 }
0242
0243 inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
0244 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0245 ASAN_UNPOISON_MEMORY_REGION(m, s);
0246 #endif
0247 #ifdef ABSL_HAVE_MEMORY_SANITIZER
0248 __msan_unpoison(m, s);
0249 #endif
0250 (void)m;
0251 (void)s;
0252 }
0253
0254 template <typename T>
0255 inline void SanitizerPoisonObject(const T* object) {
0256 SanitizerPoisonMemoryRegion(object, sizeof(T));
0257 }
0258
0259 template <typename T>
0260 inline void SanitizerUnpoisonObject(const T* object) {
0261 SanitizerUnpoisonMemoryRegion(object, sizeof(T));
0262 }
0263
0264 namespace memory_internal {
0265
0266
0267
0268
0269
0270
0271
0272 template <class Pair, class = std::true_type>
0273 struct OffsetOf {
0274 static constexpr size_t kFirst = static_cast<size_t>(-1);
0275 static constexpr size_t kSecond = static_cast<size_t>(-1);
0276 };
0277
0278 template <class Pair>
0279 struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type> {
0280 static constexpr size_t kFirst = offsetof(Pair, first);
0281 static constexpr size_t kSecond = offsetof(Pair, second);
0282 };
0283
0284 template <class K, class V>
0285 struct IsLayoutCompatible {
0286 private:
0287 struct Pair {
0288 K first;
0289 V second;
0290 };
0291
0292
0293 template <class P>
0294 static constexpr bool LayoutCompatible() {
0295 return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) &&
0296 alignof(P) == alignof(Pair) &&
0297 memory_internal::OffsetOf<P>::kFirst ==
0298 memory_internal::OffsetOf<Pair>::kFirst &&
0299 memory_internal::OffsetOf<P>::kSecond ==
0300 memory_internal::OffsetOf<Pair>::kSecond;
0301 }
0302
0303 public:
0304
0305
0306 static constexpr bool value = std::is_standard_layout<K>() &&
0307 std::is_standard_layout<Pair>() &&
0308 memory_internal::OffsetOf<Pair>::kFirst == 0 &&
0309 LayoutCompatible<std::pair<K, V>>() &&
0310 LayoutCompatible<std::pair<const K, V>>();
0311 };
0312
0313 }
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 template <class K, class V>
0340 union map_slot_type {
0341 map_slot_type() {}
0342 ~map_slot_type() = delete;
0343 using value_type = std::pair<const K, V>;
0344 using mutable_value_type =
0345 std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
0346
0347 value_type value;
0348 mutable_value_type mutable_value;
0349 absl::remove_const_t<K> key;
0350 };
0351
0352 template <class K, class V>
0353 struct map_slot_policy {
0354 using slot_type = map_slot_type<K, V>;
0355 using value_type = std::pair<const K, V>;
0356 using mutable_value_type =
0357 std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
0358
0359 private:
0360 static void emplace(slot_type* slot) {
0361
0362
0363 new (slot) slot_type;
0364 }
0365
0366
0367
0368 using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;
0369
0370 public:
0371 static value_type& element(slot_type* slot) { return slot->value; }
0372 static const value_type& element(const slot_type* slot) {
0373 return slot->value;
0374 }
0375
0376
0377
0378 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
0379 static K& mutable_key(slot_type* slot) {
0380
0381
0382 return kMutableKeys::value ? slot->key
0383 : *std::launder(const_cast<K*>(
0384 std::addressof(slot->value.first)));
0385 }
0386 #else
0387 static const K& mutable_key(slot_type* slot) { return key(slot); }
0388 #endif
0389
0390 static const K& key(const slot_type* slot) {
0391 return kMutableKeys::value ? slot->key : slot->value.first;
0392 }
0393
0394 template <class Allocator, class... Args>
0395 static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
0396 emplace(slot);
0397 if (kMutableKeys::value) {
0398 absl::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value,
0399 std::forward<Args>(args)...);
0400 } else {
0401 absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
0402 std::forward<Args>(args)...);
0403 }
0404 }
0405
0406
0407 template <class Allocator>
0408 static void construct(Allocator* alloc, slot_type* slot, slot_type* other) {
0409 emplace(slot);
0410 if (kMutableKeys::value) {
0411 absl::allocator_traits<Allocator>::construct(
0412 *alloc, &slot->mutable_value, std::move(other->mutable_value));
0413 } else {
0414 absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
0415 std::move(other->value));
0416 }
0417 }
0418
0419
0420 template <class Allocator>
0421 static void construct(Allocator* alloc, slot_type* slot,
0422 const slot_type* other) {
0423 emplace(slot);
0424 absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
0425 other->value);
0426 }
0427
0428 template <class Allocator>
0429 static auto destroy(Allocator* alloc, slot_type* slot) {
0430 if (kMutableKeys::value) {
0431 absl::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value);
0432 } else {
0433 absl::allocator_traits<Allocator>::destroy(*alloc, &slot->value);
0434 }
0435 return IsDestructionTrivial<Allocator, value_type>();
0436 }
0437
0438 template <class Allocator>
0439 static auto transfer(Allocator* alloc, slot_type* new_slot,
0440 slot_type* old_slot) {
0441 auto is_relocatable =
0442 typename absl::is_trivially_relocatable<value_type>::type();
0443
0444 emplace(new_slot);
0445 #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
0446 if (is_relocatable) {
0447
0448 std::memcpy(static_cast<void*>(std::launder(&new_slot->value)),
0449 static_cast<const void*>(&old_slot->value),
0450 sizeof(value_type));
0451 return is_relocatable;
0452 }
0453 #endif
0454
0455 if (kMutableKeys::value) {
0456 absl::allocator_traits<Allocator>::construct(
0457 *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value));
0458 } else {
0459 absl::allocator_traits<Allocator>::construct(*alloc, &new_slot->value,
0460 std::move(old_slot->value));
0461 }
0462 destroy(alloc, old_slot);
0463 return is_relocatable;
0464 }
0465 };
0466
0467
0468 using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
0469
0470
0471
0472 template <class Fn, class T>
0473 size_t TypeErasedApplyToSlotFn(const void* fn, void* slot) {
0474 const auto* f = static_cast<const Fn*>(fn);
0475 return (*f)(*static_cast<const T*>(slot));
0476 }
0477
0478
0479
0480 template <class Fn, class T>
0481 size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr) {
0482 const auto* f = static_cast<const Fn*>(fn);
0483 const T* slot = *static_cast<const T**>(slot_ptr);
0484 return (*f)(*slot);
0485 }
0486
0487 }
0488 ABSL_NAMESPACE_END
0489 }
0490
0491 #endif