389ec3f906
-- 636137f6f0de910691a3950387fefacfa4909fb8 by Abseil Team <absl-team@google.com>: Add move semantics to absl::container_internal::CompressedTuple PiperOrigin-RevId: 225394165 -- 43da91e4f95a196b2e6b76f1c2f4158817b0ebb0 by Greg Falcon <gfalcon@google.com>: Add a constructor to allow for global absl::Mutex instances. This adds a new constexpr constructor to absl::Mutex, invoked with the absl::kConstInit tag value, which is intended to be used to construct Mutex instances with static storage duration. What's tricky about is absl::Mutex (like std::mutex) is not a trivially destructible class, so by the letter of the law, accessing a global Mutex instance after it is destroyed results in undefined behavior. Despite this, we take care in the destructor to not invalidate the memory layout of the Mutex. Using a kConstInit-constructed global Mutex after it is destroyed happens to work on the toolchains we use. Google relies heavily on this behavior internally. Code sanitizers that detect undefined behavior are able to notice use-after-free of globals, and might complain about this pattern. PiperOrigin-RevId: 225389447 -- 7b553a54bc6460cc7008b028552e66799475ca64 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 225373389 -- fd0c722d217b3b509102274765ccb1a0b596cf46 by Abseil Team <absl-team@google.com>: Update absl/time/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 225246853 -- 9f8f3ba3b67a6d1ac4ecdc529c8b8eb0f02576d9 by Abseil Team <absl-team@google.com>: Update absl/synchronisation/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 225237980 -- a3fdd67dad2e596f804f5e100c8d3a74d8064faa by Abseil Team <absl-team@google.com>: Internal cleanup PiperOrigin-RevId: 225226813 -- 48fab23fb8cdca45e95da14fce0de56614d09c25 by Jon Cohen <cohenjon@google.com>: Use a shim #define for wchar_t in msvc in int128. On ancient versions of msvc and with some compatibility flags on wchar_t is a typedef for unsigned short, whereas on standards-conforming versions wchar_t is a typedef for __wchar_t. The first situation causes int128 to not compile as you can't define both `operator wchar_t()` and `operator unsigned short()` because they are the same type. This CL introduces a wrapper #define in order to abstract over the different typedefs for wchar_t. We do a define instead of a typedef so that we can #undef at the end and not leak the symbol, since we need it in a header. https://docs.microsoft.com/en-us/previous-versions/dh8che7s(v=vs.140) has more detail about the underlying problem. PiperOrigin-RevId: 225223756 GitOrigin-RevId: 636137f6f0de910691a3950387fefacfa4909fb8 Change-Id: Iad94e52e9484c5acec115a2f09ef2d5ec22c2074
191 lines
6.5 KiB
C++
191 lines
6.5 KiB
C++
// Copyright 2018 The Abseil Authors.
|
|
//
|
|
// 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.
|
|
//
|
|
// Helper class to perform the Empty Base Optimization.
|
|
// Ts can contain classes and non-classes, empty or not. For the ones that
|
|
// are empty classes, we perform the optimization. If all types in Ts are empty
|
|
// classes, then CompressedTuple<Ts...> is itself an empty class.
|
|
//
|
|
// To access the members, use member get<N>() function.
|
|
//
|
|
// Eg:
|
|
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
|
|
// t3);
|
|
// assert(value.get<0>() == 7);
|
|
// T1& t1 = value.get<1>();
|
|
// const T2& t2 = value.get<2>();
|
|
// ...
|
|
//
|
|
// http://en.cppreference.com/w/cpp/language/ebo
|
|
|
|
#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
|
|
#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
|
|
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include "absl/utility/utility.h"
|
|
|
|
#ifdef _MSC_VER
|
|
// We need to mark these classes with this declspec to ensure that
|
|
// CompressedTuple happens.
|
|
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
|
|
#else // _MSC_VER
|
|
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
|
|
#endif // _MSC_VER
|
|
|
|
namespace absl {
|
|
namespace container_internal {
|
|
|
|
template <typename... Ts>
|
|
class CompressedTuple;
|
|
|
|
namespace internal_compressed_tuple {
|
|
|
|
template <typename D, size_t I>
|
|
struct Elem;
|
|
template <typename... B, size_t I>
|
|
struct Elem<CompressedTuple<B...>, I>
|
|
: std::tuple_element<I, std::tuple<B...>> {};
|
|
template <typename D, size_t I>
|
|
using ElemT = typename Elem<D, I>::type;
|
|
|
|
// Use the __is_final intrinsic if available. Where it's not available, classes
|
|
// declared with the 'final' specifier cannot be used as CompressedTuple
|
|
// elements.
|
|
// TODO(sbenza): Replace this with std::is_final in C++14.
|
|
template <typename T>
|
|
constexpr bool IsFinal() {
|
|
#if defined(__clang__) || defined(__GNUC__)
|
|
return __is_final(T);
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
constexpr bool ShouldUseBase() {
|
|
return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>();
|
|
}
|
|
|
|
// The storage class provides two specializations:
|
|
// - For empty classes, it stores T as a base class.
|
|
// - For everything else, it stores T as a member.
|
|
template <typename D, size_t I, bool = ShouldUseBase<ElemT<D, I>>()>
|
|
struct Storage {
|
|
using T = ElemT<D, I>;
|
|
T value;
|
|
constexpr Storage() = default;
|
|
explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
|
|
constexpr const T& get() const& { return value; }
|
|
T& get() & { return value; }
|
|
constexpr const T&& get() const&& { return absl::move(*this).value; }
|
|
T&& get() && { return std::move(*this).value; }
|
|
};
|
|
|
|
template <typename D, size_t I>
|
|
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true>
|
|
: ElemT<D, I> {
|
|
using T = internal_compressed_tuple::ElemT<D, I>;
|
|
constexpr Storage() = default;
|
|
explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
|
|
constexpr const T& get() const& { return *this; }
|
|
T& get() & { return *this; }
|
|
constexpr const T&& get() const&& { return absl::move(*this); }
|
|
T&& get() && { return std::move(*this); }
|
|
};
|
|
|
|
template <typename D, typename I>
|
|
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
|
|
|
|
template <typename... Ts, size_t... I>
|
|
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
|
|
CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>>
|
|
// We use the dummy identity function through std::integral_constant to
|
|
// convince MSVC of accepting and expanding I in that context. Without it
|
|
// you would get:
|
|
// error C3548: 'I': parameter pack cannot be used in this context
|
|
: Storage<CompressedTuple<Ts...>,
|
|
std::integral_constant<size_t, I>::value>... {
|
|
constexpr CompressedTupleImpl() = default;
|
|
explicit constexpr CompressedTupleImpl(Ts&&... args)
|
|
: Storage<CompressedTuple<Ts...>, I>(absl::forward<Ts>(args))... {}
|
|
};
|
|
|
|
} // namespace internal_compressed_tuple
|
|
|
|
// Helper class to perform the Empty Base Class Optimization.
|
|
// Ts can contain classes and non-classes, empty or not. For the ones that
|
|
// are empty classes, we perform the CompressedTuple. If all types in Ts are
|
|
// empty classes, then CompressedTuple<Ts...> is itself an empty class.
|
|
//
|
|
// To access the members, use member .get<N>() function.
|
|
//
|
|
// Eg:
|
|
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
|
|
// t3);
|
|
// assert(value.get<0>() == 7);
|
|
// T1& t1 = value.get<1>();
|
|
// const T2& t2 = value.get<2>();
|
|
// ...
|
|
//
|
|
// http://en.cppreference.com/w/cpp/language/ebo
|
|
template <typename... Ts>
|
|
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
|
|
: private internal_compressed_tuple::CompressedTupleImpl<
|
|
CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>> {
|
|
private:
|
|
template <int I>
|
|
using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
|
|
|
|
public:
|
|
constexpr CompressedTuple() = default;
|
|
explicit constexpr CompressedTuple(Ts... base)
|
|
: CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
|
|
|
|
template <int I>
|
|
ElemT<I>& get() & {
|
|
return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
|
|
}
|
|
|
|
template <int I>
|
|
constexpr const ElemT<I>& get() const& {
|
|
return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
|
|
}
|
|
|
|
template <int I>
|
|
ElemT<I>&& get() && {
|
|
return std::move(*this)
|
|
.internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
|
|
}
|
|
|
|
template <int I>
|
|
constexpr const ElemT<I>&& get() const&& {
|
|
return absl::move(*this)
|
|
.internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
|
|
}
|
|
};
|
|
|
|
// Explicit specialization for a zero-element tuple
|
|
// (needed to avoid ambiguous overloads for the default constructor).
|
|
template <>
|
|
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
|
|
|
|
} // namespace container_internal
|
|
} // namespace absl
|
|
|
|
#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
|
|
|
|
#endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
|