compressed_tuple.h
Go to the documentation of this file.
00001 // Copyright 2018 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 //
00015 // Helper class to perform the Empty Base Optimization.
00016 // Ts can contain classes and non-classes, empty or not. For the ones that
00017 // are empty classes, we perform the optimization. If all types in Ts are empty
00018 // classes, then CompressedTuple<Ts...> is itself an empty class.
00019 //
00020 // To access the members, use member get<N>() function.
00021 //
00022 // Eg:
00023 //   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
00024 //                                                                    t3);
00025 //   assert(value.get<0>() == 7);
00026 //   T1& t1 = value.get<1>();
00027 //   const T2& t2 = value.get<2>();
00028 //   ...
00029 //
00030 // https://en.cppreference.com/w/cpp/language/ebo
00031 
00032 #ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
00033 #define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
00034 
00035 #include <tuple>
00036 #include <type_traits>
00037 #include <utility>
00038 
00039 #include "absl/utility/utility.h"
00040 
00041 #if defined(_MSC_VER) && !defined(__NVCC__)
00042 // We need to mark these classes with this declspec to ensure that
00043 // CompressedTuple happens.
00044 #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
00045 #else
00046 #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
00047 #endif
00048 
00049 namespace absl {
00050 namespace container_internal {
00051 
00052 template <typename... Ts>
00053 class CompressedTuple;
00054 
00055 namespace internal_compressed_tuple {
00056 
00057 template <typename D, size_t I>
00058 struct Elem;
00059 template <typename... B, size_t I>
00060 struct Elem<CompressedTuple<B...>, I>
00061     : std::tuple_element<I, std::tuple<B...>> {};
00062 template <typename D, size_t I>
00063 using ElemT = typename Elem<D, I>::type;
00064 
00065 // Use the __is_final intrinsic if available. Where it's not available, classes
00066 // declared with the 'final' specifier cannot be used as CompressedTuple
00067 // elements.
00068 // TODO(sbenza): Replace this with std::is_final in C++14.
00069 template <typename T>
00070 constexpr bool IsFinal() {
00071 #if defined(__clang__) || defined(__GNUC__)
00072   return __is_final(T);
00073 #else
00074   return false;
00075 #endif
00076 }
00077 
00078 template <typename T>
00079 constexpr bool ShouldUseBase() {
00080   return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>();
00081 }
00082 
00083 // The storage class provides two specializations:
00084 //  - For empty classes, it stores T as a base class.
00085 //  - For everything else, it stores T as a member.
00086 template <typename D, size_t I, bool = ShouldUseBase<ElemT<D, I>>()>
00087 struct Storage {
00088   using T = ElemT<D, I>;
00089   T value;
00090   constexpr Storage() = default;
00091   explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
00092   constexpr const T& get() const& { return value; }
00093   T& get() & { return value; }
00094   constexpr const T&& get() const&& { return absl::move(*this).value; }
00095   T&& get() && { return std::move(*this).value; }
00096 };
00097 
00098 template <typename D, size_t I>
00099 struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true>
00100     : ElemT<D, I> {
00101   using T = internal_compressed_tuple::ElemT<D, I>;
00102   constexpr Storage() = default;
00103   explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
00104   constexpr const T& get() const& { return *this; }
00105   T& get() & { return *this; }
00106   constexpr const T&& get() const&& { return absl::move(*this); }
00107   T&& get() && { return std::move(*this); }
00108 };
00109 
00110 template <typename D, typename I>
00111 struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
00112 
00113 template <typename... Ts, size_t... I>
00114 struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
00115     CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>>
00116     // We use the dummy identity function through std::integral_constant to
00117     // convince MSVC of accepting and expanding I in that context. Without it
00118     // you would get:
00119     //   error C3548: 'I': parameter pack cannot be used in this context
00120     : Storage<CompressedTuple<Ts...>,
00121               std::integral_constant<size_t, I>::value>... {
00122   constexpr CompressedTupleImpl() = default;
00123   explicit constexpr CompressedTupleImpl(Ts&&... args)
00124       : Storage<CompressedTuple<Ts...>, I>(absl::forward<Ts>(args))... {}
00125 };
00126 
00127 }  // namespace internal_compressed_tuple
00128 
00129 // Helper class to perform the Empty Base Class Optimization.
00130 // Ts can contain classes and non-classes, empty or not. For the ones that
00131 // are empty classes, we perform the CompressedTuple. If all types in Ts are
00132 // empty classes, then CompressedTuple<Ts...> is itself an empty class.
00133 //
00134 // To access the members, use member .get<N>() function.
00135 //
00136 // Eg:
00137 //   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
00138 //                                                                    t3);
00139 //   assert(value.get<0>() == 7);
00140 //   T1& t1 = value.get<1>();
00141 //   const T2& t2 = value.get<2>();
00142 //   ...
00143 //
00144 // https://en.cppreference.com/w/cpp/language/ebo
00145 template <typename... Ts>
00146 class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
00147     : private internal_compressed_tuple::CompressedTupleImpl<
00148           CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>> {
00149  private:
00150   template <int I>
00151   using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
00152 
00153  public:
00154   constexpr CompressedTuple() = default;
00155   explicit constexpr CompressedTuple(Ts... base)
00156       : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
00157 
00158   template <int I>
00159   ElemT<I>& get() & {
00160     return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
00161   }
00162 
00163   template <int I>
00164   constexpr const ElemT<I>& get() const& {
00165     return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
00166   }
00167 
00168   template <int I>
00169   ElemT<I>&& get() && {
00170     return std::move(*this)
00171         .internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
00172   }
00173 
00174   template <int I>
00175   constexpr const ElemT<I>&& get() const&& {
00176     return absl::move(*this)
00177         .internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
00178   }
00179 };
00180 
00181 // Explicit specialization for a zero-element tuple
00182 // (needed to avoid ambiguous overloads for the default constructor).
00183 template <>
00184 class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
00185 
00186 }  // namespace container_internal
00187 }  // namespace absl
00188 
00189 #undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
00190 
00191 #endif  // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14