diff options
Diffstat (limited to 'absl/utility')
-rw-r--r-- | absl/utility/BUILD.bazel | 34 | ||||
-rw-r--r-- | absl/utility/utility.cc | 27 | ||||
-rw-r--r-- | absl/utility/utility.h | 177 | ||||
-rw-r--r-- | absl/utility/utility_test.cc | 163 |
4 files changed, 401 insertions, 0 deletions
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel new file mode 100644 index 000000000000..73d051992bd3 --- /dev/null +++ b/absl/utility/BUILD.bazel @@ -0,0 +1,34 @@ +load( + "//absl:copts.bzl", + "ABSL_DEFAULT_COPTS", + "ABSL_TEST_COPTS", +) +load( + "//absl:test_dependencies.bzl", + "GUNIT_MAIN_DEPS_SELECTOR", +) + +package(default_visibility = ["//visibility:public"]) + +licenses(["unencumbered"]) # Owned by Google + +cc_library( + name = "utility", + srcs = ["utility.cc"], + hdrs = ["utility.h"], + copts = ABSL_DEFAULT_COPTS, + deps = [ + "//absl/base:config", + "//absl/meta:type_traits", + ], +) + +cc_test( + name = "utility_test", + srcs = ["utility_test.cc"], + copts = ABSL_TEST_COPTS, + deps = [ + ":utility", + "//absl/base:core_headers", + ] + select(GUNIT_MAIN_DEPS_SELECTOR), +) diff --git a/absl/utility/utility.cc b/absl/utility/utility.cc new file mode 100644 index 000000000000..fce79f5bb5b8 --- /dev/null +++ b/absl/utility/utility.cc @@ -0,0 +1,27 @@ +// Copyright 2017 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. + +// ----------------------------------------------------------------------------- +// File: ascii.h +// ----------------------------------------------------------------------------- +// +#include "absl/utility/utility.h" + +namespace absl { + +#ifndef ABSL_HAVE_STD_OPTIONAL +const in_place_t in_place{}; +#endif + +} // namespace absl diff --git a/absl/utility/utility.h b/absl/utility/utility.h new file mode 100644 index 000000000000..4f4a0624d3db --- /dev/null +++ b/absl/utility/utility.h @@ -0,0 +1,177 @@ +// Copyright 2017 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. +// + +// absl/utility:utility is an extension of the <utility> header +// +// It provides stand-ins for C++14's std::integer_sequence and +// related utilities. They are intended to be exactly equivalent. +// - integer_sequence<T, Ints...> == std::integer_sequence<T, Ints...> +// - index_sequence<Ints...> == std::index_sequence<Ints...> +// - make_integer_sequence<T, N> == std::make_integer_sequence<T, N> +// - make_index_sequence<N> == std::make_index_sequence<N> +// - index_sequence_for<Ts...> == std::index_sequence_for<Ts...> +// +// It also provides the tag types in_place_t, in_place_type_t, and +// in_place_index_t, as well as the constant in_place, and constexpr std::move +// and std::forward impolementations in C++11. +// +// References: +// http://en.cppreference.com/w/cpp/utility/integer_sequence +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html +// +// Example: +// // Unpack a tuple for use as a function call's argument list. +// +// template <typename F, typename Tup, size_t... Is> +// auto Impl(F f, const Tup& tup, index_sequence<Is...>) +// -> decltype(f(std::get<Is>(tup) ...)) { +// return f(std::get<Is>(tup) ...); +// } +// +// template <typename Tup> +// using TupIdxSeq = make_index_sequence<std::tuple_size<Tup>::value>; +// +// template <typename F, typename Tup> +// auto ApplyFromTuple(F f, const Tup& tup) +// -> decltype(Impl(f, tup, TupIdxSeq<Tup>{})) { +// return Impl(f, tup, TupIdxSeq<Tup>{}); +// } +#ifndef ABSL_UTILITY_UTILITY_H_ +#define ABSL_UTILITY_UTILITY_H_ + +#include <cstddef> +#include <cstdlib> +#include <utility> + +#include "absl/base/config.h" +#include "absl/meta/type_traits.h" + +namespace absl { + +// Equivalent to std::integer_sequence. +// +// Function templates can deduce compile-time integer sequences by accepting +// an argument of integer_sequence<T, Ints...>. This is a common need when +// working with C++11 variadic templates. +// +// T - the integer type of the sequence elements +// ...Ints - a parameter pack of T values representing the sequence +template <typename T, T... Ints> +struct integer_sequence { + using value_type = T; + static constexpr size_t size() noexcept { return sizeof...(Ints); } +}; + +// Equivalent to std::index_sequence. +// +// Alias for an integer_sequence of size_t. +template <size_t... Ints> +using index_sequence = integer_sequence<size_t, Ints...>; + +namespace utility_internal { + +template <typename Seq, size_t SeqSize, size_t Rem> +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template <typename T, T... Ints, size_t SeqSize> +struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> { + using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>; +}; + +template <typename T, T... Ints, size_t SeqSize> +struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> { + using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>; +}; + +// Recursion helper for 'make_integer_sequence<T, N>'. +// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'. +template <typename T, size_t N> +struct Gen { + using type = + typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type; +}; + +template <typename T> +struct Gen<T, 0> { + using type = integer_sequence<T>; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// Equivalent to std::make_integer_sequence. +// +// make_integer_sequence<int, N> is integer_sequence<int, 0, 1, ..., N-1>; +template <typename T, T N> +using make_integer_sequence = typename utility_internal::Gen<T, N>::type; + +// Equivalent to std::make_index_sequence. +// +// make_index_sequence<N> is index_sequence<0, 1, ..., N-1>; +template <size_t N> +using make_index_sequence = make_integer_sequence<size_t, N>; + +// Equivalent to std::index_sequence_for. +// +// Convert a typename pack into an index sequence of the same length. +template <typename... Ts> +using index_sequence_for = make_index_sequence<sizeof...(Ts)>; + +// Tag types + +#ifdef ABSL_HAVE_STD_OPTIONAL + +using std::in_place_t; +using std::in_place; + +#else // ABSL_HAVE_STD_OPTIONAL + +// Tag type used in order to specify in-place construction, such as with +// absl::optional. +struct in_place_t {}; +extern const in_place_t in_place; + +#endif // ABSL_HAVE_STD_OPTIONAL + +#ifdef ABSL_HAVE_STD_ANY +using std::in_place_type_t; +#else +// Tag types used for in-place construction when the type to construct needs to +// be specified, such as with absl::variant and absl::any. +template <typename T> +struct in_place_type_t {}; +#endif // ABSL_HAVE_STD_ANY + +template <size_t I> +struct in_place_index_t {}; + +// Constexpr move and forward + +template <typename T> +constexpr absl::remove_reference_t<T>&& move(T&& t) noexcept { + return static_cast<absl::remove_reference_t<T>&&>(t); +} + +template <typename T> +constexpr T&& forward( + absl::remove_reference_t<T>& t) noexcept { // NOLINT(runtime/references) + return static_cast<T&&>(t); +} + +} // namespace absl + +#endif // ABSL_UTILITY_UTILITY_H_ diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc new file mode 100644 index 000000000000..62cb46f4d160 --- /dev/null +++ b/absl/utility/utility_test.cc @@ -0,0 +1,163 @@ +// Copyright 2017 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. + +#include "absl/utility/utility.h" + +#include <sstream> +#include <string> +#include <tuple> +#include <type_traits> +#include <vector> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/attributes.h" + +namespace { + +#ifdef _MSC_VER +// Warnings for unused variables in this test are false positives. On other +// platforms, they are suppressed by ABSL_ATTRIBUTE_UNUSED, but that doesn't +// work on MSVC. +// Both the unused variables and the name length warnings are due to calls +// to absl::make_index_sequence with very large values, creating very long type +// names. The resulting warnings are so long they make build output unreadable. +#pragma warning( push ) +#pragma warning( disable : 4503 ) // decorated name length exceeded +#pragma warning( disable : 4101 ) // unreferenced local variable +#endif // _MSC_VER + +using testing::StaticAssertTypeEq; +using testing::ElementsAre; + +TEST(IntegerSequenceTest, ValueType) { + StaticAssertTypeEq<int, absl::integer_sequence<int>::value_type>(); + StaticAssertTypeEq<char, absl::integer_sequence<char>::value_type>(); +} + +TEST(IntegerSequenceTest, Size) { + EXPECT_EQ(0, (absl::integer_sequence<int>::size())); + EXPECT_EQ(1, (absl::integer_sequence<int, 0>::size())); + EXPECT_EQ(1, (absl::integer_sequence<int, 1>::size())); + EXPECT_EQ(2, (absl::integer_sequence<int, 1, 2>::size())); + EXPECT_EQ(3, (absl::integer_sequence<int, 0, 1, 2>::size())); + EXPECT_EQ(3, (absl::integer_sequence<int, -123, 123, 456>::size())); + constexpr size_t sz = absl::integer_sequence<int, 0, 1>::size(); + EXPECT_EQ(2, sz); +} + +TEST(IntegerSequenceTest, MakeIndexSequence) { + StaticAssertTypeEq<absl::index_sequence<>, absl::make_index_sequence<0>>(); + StaticAssertTypeEq<absl::index_sequence<0>, absl::make_index_sequence<1>>(); + StaticAssertTypeEq<absl::index_sequence<0, 1>, + absl::make_index_sequence<2>>(); + StaticAssertTypeEq<absl::index_sequence<0, 1, 2>, + absl::make_index_sequence<3>>(); +} + +TEST(IntegerSequenceTest, MakeIntegerSequence) { + StaticAssertTypeEq<absl::integer_sequence<int>, + absl::make_integer_sequence<int, 0>>(); + StaticAssertTypeEq<absl::integer_sequence<int, 0>, + absl::make_integer_sequence<int, 1>>(); + StaticAssertTypeEq<absl::integer_sequence<int, 0, 1>, + absl::make_integer_sequence<int, 2>>(); + StaticAssertTypeEq<absl::integer_sequence<int, 0, 1, 2>, + absl::make_integer_sequence<int, 3>>(); +} + +template <typename... Ts> +class Counter {}; + +template <size_t... Is> +void CountAll(absl::index_sequence<Is...>) { + // We only need an alias here, but instantiate a variable to silence warnings + // for unused typedefs in some compilers. + ABSL_ATTRIBUTE_UNUSED Counter<absl::make_index_sequence<Is>...> seq; +} + +// This test verifies that absl::make_index_sequence can handle large arguments +// without blowing up template instantiation stack, going OOM or taking forever +// to compile (there is hard 15 minutes limit imposed by forge). +TEST(IntegerSequenceTest, MakeIndexSequencePerformance) { + // O(log N) template instantiations. + // We only need an alias here, but instantiate a variable to silence warnings + // for unused typedefs in some compilers. + ABSL_ATTRIBUTE_UNUSED absl::make_index_sequence<(1 << 16) - 1> seq; + // O(N) template instantiations. + CountAll(absl::make_index_sequence<(1 << 8) - 1>()); +} + +template <typename F, typename Tup, size_t... Is> +auto ApplyFromTupleImpl(F f, const Tup& tup, absl::index_sequence<Is...>) + -> decltype(f(std::get<Is>(tup)...)) { + return f(std::get<Is>(tup)...); +} + +template <typename Tup> +using TupIdxSeq = absl::make_index_sequence<std::tuple_size<Tup>::value>; + +template <typename F, typename Tup> +auto ApplyFromTuple(F f, const Tup& tup) + -> decltype(ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{})) { + return ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{}); +} + +template <typename T> +std::string Fmt(const T& x) { + std::ostringstream os; + os << x; + return os.str(); +} + +struct PoorStrCat { + template <typename... Args> + std::string operator()(const Args&... args) const { + std::string r; + for (const auto& e : {Fmt(args)...}) r += e; + return r; + } +}; + +template <typename Tup, size_t... Is> +std::vector<std::string> TupStringVecImpl(const Tup& tup, + absl::index_sequence<Is...>) { + return {Fmt(std::get<Is>(tup))...}; +} + +template <typename... Ts> +std::vector<std::string> TupStringVec(const std::tuple<Ts...>& tup) { + return TupStringVecImpl(tup, absl::index_sequence_for<Ts...>()); +} + +TEST(MakeIndexSequenceTest, ApplyFromTupleExample) { + PoorStrCat f{}; + EXPECT_EQ("12abc3.14", f(12, "abc", 3.14)); + EXPECT_EQ("12abc3.14", ApplyFromTuple(f, std::make_tuple(12, "abc", 3.14))); +} + +TEST(IndexSequenceForTest, Basic) { + StaticAssertTypeEq<absl::index_sequence<>, absl::index_sequence_for<>>(); + StaticAssertTypeEq<absl::index_sequence<0>, absl::index_sequence_for<int>>(); + StaticAssertTypeEq<absl::index_sequence<0, 1, 2, 3>, + absl::index_sequence_for<int, void, char, int>>(); +} + +TEST(IndexSequenceForTest, Example) { + EXPECT_THAT(TupStringVec(std::make_tuple(12, "abc", 3.14)), + ElementsAre("12", "abc", "3.14")); +} + +} // namespace + |