tvl-depot/absl/container/internal/layout_test.cc

1566 lines
58 KiB
C++
Raw Normal View History

// 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.
#include "absl/container/internal/layout.h"
// We need ::max_align_t because some libstdc++ versions don't provide
// std::max_align_t
#include <stddef.h>
#include <cstdint>
#include <memory>
#include <sstream>
#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/types/span.h"
namespace absl {
namespace container_internal {
namespace {
using ::absl::Span;
using ::testing::ElementsAre;
size_t Distance(const void* from, const void* to) {
ABSL_RAW_CHECK(from <= to, "Distance must be non-negative");
return static_cast<const char*>(to) - static_cast<const char*>(from);
}
template <class Expected, class Actual>
Expected Type(Actual val) {
static_assert(std::is_same<Expected, Actual>(), "");
return val;
}
Export of internal Abseil changes. -- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
2018-12-06 21:44:49 +01:00
// Helper classes to test different size and alignments.
Export of internal Abseil changes. -- 15d7bcf28220750db46930f4d8c090b54e3ae5fe by Jon Cohen <cohenjon@google.com>: Fix miscellaneous CMake change interleaving issues for the daily release: * add back the absl::container target * Add copts to absl_cc_library targets in absl/container/CMakeLists.txt * Add trailing newline to the end of AbseilConfigureCopts.cmake PiperOrigin-RevId: 223057096 -- baac35470d75b6561477f688dc4eb021f604cf71 by Abseil Team <absl-team@google.com>: Internal Cleanup. PiperOrigin-RevId: 223051579 -- 6791c2f2e35b030b5579f36d3c607c6ba92fa089 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223046855 -- 5467ad987ea82aef77d2f1cc85aa9105e7d9c320 by Samuel Benzaquen <sbenza@google.com>: Workaround for gcc bug https://gcc.gnu.org/PR88115 PiperOrigin-RevId: 223041901 -- 36fa5cfd41df2b71d26487c45363901bbf6a2463 by Tom Manshreck <shreck@google.com>: Clarify visit() constraints PiperOrigin-RevId: 223032194 -- afdf4013de036b411db7f92cde8a2493e6665223 by Abseil Team <absl-team@google.com>: Fix comment typos. PiperOrigin-RevId: 223024090 -- e11c01927eb8b898f6633282824022104b258342 by Jon Cohen <cohenjon@google.com>: Make absl::spinlock_test_common TESTONLY This should fix https://github.com/abseil/abseil-cpp/issues/221 PiperOrigin-RevId: 222885323 -- 5ccc576d1c68e4b92705aa8064f1e8d715e5415e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 222877017 -- 96ff25bf78c4f4bca0d6e61faa4feeab91a2e73c by Jon Cohen <cohenjon@google.com>: Align CMake and Bazel compile options. This is the first step towards a single source of truth for Abseil compile options. Also makes absl_test and absl_cc_test make binaries and targets with compatible names to each other to make testing easier. PiperOrigin-RevId: 222858408 -- 7dd3e2618ad5a5de5d918fc73e438ef0b98cec6a by Abseil Team <absl-team@google.com>: Revert "absl: cap SpinLock backoff to 4ms" PiperOrigin-RevId: 222656230 -- 0d49538a3cab714156ed0a5651656c0aa098a1e5 by Abseil Team <absl-team@google.com>: Update absl/container/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 222535766 -- 92744e9d0e5c3bf9e1167a7bdf1a6777192531b1 by Abseil Team <absl-team@google.com>: Disable header parsing for broken targets PiperOrigin-RevId: 222257218 -- 39a6c623601c44e02d91e412f126a813d719507b by Abseil Team <absl-team@google.com>: absl: cap SpinLock backoff to 4ms The current backoff logic has 3 problems: 1. It can produce too high values (up to 256ms), which can negatively affect tail latency. The value was chosen long time ago and now it's a good idea to reconsider it. 2. It does not have low bound, so on any iteration it can produce a very small value that will lead to unnecessary cpu consumption. 3. It does not increase low bound with the number of iterations. So if the SpinLock is actually somehow locked for a very prolonged time, a waiter can still wake periodically. Rework the logic to solve these problems. Add lower bound of 128us, no code should rely on absence of episodic delays in this range as they can occur everywhere. Lower upper bound to 4ms. A thread sleeping for 4ms does not consume significant cpu time (see below). Grow lower bound with the number of iterations. This is cpu consumption of a process doing usleep(x) in a loop (sampled with ps): 64us -> 4.0% 128us -> 2.7% 256us -> 3.5% 512us -> 2.8% 1024us -> 1.6% 2048us -> 0.6% 4096us -> 0.3% 8192us -> 0.0% Few millisecond sleeps do not consume significant time. PiperOrigin-RevId: 222196086 -- 17104a2396ddda61fb0faed0a72ff8c161ca17ea by Shahriar Rouf <nafi@google.com>: Add benchmarks for hashing civil_times. PiperOrigin-RevId: 222152108 GitOrigin-RevId: 15d7bcf28220750db46930f4d8c090b54e3ae5fe Change-Id: I73b929feaf6ce72b70fdafd6108f53bbbeaf9738
2018-11-27 23:21:25 +01:00
struct alignas(8) Int128 {
uint64_t a, b;
friend bool operator==(Int128 lhs, Int128 rhs) {
return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b);
}
static std::string Name() {
return internal_layout::adl_barrier::TypeName<Int128>();
}
};
Export of internal Abseil changes. -- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
2018-12-06 21:44:49 +01:00
// int64_t is *not* 8-byte aligned on all platforms!
struct alignas(8) Int64 {
int64_t a;
friend bool operator==(Int64 lhs, Int64 rhs) {
return lhs.a == rhs.a;
}
};
// Properties of types that this test relies on.
static_assert(sizeof(int8_t) == 1, "");
static_assert(alignof(int8_t) == 1, "");
static_assert(sizeof(int16_t) == 2, "");
static_assert(alignof(int16_t) == 2, "");
static_assert(sizeof(int32_t) == 4, "");
static_assert(alignof(int32_t) == 4, "");
Export of internal Abseil changes. -- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
2018-12-06 21:44:49 +01:00
static_assert(sizeof(Int64) == 8, "");
static_assert(alignof(Int64) == 8, "");
static_assert(sizeof(Int128) == 16, "");
static_assert(alignof(Int128) == 8, "");
template <class Expected, class Actual>
void SameType() {
static_assert(std::is_same<Expected, Actual>(), "");
}
TEST(Layout, ElementType) {
{
using L = Layout<int32_t>;
SameType<int32_t, L::ElementType<0>>();
SameType<int32_t, decltype(L::Partial())::ElementType<0>>();
SameType<int32_t, decltype(L::Partial(0))::ElementType<0>>();
}
{
using L = Layout<int32_t, int32_t>;
SameType<int32_t, L::ElementType<0>>();
SameType<int32_t, L::ElementType<1>>();
SameType<int32_t, decltype(L::Partial())::ElementType<0>>();
SameType<int32_t, decltype(L::Partial())::ElementType<1>>();
SameType<int32_t, decltype(L::Partial(0))::ElementType<0>>();
SameType<int32_t, decltype(L::Partial(0))::ElementType<1>>();
}
{
using L = Layout<int8_t, int32_t, Int128>;
SameType<int8_t, L::ElementType<0>>();
SameType<int32_t, L::ElementType<1>>();
SameType<Int128, L::ElementType<2>>();
SameType<int8_t, decltype(L::Partial())::ElementType<0>>();
SameType<int8_t, decltype(L::Partial(0))::ElementType<0>>();
SameType<int32_t, decltype(L::Partial(0))::ElementType<1>>();
SameType<int8_t, decltype(L::Partial(0, 0))::ElementType<0>>();
SameType<int32_t, decltype(L::Partial(0, 0))::ElementType<1>>();
SameType<Int128, decltype(L::Partial(0, 0))::ElementType<2>>();
SameType<int8_t, decltype(L::Partial(0, 0, 0))::ElementType<0>>();
SameType<int32_t, decltype(L::Partial(0, 0, 0))::ElementType<1>>();
SameType<Int128, decltype(L::Partial(0, 0, 0))::ElementType<2>>();
}
}
TEST(Layout, ElementTypes) {
{
using L = Layout<int32_t>;
SameType<std::tuple<int32_t>, L::ElementTypes>();
SameType<std::tuple<int32_t>, decltype(L::Partial())::ElementTypes>();
SameType<std::tuple<int32_t>, decltype(L::Partial(0))::ElementTypes>();
}
{
using L = Layout<int32_t, int32_t>;
SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>();
SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>();
}
{
using L = Layout<int8_t, int32_t, Int128>;
SameType<std::tuple<int8_t, int32_t, Int128>, L::ElementTypes>();
SameType<std::tuple<int8_t, int32_t, Int128>,
decltype(L::Partial())::ElementTypes>();
SameType<std::tuple<int8_t, int32_t, Int128>,
decltype(L::Partial(0))::ElementTypes>();
SameType<std::tuple<int8_t, int32_t, Int128>,
decltype(L::Partial(0, 0))::ElementTypes>();
SameType<std::tuple<int8_t, int32_t, Int128>,
decltype(L::Partial(0, 0, 0))::ElementTypes>();
}
}
TEST(Layout, OffsetByIndex) {
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial().Offset<0>());
EXPECT_EQ(0, L::Partial(3).Offset<0>());
EXPECT_EQ(0, L(3).Offset<0>());
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0, L::Partial().Offset<0>());
EXPECT_EQ(0, L::Partial(3).Offset<0>());
EXPECT_EQ(12, L::Partial(3).Offset<1>());
EXPECT_EQ(0, L::Partial(3, 5).Offset<0>());
EXPECT_EQ(12, L::Partial(3, 5).Offset<1>());
EXPECT_EQ(0, L(3, 5).Offset<0>());
EXPECT_EQ(12, L(3, 5).Offset<1>());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, L::Partial().Offset<0>());
EXPECT_EQ(0, L::Partial(0).Offset<0>());
EXPECT_EQ(0, L::Partial(0).Offset<1>());
EXPECT_EQ(0, L::Partial(1).Offset<0>());
EXPECT_EQ(4, L::Partial(1).Offset<1>());
EXPECT_EQ(0, L::Partial(5).Offset<0>());
EXPECT_EQ(8, L::Partial(5).Offset<1>());
EXPECT_EQ(0, L::Partial(0, 0).Offset<0>());
EXPECT_EQ(0, L::Partial(0, 0).Offset<1>());
EXPECT_EQ(0, L::Partial(0, 0).Offset<2>());
EXPECT_EQ(0, L::Partial(1, 0).Offset<0>());
EXPECT_EQ(4, L::Partial(1, 0).Offset<1>());
EXPECT_EQ(8, L::Partial(1, 0).Offset<2>());
EXPECT_EQ(0, L::Partial(5, 3).Offset<0>());
EXPECT_EQ(8, L::Partial(5, 3).Offset<1>());
EXPECT_EQ(24, L::Partial(5, 3).Offset<2>());
EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<0>());
EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<1>());
EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<2>());
EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<0>());
EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<1>());
EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<2>());
EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<0>());
EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<2>());
EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<1>());
EXPECT_EQ(0, L(5, 3, 1).Offset<0>());
EXPECT_EQ(24, L(5, 3, 1).Offset<2>());
EXPECT_EQ(8, L(5, 3, 1).Offset<1>());
}
}
TEST(Layout, OffsetByType) {
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial().Offset<int32_t>());
EXPECT_EQ(0, L::Partial(3).Offset<int32_t>());
EXPECT_EQ(0, L(3).Offset<int32_t>());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, L::Partial().Offset<int8_t>());
EXPECT_EQ(0, L::Partial(0).Offset<int8_t>());
EXPECT_EQ(0, L::Partial(0).Offset<int32_t>());
EXPECT_EQ(0, L::Partial(1).Offset<int8_t>());
EXPECT_EQ(4, L::Partial(1).Offset<int32_t>());
EXPECT_EQ(0, L::Partial(5).Offset<int8_t>());
EXPECT_EQ(8, L::Partial(5).Offset<int32_t>());
EXPECT_EQ(0, L::Partial(0, 0).Offset<int8_t>());
EXPECT_EQ(0, L::Partial(0, 0).Offset<int32_t>());
EXPECT_EQ(0, L::Partial(0, 0).Offset<Int128>());
EXPECT_EQ(0, L::Partial(1, 0).Offset<int8_t>());
EXPECT_EQ(4, L::Partial(1, 0).Offset<int32_t>());
EXPECT_EQ(8, L::Partial(1, 0).Offset<Int128>());
EXPECT_EQ(0, L::Partial(5, 3).Offset<int8_t>());
EXPECT_EQ(8, L::Partial(5, 3).Offset<int32_t>());
EXPECT_EQ(24, L::Partial(5, 3).Offset<Int128>());
EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<int8_t>());
EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<int32_t>());
EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<Int128>());
EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<int8_t>());
EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<int32_t>());
EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<Int128>());
EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<int8_t>());
EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<Int128>());
EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<int32_t>());
EXPECT_EQ(0, L(5, 3, 1).Offset<int8_t>());
EXPECT_EQ(24, L(5, 3, 1).Offset<Int128>());
EXPECT_EQ(8, L(5, 3, 1).Offset<int32_t>());
}
}
TEST(Layout, Offsets) {
{
using L = Layout<int32_t>;
EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0));
EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0));
EXPECT_THAT(L(3).Offsets(), ElementsAre(0));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0));
EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0, 12));
EXPECT_THAT(L::Partial(3, 5).Offsets(), ElementsAre(0, 12));
EXPECT_THAT(L(3, 5).Offsets(), ElementsAre(0, 12));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0));
EXPECT_THAT(L::Partial(1).Offsets(), ElementsAre(0, 4));
EXPECT_THAT(L::Partial(5).Offsets(), ElementsAre(0, 8));
EXPECT_THAT(L::Partial(0, 0).Offsets(), ElementsAre(0, 0, 0));
EXPECT_THAT(L::Partial(1, 0).Offsets(), ElementsAre(0, 4, 8));
EXPECT_THAT(L::Partial(5, 3).Offsets(), ElementsAre(0, 8, 24));
EXPECT_THAT(L::Partial(0, 0, 0).Offsets(), ElementsAre(0, 0, 0));
EXPECT_THAT(L::Partial(1, 0, 0).Offsets(), ElementsAre(0, 4, 8));
EXPECT_THAT(L::Partial(5, 3, 1).Offsets(), ElementsAre(0, 8, 24));
EXPECT_THAT(L(5, 3, 1).Offsets(), ElementsAre(0, 8, 24));
}
}
TEST(Layout, AllocSize) {
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).AllocSize());
EXPECT_EQ(12, L::Partial(3).AllocSize());
EXPECT_EQ(12, L(3).AllocSize());
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(32, L::Partial(3, 5).AllocSize());
EXPECT_EQ(32, L(3, 5).AllocSize());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, L::Partial(0, 0, 0).AllocSize());
EXPECT_EQ(8, L::Partial(1, 0, 0).AllocSize());
EXPECT_EQ(8, L::Partial(0, 1, 0).AllocSize());
EXPECT_EQ(16, L::Partial(0, 0, 1).AllocSize());
EXPECT_EQ(24, L::Partial(1, 1, 1).AllocSize());
EXPECT_EQ(136, L::Partial(3, 5, 7).AllocSize());
EXPECT_EQ(136, L(3, 5, 7).AllocSize());
}
}
TEST(Layout, SizeByIndex) {
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).Size<0>());
EXPECT_EQ(3, L::Partial(3).Size<0>());
EXPECT_EQ(3, L(3).Size<0>());
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0, L::Partial(0).Size<0>());
EXPECT_EQ(3, L::Partial(3).Size<0>());
EXPECT_EQ(3, L::Partial(3, 5).Size<0>());
EXPECT_EQ(5, L::Partial(3, 5).Size<1>());
EXPECT_EQ(3, L(3, 5).Size<0>());
EXPECT_EQ(5, L(3, 5).Size<1>());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(3, L::Partial(3).Size<0>());
EXPECT_EQ(3, L::Partial(3, 5).Size<0>());
EXPECT_EQ(5, L::Partial(3, 5).Size<1>());
EXPECT_EQ(3, L::Partial(3, 5, 7).Size<0>());
EXPECT_EQ(5, L::Partial(3, 5, 7).Size<1>());
EXPECT_EQ(7, L::Partial(3, 5, 7).Size<2>());
EXPECT_EQ(3, L(3, 5, 7).Size<0>());
EXPECT_EQ(5, L(3, 5, 7).Size<1>());
EXPECT_EQ(7, L(3, 5, 7).Size<2>());
}
}
TEST(Layout, SizeByType) {
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).Size<int32_t>());
EXPECT_EQ(3, L::Partial(3).Size<int32_t>());
EXPECT_EQ(3, L(3).Size<int32_t>());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(3, L::Partial(3).Size<int8_t>());
EXPECT_EQ(3, L::Partial(3, 5).Size<int8_t>());
EXPECT_EQ(5, L::Partial(3, 5).Size<int32_t>());
EXPECT_EQ(3, L::Partial(3, 5, 7).Size<int8_t>());
EXPECT_EQ(5, L::Partial(3, 5, 7).Size<int32_t>());
EXPECT_EQ(7, L::Partial(3, 5, 7).Size<Int128>());
EXPECT_EQ(3, L(3, 5, 7).Size<int8_t>());
EXPECT_EQ(5, L(3, 5, 7).Size<int32_t>());
EXPECT_EQ(7, L(3, 5, 7).Size<Int128>());
}
}
TEST(Layout, Sizes) {
{
using L = Layout<int32_t>;
EXPECT_THAT(L::Partial().Sizes(), ElementsAre());
EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3));
EXPECT_THAT(L(3).Sizes(), ElementsAre(3));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_THAT(L::Partial().Sizes(), ElementsAre());
EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3));
EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5));
EXPECT_THAT(L(3, 5).Sizes(), ElementsAre(3, 5));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_THAT(L::Partial().Sizes(), ElementsAre());
EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3));
EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5));
EXPECT_THAT(L::Partial(3, 5, 7).Sizes(), ElementsAre(3, 5, 7));
EXPECT_THAT(L(3, 5, 7).Sizes(), ElementsAre(3, 5, 7));
}
}
TEST(Layout, PointerByIndex) {
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
EXPECT_EQ(12,
Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
EXPECT_EQ(0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
EXPECT_EQ(4,
Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
EXPECT_EQ(8,
Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
EXPECT_EQ(8,
Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
EXPECT_EQ(24,
Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
EXPECT_EQ(
0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
EXPECT_EQ(
4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
EXPECT_EQ(
8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(
24,
Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(
8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
}
}
TEST(Layout, PointerByType) {
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
EXPECT_EQ(4,
Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
EXPECT_EQ(8,
Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
EXPECT_EQ(
4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
8,
Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
EXPECT_EQ(
0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
EXPECT_EQ(
8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
EXPECT_EQ(
24,
Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<const Int128*>(
L::Partial(0, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(
4,
Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(8, Distance(p, Type<const Int128*>(
L::Partial(1, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ(
0,
Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(24, Distance(p, Type<const Int128*>(
L::Partial(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(
8,
Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
EXPECT_EQ(24,
Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
}
}
TEST(Layout, MutablePointerByIndex) {
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<0>(p))));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3, 5).Pointer<0>(p))));
EXPECT_EQ(12, Distance(p, Type<int32_t*>(L(3, 5).Pointer<1>(p))));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<0>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<0>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24,
Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
}
}
TEST(Layout, MutablePointerByType) {
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
EXPECT_EQ(8,
Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
EXPECT_EQ(24,
Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
EXPECT_EQ(0,
Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(0,
Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ(0,
Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
EXPECT_EQ(4,
Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
EXPECT_EQ(
8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
EXPECT_EQ(0,
Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(
24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(8,
Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
}
}
TEST(Layout, Pointers) {
alignas(max_align_t) const unsigned char p[100] = {};
using L = Layout<int8_t, int8_t, Int128>;
{
const auto x = L::Partial();
EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)),
Type<std::tuple<const int8_t*>>(x.Pointers(p)));
}
{
const auto x = L::Partial(1);
EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)),
(Type<std::tuple<const int8_t*, const int8_t*>>(x.Pointers(p))));
}
{
const auto x = L::Partial(1, 2);
EXPECT_EQ(
std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
(Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>(
x.Pointers(p))));
}
{
const auto x = L::Partial(1, 2, 3);
EXPECT_EQ(
std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
(Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>(
x.Pointers(p))));
}
{
const L x(1, 2, 3);
EXPECT_EQ(
std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
(Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>(
x.Pointers(p))));
}
}
TEST(Layout, MutablePointers) {
alignas(max_align_t) unsigned char p[100];
using L = Layout<int8_t, int8_t, Int128>;
{
const auto x = L::Partial();
EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)),
Type<std::tuple<int8_t*>>(x.Pointers(p)));
}
{
const auto x = L::Partial(1);
EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)),
(Type<std::tuple<int8_t*, int8_t*>>(x.Pointers(p))));
}
{
const auto x = L::Partial(1, 2);
EXPECT_EQ(
std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
(Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p))));
}
{
const auto x = L::Partial(1, 2, 3);
EXPECT_EQ(
std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
(Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p))));
}
{
const L x(1, 2, 3);
EXPECT_EQ(
std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)),
(Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p))));
}
}
TEST(Layout, SliceByIndexSize) {
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size());
EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
EXPECT_EQ(3, L(3).Slice<0>(p).size());
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
EXPECT_EQ(5, L(3, 5).Slice<1>(p).size());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size());
EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size());
EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size());
EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size());
EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size());
EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size());
EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size());
}
}
TEST(Layout, SliceByTypeSize) {
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).Slice<int32_t>(p).size());
EXPECT_EQ(3, L::Partial(3).Slice<int32_t>(p).size());
EXPECT_EQ(3, L(3).Slice<int32_t>(p).size());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(3, L::Partial(3).Slice<int8_t>(p).size());
EXPECT_EQ(3, L::Partial(3, 5).Slice<int8_t>(p).size());
EXPECT_EQ(5, L::Partial(3, 5).Slice<int32_t>(p).size());
EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<int8_t>(p).size());
EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<int32_t>(p).size());
EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<Int128>(p).size());
EXPECT_EQ(3, L(3, 5, 7).Slice<int8_t>(p).size());
EXPECT_EQ(5, L(3, 5, 7).Slice<int32_t>(p).size());
EXPECT_EQ(7, L(3, 5, 7).Slice<Int128>(p).size());
}
}
TEST(Layout, MutableSliceByIndexSize) {
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size());
EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
EXPECT_EQ(3, L(3).Slice<0>(p).size());
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
EXPECT_EQ(5, L(3, 5).Slice<1>(p).size());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size());
EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size());
EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size());
EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size());
EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size());
EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size());
EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size());
EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size());
EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size());
}
}
TEST(Layout, MutableSliceByTypeSize) {
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
EXPECT_EQ(0, L::Partial(0).Slice<int32_t>(p).size());
EXPECT_EQ(3, L::Partial(3).Slice<int32_t>(p).size());
EXPECT_EQ(3, L(3).Slice<int32_t>(p).size());
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(3, L::Partial(3).Slice<int8_t>(p).size());
EXPECT_EQ(3, L::Partial(3, 5).Slice<int8_t>(p).size());
EXPECT_EQ(5, L::Partial(3, 5).Slice<int32_t>(p).size());
EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<int8_t>(p).size());
EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<int32_t>(p).size());
EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<Int128>(p).size());
EXPECT_EQ(3, L(3, 5, 7).Slice<int8_t>(p).size());
EXPECT_EQ(5, L(3, 5, 7).Slice<int32_t>(p).size());
EXPECT_EQ(7, L(3, 5, 7).Slice<Int128>(p).size());
}
}
TEST(Layout, SliceByIndexData) {
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
EXPECT_EQ(
0,
Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(
0,
Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p,
Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(
12,
Distance(p,
Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(12,
Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(
0,
Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p,
Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
EXPECT_EQ(
4,
Distance(p,
Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
EXPECT_EQ(
8,
Distance(p,
Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<const Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
4,
Distance(
p,
Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
8,
Distance(
p,
Type<Span<const Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(
24,
Distance(
p,
Type<Span<const Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(
8,
Distance(
p,
Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(
24,
Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(
8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
}
}
TEST(Layout, SliceByTypeData) {
alignas(max_align_t) const unsigned char p[100] = {};
{
using L = Layout<int32_t>;
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
4,
Distance(
p,
Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
EXPECT_EQ(
8,
Distance(
p,
Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p))
.data()));
EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
L::Partial(0, 0, 0).Slice<Int128>(p))
.data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
4,
Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p))
.data()));
EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
L::Partial(1, 0, 0).Slice<Int128>(p))
.data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
L::Partial(5, 3, 1).Slice<Int128>(p))
.data()));
EXPECT_EQ(
8,
Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p))
.data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
24,
Distance(p,
Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ(
8, Distance(
p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
}
}
TEST(Layout, MutableSliceByIndexData) {
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
EXPECT_EQ(0,
Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
}
{
using L = Layout<int32_t, int32_t>;
EXPECT_EQ(0,
Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(
12,
Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3, 5).Slice<0>(p)).data()));
EXPECT_EQ(12, Distance(p, Type<Span<int32_t>>(L(3, 5).Slice<1>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
EXPECT_EQ(
4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
EXPECT_EQ(
8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
EXPECT_EQ(
4,
Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
EXPECT_EQ(
8, Distance(
p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(
24, Distance(
p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(
8,
Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
EXPECT_EQ(24,
Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
}
}
TEST(Layout, MutableSliceByTypeData) {
alignas(max_align_t) unsigned char p[100];
{
using L = Layout<int32_t>;
EXPECT_EQ(
0,
Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
}
{
using L = Layout<int8_t, int32_t, Int128>;
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
4, Distance(
p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
EXPECT_EQ(
8, Distance(
p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
0,
Distance(
p,
Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
EXPECT_EQ(
4,
Distance(
p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
EXPECT_EQ(
8,
Distance(
p,
Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
EXPECT_EQ(
0, Distance(
p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
24,
Distance(
p,
Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ(
8,
Distance(
p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
EXPECT_EQ(0,
Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
EXPECT_EQ(
24,
Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
EXPECT_EQ(
8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
}
}
MATCHER_P(IsSameSlice, slice, "") {
return arg.size() == slice.size() && arg.data() == slice.data();
}
template <typename... M>
class TupleMatcher {
public:
explicit TupleMatcher(M... matchers) : matchers_(std::move(matchers)...) {}
template <typename Tuple>
bool MatchAndExplain(const Tuple& p,
testing::MatchResultListener* /* listener */) const {
static_assert(std::tuple_size<Tuple>::value == sizeof...(M), "");
return MatchAndExplainImpl(
p, absl::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
// For the matcher concept. Left empty as we don't really need the diagnostics
// right now.
void DescribeTo(::std::ostream* os) const {}
void DescribeNegationTo(::std::ostream* os) const {}
private:
template <typename Tuple, size_t... Is>
bool MatchAndExplainImpl(const Tuple& p, absl::index_sequence<Is...>) const {
// Using std::min as a simple variadic "and".
return std::min(
{true, testing::SafeMatcherCast<
const typename std::tuple_element<Is, Tuple>::type&>(
std::get<Is>(matchers_))
.Matches(std::get<Is>(p))...});
}
std::tuple<M...> matchers_;
};
template <typename... M>
testing::PolymorphicMatcher<TupleMatcher<M...>> Tuple(M... matchers) {
return testing::MakePolymorphicMatcher(
TupleMatcher<M...>(std::move(matchers)...));
}
TEST(Layout, Slices) {
alignas(max_align_t) const unsigned char p[100] = {};
using L = Layout<int8_t, int8_t, Int128>;
{
const auto x = L::Partial();
EXPECT_THAT(Type<std::tuple<>>(x.Slices(p)), Tuple());
}
{
const auto x = L::Partial(1);
EXPECT_THAT(Type<std::tuple<Span<const int8_t>>>(x.Slices(p)),
Tuple(IsSameSlice(x.Slice<0>(p))));
}
{
const auto x = L::Partial(1, 2);
EXPECT_THAT(
(Type<std::tuple<Span<const int8_t>, Span<const int8_t>>>(x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p))));
}
{
const auto x = L::Partial(1, 2, 3);
EXPECT_THAT((Type<std::tuple<Span<const int8_t>, Span<const int8_t>,
Span<const Int128>>>(x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
IsSameSlice(x.Slice<2>(p))));
}
{
const L x(1, 2, 3);
EXPECT_THAT((Type<std::tuple<Span<const int8_t>, Span<const int8_t>,
Span<const Int128>>>(x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
IsSameSlice(x.Slice<2>(p))));
}
}
TEST(Layout, MutableSlices) {
alignas(max_align_t) unsigned char p[100] = {};
using L = Layout<int8_t, int8_t, Int128>;
{
const auto x = L::Partial();
EXPECT_THAT(Type<std::tuple<>>(x.Slices(p)), Tuple());
}
{
const auto x = L::Partial(1);
EXPECT_THAT(Type<std::tuple<Span<int8_t>>>(x.Slices(p)),
Tuple(IsSameSlice(x.Slice<0>(p))));
}
{
const auto x = L::Partial(1, 2);
EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>>>(x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p))));
}
{
const auto x = L::Partial(1, 2, 3);
EXPECT_THAT(
(Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
IsSameSlice(x.Slice<2>(p))));
}
{
const L x(1, 2, 3);
EXPECT_THAT(
(Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
IsSameSlice(x.Slice<2>(p))));
}
}
TEST(Layout, UnalignedTypes) {
constexpr Layout<unsigned char, unsigned char, unsigned char> x(1, 2, 3);
alignas(max_align_t) unsigned char p[x.AllocSize() + 1];
EXPECT_THAT(x.Pointers(p + 1), Tuple(p + 1, p + 2, p + 4));
}
TEST(Layout, CustomAlignment) {
constexpr Layout<unsigned char, Aligned<unsigned char, 8>> x(1, 2);
alignas(max_align_t) unsigned char p[x.AllocSize()];
EXPECT_EQ(10, x.AllocSize());
EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 8));
}
TEST(Layout, OverAligned) {
constexpr size_t M = alignof(max_align_t);
constexpr Layout<unsigned char, Aligned<unsigned char, 2 * M>> x(1, 3);
alignas(2 * M) unsigned char p[x.AllocSize()];
EXPECT_EQ(2 * M + 3, x.AllocSize());
EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 2 * M));
}
TEST(Layout, Alignment) {
static_assert(Layout<int8_t>::Alignment() == 1, "");
static_assert(Layout<int32_t>::Alignment() == 4, "");
Export of internal Abseil changes. -- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
2018-12-06 21:44:49 +01:00
static_assert(Layout<Int64>::Alignment() == 8, "");
static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, "");
Export of internal Abseil changes. -- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
2018-12-06 21:44:49 +01:00
static_assert(Layout<int8_t, int32_t, Int64>::Alignment() == 8, "");
static_assert(Layout<int8_t, Int64, int32_t>::Alignment() == 8, "");
static_assert(Layout<int32_t, int8_t, Int64>::Alignment() == 8, "");
static_assert(Layout<int32_t, Int64, int8_t>::Alignment() == 8, "");
static_assert(Layout<Int64, int8_t, int32_t>::Alignment() == 8, "");
static_assert(Layout<Int64, int32_t, int8_t>::Alignment() == 8, "");
}
TEST(Layout, ConstexprPartial) {
constexpr size_t M = alignof(max_align_t);
constexpr Layout<unsigned char, Aligned<unsigned char, 2 * M>> x(1, 3);
static_assert(x.Partial(1).template Offset<1>() == 2 * M, "");
}
// [from, to)
struct Region {
size_t from;
size_t to;
};
void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) {
#ifdef ADDRESS_SANITIZER
for (size_t i = 0; i != n; ++i) {
EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i));
}
#endif
}
template <size_t N>
void ExpectPoisoned(const unsigned char (&buf)[N],
std::initializer_list<Region> reg) {
size_t prev = 0;
for (const Region& r : reg) {
ExpectRegionPoisoned(buf + prev, r.from - prev, false);
ExpectRegionPoisoned(buf + r.from, r.to - r.from, true);
prev = r.to;
}
ExpectRegionPoisoned(buf + prev, N - prev, false);
}
TEST(Layout, PoisonPadding) {
Export of internal Abseil changes. -- 1a5fb4eb5bc6c0332962f659470a07908168aa5c by CJ Johnson <johnsoncj@google.com>: Move InlinedVector's AbslHashValue(...) definition to out of line PiperOrigin-RevId: 224389234 -- b7c5ccdfe17b9cb5f7124c8d591ce0989a15b9fb by Jon Cohen <cohenjon@google.com>: Add a shebang line and chmod +x generate_copts.py. Note that we use the "python" command as suggested in PEP 934 (https://www.python.org/dev/peps/pep-0394/) as this script should work in both Python 2 and Python 3. Also adds a gitignore for __pycache__ for when using python3 PiperOrigin-RevId: 224375405 -- c57a148a1106b21dbcd750541f10b058bf55a2bf by CJ Johnson <johnsoncj@google.com>: Adds comment to InlinedVector intended to help the g4 diffing algo to better identify the substantive change PiperOrigin-RevId: 224362807 -- b635ab981a07dc2434be7b0d164030a42cc67923 by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 224362442 -- 217021f7dcec31141a89b91930c241af062c2133 by CJ Johnson <johnsoncj@google.com>: Distinguishes the source of InlinedVector::at(...)'s bounds checking exception PiperOrigin-RevId: 224341645 -- 01a5943560ce9216a9d8ccb1279b5c5c2f6e1019 by CJ Johnson <johnsoncj@google.com>: Relocates out of line member function definitions to their respective declarations in InlinedVector PiperOrigin-RevId: 224320130 -- b3d57fcddcd737e91aab812d69b82fef2ca43d7e by Abseil Team <absl-team@google.com>: On 32-bit systems, the alignment of int64 can be 4 bytes. Created a custom Int64 type (to go with the custom Int128 type) just for the purpose of testing layouts and alignments; it doesn't need to support actual arithmetic. PiperOrigin-RevId: 224209785 GitOrigin-RevId: 1a5fb4eb5bc6c0332962f659470a07908168aa5c Change-Id: I9d6b1c441cd712709ebd6c0a8911d0755cab506f
2018-12-06 21:44:49 +01:00
using L = Layout<int8_t, Int64, int32_t, Int128>;
constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize();
{
constexpr auto x = L::Partial();
alignas(max_align_t) const unsigned char c[n] = {};
x.PoisonPadding(c);
EXPECT_EQ(x.Slices(c), x.Slices(c));
ExpectPoisoned(c, {});
}
{
constexpr auto x = L::Partial(1);
alignas(max_align_t) const unsigned char c[n] = {};
x.PoisonPadding(c);
EXPECT_EQ(x.Slices(c), x.Slices(c));
ExpectPoisoned(c, {{1, 8}});
}
{
constexpr auto x = L::Partial(1, 2);
alignas(max_align_t) const unsigned char c[n] = {};
x.PoisonPadding(c);
EXPECT_EQ(x.Slices(c), x.Slices(c));
ExpectPoisoned(c, {{1, 8}});
}
{
constexpr auto x = L::Partial(1, 2, 3);
alignas(max_align_t) const unsigned char c[n] = {};
x.PoisonPadding(c);
EXPECT_EQ(x.Slices(c), x.Slices(c));
ExpectPoisoned(c, {{1, 8}, {36, 40}});
}
{
constexpr auto x = L::Partial(1, 2, 3, 4);
alignas(max_align_t) const unsigned char c[n] = {};
x.PoisonPadding(c);
EXPECT_EQ(x.Slices(c), x.Slices(c));
ExpectPoisoned(c, {{1, 8}, {36, 40}});
}
{
constexpr L x(1, 2, 3, 4);
alignas(max_align_t) const unsigned char c[n] = {};
x.PoisonPadding(c);
EXPECT_EQ(x.Slices(c), x.Slices(c));
ExpectPoisoned(c, {{1, 8}, {36, 40}});
}
}
TEST(Layout, DebugString) {
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial();
EXPECT_EQ("@0<signed char>(1)", x.DebugString());
}
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1);
EXPECT_EQ("@0<signed char>(1)[1]; @4<int>(4)", x.DebugString());
}
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2);
EXPECT_EQ("@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)",
x.DebugString());
}
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
Export of internal Abseil changes. -- 15d7bcf28220750db46930f4d8c090b54e3ae5fe by Jon Cohen <cohenjon@google.com>: Fix miscellaneous CMake change interleaving issues for the daily release: * add back the absl::container target * Add copts to absl_cc_library targets in absl/container/CMakeLists.txt * Add trailing newline to the end of AbseilConfigureCopts.cmake PiperOrigin-RevId: 223057096 -- baac35470d75b6561477f688dc4eb021f604cf71 by Abseil Team <absl-team@google.com>: Internal Cleanup. PiperOrigin-RevId: 223051579 -- 6791c2f2e35b030b5579f36d3c607c6ba92fa089 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223046855 -- 5467ad987ea82aef77d2f1cc85aa9105e7d9c320 by Samuel Benzaquen <sbenza@google.com>: Workaround for gcc bug https://gcc.gnu.org/PR88115 PiperOrigin-RevId: 223041901 -- 36fa5cfd41df2b71d26487c45363901bbf6a2463 by Tom Manshreck <shreck@google.com>: Clarify visit() constraints PiperOrigin-RevId: 223032194 -- afdf4013de036b411db7f92cde8a2493e6665223 by Abseil Team <absl-team@google.com>: Fix comment typos. PiperOrigin-RevId: 223024090 -- e11c01927eb8b898f6633282824022104b258342 by Jon Cohen <cohenjon@google.com>: Make absl::spinlock_test_common TESTONLY This should fix https://github.com/abseil/abseil-cpp/issues/221 PiperOrigin-RevId: 222885323 -- 5ccc576d1c68e4b92705aa8064f1e8d715e5415e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 222877017 -- 96ff25bf78c4f4bca0d6e61faa4feeab91a2e73c by Jon Cohen <cohenjon@google.com>: Align CMake and Bazel compile options. This is the first step towards a single source of truth for Abseil compile options. Also makes absl_test and absl_cc_test make binaries and targets with compatible names to each other to make testing easier. PiperOrigin-RevId: 222858408 -- 7dd3e2618ad5a5de5d918fc73e438ef0b98cec6a by Abseil Team <absl-team@google.com>: Revert "absl: cap SpinLock backoff to 4ms" PiperOrigin-RevId: 222656230 -- 0d49538a3cab714156ed0a5651656c0aa098a1e5 by Abseil Team <absl-team@google.com>: Update absl/container/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 222535766 -- 92744e9d0e5c3bf9e1167a7bdf1a6777192531b1 by Abseil Team <absl-team@google.com>: Disable header parsing for broken targets PiperOrigin-RevId: 222257218 -- 39a6c623601c44e02d91e412f126a813d719507b by Abseil Team <absl-team@google.com>: absl: cap SpinLock backoff to 4ms The current backoff logic has 3 problems: 1. It can produce too high values (up to 256ms), which can negatively affect tail latency. The value was chosen long time ago and now it's a good idea to reconsider it. 2. It does not have low bound, so on any iteration it can produce a very small value that will lead to unnecessary cpu consumption. 3. It does not increase low bound with the number of iterations. So if the SpinLock is actually somehow locked for a very prolonged time, a waiter can still wake periodically. Rework the logic to solve these problems. Add lower bound of 128us, no code should rely on absence of episodic delays in this range as they can occur everywhere. Lower upper bound to 4ms. A thread sleeping for 4ms does not consume significant cpu time (see below). Grow lower bound with the number of iterations. This is cpu consumption of a process doing usleep(x) in a loop (sampled with ps): 64us -> 4.0% 128us -> 2.7% 256us -> 3.5% 512us -> 2.8% 1024us -> 1.6% 2048us -> 0.6% 4096us -> 0.3% 8192us -> 0.0% Few millisecond sleeps do not consume significant time. PiperOrigin-RevId: 222196086 -- 17104a2396ddda61fb0faed0a72ff8c161ca17ea by Shahriar Rouf <nafi@google.com>: Add benchmarks for hashing civil_times. PiperOrigin-RevId: 222152108 GitOrigin-RevId: 15d7bcf28220750db46930f4d8c090b54e3ae5fe Change-Id: I73b929feaf6ce72b70fdafd6108f53bbbeaf9738
2018-11-27 23:21:25 +01:00
"@16" +
Int128::Name() + "(16)",
x.DebugString());
}
{
constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
Export of internal Abseil changes. -- 15d7bcf28220750db46930f4d8c090b54e3ae5fe by Jon Cohen <cohenjon@google.com>: Fix miscellaneous CMake change interleaving issues for the daily release: * add back the absl::container target * Add copts to absl_cc_library targets in absl/container/CMakeLists.txt * Add trailing newline to the end of AbseilConfigureCopts.cmake PiperOrigin-RevId: 223057096 -- baac35470d75b6561477f688dc4eb021f604cf71 by Abseil Team <absl-team@google.com>: Internal Cleanup. PiperOrigin-RevId: 223051579 -- 6791c2f2e35b030b5579f36d3c607c6ba92fa089 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223046855 -- 5467ad987ea82aef77d2f1cc85aa9105e7d9c320 by Samuel Benzaquen <sbenza@google.com>: Workaround for gcc bug https://gcc.gnu.org/PR88115 PiperOrigin-RevId: 223041901 -- 36fa5cfd41df2b71d26487c45363901bbf6a2463 by Tom Manshreck <shreck@google.com>: Clarify visit() constraints PiperOrigin-RevId: 223032194 -- afdf4013de036b411db7f92cde8a2493e6665223 by Abseil Team <absl-team@google.com>: Fix comment typos. PiperOrigin-RevId: 223024090 -- e11c01927eb8b898f6633282824022104b258342 by Jon Cohen <cohenjon@google.com>: Make absl::spinlock_test_common TESTONLY This should fix https://github.com/abseil/abseil-cpp/issues/221 PiperOrigin-RevId: 222885323 -- 5ccc576d1c68e4b92705aa8064f1e8d715e5415e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 222877017 -- 96ff25bf78c4f4bca0d6e61faa4feeab91a2e73c by Jon Cohen <cohenjon@google.com>: Align CMake and Bazel compile options. This is the first step towards a single source of truth for Abseil compile options. Also makes absl_test and absl_cc_test make binaries and targets with compatible names to each other to make testing easier. PiperOrigin-RevId: 222858408 -- 7dd3e2618ad5a5de5d918fc73e438ef0b98cec6a by Abseil Team <absl-team@google.com>: Revert "absl: cap SpinLock backoff to 4ms" PiperOrigin-RevId: 222656230 -- 0d49538a3cab714156ed0a5651656c0aa098a1e5 by Abseil Team <absl-team@google.com>: Update absl/container/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 222535766 -- 92744e9d0e5c3bf9e1167a7bdf1a6777192531b1 by Abseil Team <absl-team@google.com>: Disable header parsing for broken targets PiperOrigin-RevId: 222257218 -- 39a6c623601c44e02d91e412f126a813d719507b by Abseil Team <absl-team@google.com>: absl: cap SpinLock backoff to 4ms The current backoff logic has 3 problems: 1. It can produce too high values (up to 256ms), which can negatively affect tail latency. The value was chosen long time ago and now it's a good idea to reconsider it. 2. It does not have low bound, so on any iteration it can produce a very small value that will lead to unnecessary cpu consumption. 3. It does not increase low bound with the number of iterations. So if the SpinLock is actually somehow locked for a very prolonged time, a waiter can still wake periodically. Rework the logic to solve these problems. Add lower bound of 128us, no code should rely on absence of episodic delays in this range as they can occur everywhere. Lower upper bound to 4ms. A thread sleeping for 4ms does not consume significant cpu time (see below). Grow lower bound with the number of iterations. This is cpu consumption of a process doing usleep(x) in a loop (sampled with ps): 64us -> 4.0% 128us -> 2.7% 256us -> 3.5% 512us -> 2.8% 1024us -> 1.6% 2048us -> 0.6% 4096us -> 0.3% 8192us -> 0.0% Few millisecond sleeps do not consume significant time. PiperOrigin-RevId: 222196086 -- 17104a2396ddda61fb0faed0a72ff8c161ca17ea by Shahriar Rouf <nafi@google.com>: Add benchmarks for hashing civil_times. PiperOrigin-RevId: 222152108 GitOrigin-RevId: 15d7bcf28220750db46930f4d8c090b54e3ae5fe Change-Id: I73b929feaf6ce72b70fdafd6108f53bbbeaf9738
2018-11-27 23:21:25 +01:00
"@16" +
Int128::Name() + "(16)[4]",
x.DebugString());
}
{
constexpr Layout<int8_t, int32_t, int8_t, Int128> x(1, 2, 3, 4);
EXPECT_EQ(
"@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
Export of internal Abseil changes. -- 15d7bcf28220750db46930f4d8c090b54e3ae5fe by Jon Cohen <cohenjon@google.com>: Fix miscellaneous CMake change interleaving issues for the daily release: * add back the absl::container target * Add copts to absl_cc_library targets in absl/container/CMakeLists.txt * Add trailing newline to the end of AbseilConfigureCopts.cmake PiperOrigin-RevId: 223057096 -- baac35470d75b6561477f688dc4eb021f604cf71 by Abseil Team <absl-team@google.com>: Internal Cleanup. PiperOrigin-RevId: 223051579 -- 6791c2f2e35b030b5579f36d3c607c6ba92fa089 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223046855 -- 5467ad987ea82aef77d2f1cc85aa9105e7d9c320 by Samuel Benzaquen <sbenza@google.com>: Workaround for gcc bug https://gcc.gnu.org/PR88115 PiperOrigin-RevId: 223041901 -- 36fa5cfd41df2b71d26487c45363901bbf6a2463 by Tom Manshreck <shreck@google.com>: Clarify visit() constraints PiperOrigin-RevId: 223032194 -- afdf4013de036b411db7f92cde8a2493e6665223 by Abseil Team <absl-team@google.com>: Fix comment typos. PiperOrigin-RevId: 223024090 -- e11c01927eb8b898f6633282824022104b258342 by Jon Cohen <cohenjon@google.com>: Make absl::spinlock_test_common TESTONLY This should fix https://github.com/abseil/abseil-cpp/issues/221 PiperOrigin-RevId: 222885323 -- 5ccc576d1c68e4b92705aa8064f1e8d715e5415e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 222877017 -- 96ff25bf78c4f4bca0d6e61faa4feeab91a2e73c by Jon Cohen <cohenjon@google.com>: Align CMake and Bazel compile options. This is the first step towards a single source of truth for Abseil compile options. Also makes absl_test and absl_cc_test make binaries and targets with compatible names to each other to make testing easier. PiperOrigin-RevId: 222858408 -- 7dd3e2618ad5a5de5d918fc73e438ef0b98cec6a by Abseil Team <absl-team@google.com>: Revert "absl: cap SpinLock backoff to 4ms" PiperOrigin-RevId: 222656230 -- 0d49538a3cab714156ed0a5651656c0aa098a1e5 by Abseil Team <absl-team@google.com>: Update absl/container/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 222535766 -- 92744e9d0e5c3bf9e1167a7bdf1a6777192531b1 by Abseil Team <absl-team@google.com>: Disable header parsing for broken targets PiperOrigin-RevId: 222257218 -- 39a6c623601c44e02d91e412f126a813d719507b by Abseil Team <absl-team@google.com>: absl: cap SpinLock backoff to 4ms The current backoff logic has 3 problems: 1. It can produce too high values (up to 256ms), which can negatively affect tail latency. The value was chosen long time ago and now it's a good idea to reconsider it. 2. It does not have low bound, so on any iteration it can produce a very small value that will lead to unnecessary cpu consumption. 3. It does not increase low bound with the number of iterations. So if the SpinLock is actually somehow locked for a very prolonged time, a waiter can still wake periodically. Rework the logic to solve these problems. Add lower bound of 128us, no code should rely on absence of episodic delays in this range as they can occur everywhere. Lower upper bound to 4ms. A thread sleeping for 4ms does not consume significant cpu time (see below). Grow lower bound with the number of iterations. This is cpu consumption of a process doing usleep(x) in a loop (sampled with ps): 64us -> 4.0% 128us -> 2.7% 256us -> 3.5% 512us -> 2.8% 1024us -> 1.6% 2048us -> 0.6% 4096us -> 0.3% 8192us -> 0.0% Few millisecond sleeps do not consume significant time. PiperOrigin-RevId: 222196086 -- 17104a2396ddda61fb0faed0a72ff8c161ca17ea by Shahriar Rouf <nafi@google.com>: Add benchmarks for hashing civil_times. PiperOrigin-RevId: 222152108 GitOrigin-RevId: 15d7bcf28220750db46930f4d8c090b54e3ae5fe Change-Id: I73b929feaf6ce72b70fdafd6108f53bbbeaf9738
2018-11-27 23:21:25 +01:00
"@16" +
Int128::Name() + "(16)[4]",
x.DebugString());
}
}
TEST(Layout, CharTypes) {
constexpr Layout<int32_t> x(1);
alignas(max_align_t) char c[x.AllocSize()] = {};
alignas(max_align_t) unsigned char uc[x.AllocSize()] = {};
alignas(max_align_t) signed char sc[x.AllocSize()] = {};
alignas(max_align_t) const char cc[x.AllocSize()] = {};
alignas(max_align_t) const unsigned char cuc[x.AllocSize()] = {};
alignas(max_align_t) const signed char csc[x.AllocSize()] = {};
Type<int32_t*>(x.Pointer<0>(c));
Type<int32_t*>(x.Pointer<0>(uc));
Type<int32_t*>(x.Pointer<0>(sc));
Type<const int32_t*>(x.Pointer<0>(cc));
Type<const int32_t*>(x.Pointer<0>(cuc));
Type<const int32_t*>(x.Pointer<0>(csc));
Type<int32_t*>(x.Pointer<int32_t>(c));
Type<int32_t*>(x.Pointer<int32_t>(uc));
Type<int32_t*>(x.Pointer<int32_t>(sc));
Type<const int32_t*>(x.Pointer<int32_t>(cc));
Type<const int32_t*>(x.Pointer<int32_t>(cuc));
Type<const int32_t*>(x.Pointer<int32_t>(csc));
Type<std::tuple<int32_t*>>(x.Pointers(c));
Type<std::tuple<int32_t*>>(x.Pointers(uc));
Type<std::tuple<int32_t*>>(x.Pointers(sc));
Type<std::tuple<const int32_t*>>(x.Pointers(cc));
Type<std::tuple<const int32_t*>>(x.Pointers(cuc));
Type<std::tuple<const int32_t*>>(x.Pointers(csc));
Type<Span<int32_t>>(x.Slice<0>(c));
Type<Span<int32_t>>(x.Slice<0>(uc));
Type<Span<int32_t>>(x.Slice<0>(sc));
Type<Span<const int32_t>>(x.Slice<0>(cc));
Type<Span<const int32_t>>(x.Slice<0>(cuc));
Type<Span<const int32_t>>(x.Slice<0>(csc));
Type<std::tuple<Span<int32_t>>>(x.Slices(c));
Type<std::tuple<Span<int32_t>>>(x.Slices(uc));
Type<std::tuple<Span<int32_t>>>(x.Slices(sc));
Type<std::tuple<Span<const int32_t>>>(x.Slices(cc));
Type<std::tuple<Span<const int32_t>>>(x.Slices(cuc));
Type<std::tuple<Span<const int32_t>>>(x.Slices(csc));
}
TEST(Layout, ConstElementType) {
constexpr Layout<const int32_t> x(1);
alignas(int32_t) char c[x.AllocSize()] = {};
const char* cc = c;
const int32_t* p = reinterpret_cast<const int32_t*>(cc);
EXPECT_EQ(alignof(int32_t), x.Alignment());
EXPECT_EQ(0, x.Offset<0>());
EXPECT_EQ(0, x.Offset<const int32_t>());
EXPECT_THAT(x.Offsets(), ElementsAre(0));
EXPECT_EQ(1, x.Size<0>());
EXPECT_EQ(1, x.Size<const int32_t>());
EXPECT_THAT(x.Sizes(), ElementsAre(1));
EXPECT_EQ(sizeof(int32_t), x.AllocSize());
EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<0>(c)));
EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<0>(cc)));
EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<const int32_t>(c)));
EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<const int32_t>(cc)));
EXPECT_THAT(Type<std::tuple<const int32_t*>>(x.Pointers(c)), Tuple(p));
EXPECT_THAT(Type<std::tuple<const int32_t*>>(x.Pointers(cc)), Tuple(p));
EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<0>(c)),
IsSameSlice(Span<const int32_t>(p, 1)));
EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<0>(cc)),
IsSameSlice(Span<const int32_t>(p, 1)));
EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<const int32_t>(c)),
IsSameSlice(Span<const int32_t>(p, 1)));
EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<const int32_t>(cc)),
IsSameSlice(Span<const int32_t>(p, 1)));
EXPECT_THAT(Type<std::tuple<Span<const int32_t>>>(x.Slices(c)),
Tuple(IsSameSlice(Span<const int32_t>(p, 1))));
EXPECT_THAT(Type<std::tuple<Span<const int32_t>>>(x.Slices(cc)),
Tuple(IsSameSlice(Span<const int32_t>(p, 1))));
}
namespace example {
// Immutable move-only string with sizeof equal to sizeof(void*). The string
// size and the characters are kept in the same heap allocation.
class CompactString {
public:
CompactString(const char* s = "") { // NOLINT
const size_t size = strlen(s);
// size_t[1], followed by char[size + 1].
// This statement doesn't allocate memory.
const L layout(1, size + 1);
// AllocSize() tells us how much memory we need to allocate for all our
// data.
p_.reset(new unsigned char[layout.AllocSize()]);
// If running under ASAN, mark the padding bytes, if any, to catch memory
// errors.
layout.PoisonPadding(p_.get());
// Store the size in the allocation.
// Pointer<size_t>() is a synonym for Pointer<0>().
*layout.Pointer<size_t>(p_.get()) = size;
// Store the characters in the allocation.
memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
}
size_t size() const {
// Equivalent to reinterpret_cast<size_t&>(*p).
return *L::Partial().Pointer<size_t>(p_.get());
}
const char* c_str() const {
// Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
// The argument in Partial(1) specifies that we have size_t[1] in front of
Export of internal Abseil changes. -- 15d7bcf28220750db46930f4d8c090b54e3ae5fe by Jon Cohen <cohenjon@google.com>: Fix miscellaneous CMake change interleaving issues for the daily release: * add back the absl::container target * Add copts to absl_cc_library targets in absl/container/CMakeLists.txt * Add trailing newline to the end of AbseilConfigureCopts.cmake PiperOrigin-RevId: 223057096 -- baac35470d75b6561477f688dc4eb021f604cf71 by Abseil Team <absl-team@google.com>: Internal Cleanup. PiperOrigin-RevId: 223051579 -- 6791c2f2e35b030b5579f36d3c607c6ba92fa089 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 223046855 -- 5467ad987ea82aef77d2f1cc85aa9105e7d9c320 by Samuel Benzaquen <sbenza@google.com>: Workaround for gcc bug https://gcc.gnu.org/PR88115 PiperOrigin-RevId: 223041901 -- 36fa5cfd41df2b71d26487c45363901bbf6a2463 by Tom Manshreck <shreck@google.com>: Clarify visit() constraints PiperOrigin-RevId: 223032194 -- afdf4013de036b411db7f92cde8a2493e6665223 by Abseil Team <absl-team@google.com>: Fix comment typos. PiperOrigin-RevId: 223024090 -- e11c01927eb8b898f6633282824022104b258342 by Jon Cohen <cohenjon@google.com>: Make absl::spinlock_test_common TESTONLY This should fix https://github.com/abseil/abseil-cpp/issues/221 PiperOrigin-RevId: 222885323 -- 5ccc576d1c68e4b92705aa8064f1e8d715e5415e by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 222877017 -- 96ff25bf78c4f4bca0d6e61faa4feeab91a2e73c by Jon Cohen <cohenjon@google.com>: Align CMake and Bazel compile options. This is the first step towards a single source of truth for Abseil compile options. Also makes absl_test and absl_cc_test make binaries and targets with compatible names to each other to make testing easier. PiperOrigin-RevId: 222858408 -- 7dd3e2618ad5a5de5d918fc73e438ef0b98cec6a by Abseil Team <absl-team@google.com>: Revert "absl: cap SpinLock backoff to 4ms" PiperOrigin-RevId: 222656230 -- 0d49538a3cab714156ed0a5651656c0aa098a1e5 by Abseil Team <absl-team@google.com>: Update absl/container/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 222535766 -- 92744e9d0e5c3bf9e1167a7bdf1a6777192531b1 by Abseil Team <absl-team@google.com>: Disable header parsing for broken targets PiperOrigin-RevId: 222257218 -- 39a6c623601c44e02d91e412f126a813d719507b by Abseil Team <absl-team@google.com>: absl: cap SpinLock backoff to 4ms The current backoff logic has 3 problems: 1. It can produce too high values (up to 256ms), which can negatively affect tail latency. The value was chosen long time ago and now it's a good idea to reconsider it. 2. It does not have low bound, so on any iteration it can produce a very small value that will lead to unnecessary cpu consumption. 3. It does not increase low bound with the number of iterations. So if the SpinLock is actually somehow locked for a very prolonged time, a waiter can still wake periodically. Rework the logic to solve these problems. Add lower bound of 128us, no code should rely on absence of episodic delays in this range as they can occur everywhere. Lower upper bound to 4ms. A thread sleeping for 4ms does not consume significant cpu time (see below). Grow lower bound with the number of iterations. This is cpu consumption of a process doing usleep(x) in a loop (sampled with ps): 64us -> 4.0% 128us -> 2.7% 256us -> 3.5% 512us -> 2.8% 1024us -> 1.6% 2048us -> 0.6% 4096us -> 0.3% 8192us -> 0.0% Few millisecond sleeps do not consume significant time. PiperOrigin-RevId: 222196086 -- 17104a2396ddda61fb0faed0a72ff8c161ca17ea by Shahriar Rouf <nafi@google.com>: Add benchmarks for hashing civil_times. PiperOrigin-RevId: 222152108 GitOrigin-RevId: 15d7bcf28220750db46930f4d8c090b54e3ae5fe Change-Id: I73b929feaf6ce72b70fdafd6108f53bbbeaf9738
2018-11-27 23:21:25 +01:00
// the characters.
return L::Partial(1).Pointer<char>(p_.get());
}
private:
// Our heap allocation contains a size_t followed by an array of chars.
using L = Layout<size_t, char>;
std::unique_ptr<unsigned char[]> p_;
};
TEST(CompactString, Works) {
CompactString s = "hello";
EXPECT_EQ(5, s.size());
EXPECT_STREQ("hello", s.c_str());
}
} // namespace example
} // namespace
} // namespace container_internal
} // namespace absl