tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestCompactPair.cpp (6321B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include <type_traits>
      8 
      9 #include "mozilla/Assertions.h"
     10 #include "mozilla/CompactPair.h"
     11 
     12 using mozilla::CompactPair;
     13 using mozilla::MakeCompactPair;
     14 
     15 // Sizes aren't part of the guaranteed CompactPair interface, but we want to
     16 // verify our attempts at compactness through EBO are moderately functional,
     17 // *somewhere*.
     18 #define INSTANTIATE(T1, T2, name, size)                                        \
     19  MOZ_GLOBINIT CompactPair<T1, T2> name##_1(T1(0), T2(0));                     \
     20  static_assert(sizeof(name##_1.first()) > 0,                                  \
     21                "first method should work on CompactPair<" #T1 ", " #T2 ">");  \
     22                                                                               \
     23  static_assert(sizeof(name##_1.second()) > 0,                                 \
     24                "second method should work on CompactPair<" #T1 ", " #T2 ">"); \
     25                                                                               \
     26  static_assert(sizeof(name##_1) == (size),                                    \
     27                "CompactPair<" #T1 ", " #T2 "> has an unexpected size");       \
     28                                                                               \
     29  MOZ_GLOBINIT CompactPair<T2, T1> name##_2(T2(0), T1(0));                     \
     30  static_assert(sizeof(name##_2.first()) > 0,                                  \
     31                "first method should work on CompactPair<" #T2 ", " #T1 ">");  \
     32                                                                               \
     33  static_assert(sizeof(name##_2.second()) > 0,                                 \
     34                "second method should work on CompactPair<" #T2 ", " #T1 ">"); \
     35                                                                               \
     36  static_assert(sizeof(name##_2) == (size),                                    \
     37                "CompactPair<" #T2 ", " #T1 "> has an unexpected size");
     38 
     39 static constexpr std::size_t sizemax(std::size_t a, std::size_t b) {
     40  return (a > b) ? a : b;
     41 }
     42 
     43 INSTANTIATE(int, int, prim1, 2 * sizeof(int));
     44 INSTANTIATE(int, long, prim2,
     45            sizeof(long) + sizemax(sizeof(int), alignof(long)));
     46 
     47 struct EmptyClass {
     48  explicit EmptyClass(int) {}
     49 };
     50 struct NonEmpty {
     51  char mC;
     52  explicit NonEmpty(int) : mC('\0') {}
     53 };
     54 
     55 INSTANTIATE(int, EmptyClass, both1, sizeof(int));
     56 INSTANTIATE(int, NonEmpty, both2, sizeof(int) + alignof(int));
     57 INSTANTIATE(EmptyClass, NonEmpty, both3, 1);
     58 
     59 struct A {
     60  char dummy;
     61  explicit A(int) : dummy('\0') {}
     62 };
     63 struct B : A {
     64  explicit B(int aI) : A(aI) {}
     65 };
     66 
     67 INSTANTIATE(A, A, class1, 2);
     68 INSTANTIATE(A, B, class2, 2);
     69 INSTANTIATE(A, EmptyClass, class3, 1);
     70 
     71 struct EmptyNonMovableNonDefaultConstructible {
     72  explicit EmptyNonMovableNonDefaultConstructible(int) {}
     73 
     74  EmptyNonMovableNonDefaultConstructible(
     75      const EmptyNonMovableNonDefaultConstructible&) = delete;
     76  EmptyNonMovableNonDefaultConstructible(
     77      EmptyNonMovableNonDefaultConstructible&&) = delete;
     78  EmptyNonMovableNonDefaultConstructible& operator=(
     79      const EmptyNonMovableNonDefaultConstructible&) = delete;
     80  EmptyNonMovableNonDefaultConstructible& operator=(
     81      EmptyNonMovableNonDefaultConstructible&&) = delete;
     82 };
     83 
     84 static void TestInPlaceConstruction() {
     85  constexpr int firstValue = 42;
     86  constexpr int secondValue = 43;
     87 
     88  {
     89    const CompactPair<EmptyNonMovableNonDefaultConstructible, int> pair{
     90        std::piecewise_construct, std::tuple(firstValue),
     91        std::tuple(secondValue)};
     92    MOZ_RELEASE_ASSERT(pair.second() == secondValue);
     93  }
     94 
     95  {
     96    const CompactPair<int, EmptyNonMovableNonDefaultConstructible> pair{
     97        std::piecewise_construct, std::tuple(firstValue),
     98        std::tuple(secondValue)};
     99    MOZ_RELEASE_ASSERT(pair.first() == firstValue);
    100  }
    101 
    102  {
    103    const CompactPair<int, int> pair{std::piecewise_construct,
    104                                     std::tuple(firstValue),
    105                                     std::tuple(secondValue)};
    106    MOZ_RELEASE_ASSERT(pair.first() == firstValue);
    107    MOZ_RELEASE_ASSERT(pair.second() == secondValue);
    108  }
    109 
    110  {
    111    const CompactPair<EmptyNonMovableNonDefaultConstructible,
    112                      EmptyNonMovableNonDefaultConstructible>
    113        pair{std::piecewise_construct, std::tuple(firstValue),
    114             std::tuple(secondValue)};
    115 
    116    // nothing to assert here...
    117  }
    118 }
    119 
    120 struct OtherEmpty : EmptyClass {
    121  explicit OtherEmpty(int aI) : EmptyClass(aI) {}
    122 };
    123 
    124 // C++11 requires distinct objects of the same type, within the same "most
    125 // derived object", to have different addresses.  CompactPair allocates its
    126 // elements as two bases, a base and a member, or two members.  If the two
    127 // elements have non-zero size or are unrelated, no big deal.  But if they're
    128 // both empty and related, something -- possibly both -- must be inflated.
    129 // Exactly which are inflated depends which CompactPairHelper specialization is
    130 // used.  We could potentially assert something about size for this case, but
    131 // whatever we could assert would be very finicky.  Plus it's two empty classes
    132 // -- hardly likely. So don't bother trying to assert anything about this case.
    133 // INSTANTIATE(EmptyClass, OtherEmpty, class4, ...something finicky...);
    134 
    135 int main() {
    136  A a(0);
    137  B b(0);
    138  const A constA(0);
    139  const B constB(0);
    140 
    141  // Check that MakeCompactPair generates CompactPair objects of the correct
    142  // types.
    143  static_assert(
    144      std::is_same_v<decltype(MakeCompactPair(A(0), B(0))), CompactPair<A, B>>,
    145      "MakeCompactPair should strip rvalue references");
    146  static_assert(
    147      std::is_same_v<decltype(MakeCompactPair(a, b)), CompactPair<A, B>>,
    148      "MakeCompactPair should strip lvalue references");
    149  static_assert(std::is_same_v<decltype(MakeCompactPair(constA, constB)),
    150                               CompactPair<A, B>>,
    151                "MakeCompactPair should strip CV-qualifiers");
    152 
    153  // Check that copy assignment and move assignment work.
    154  a = constA;
    155  a = A(0);
    156 
    157  TestInPlaceConstruction();
    158 
    159  return 0;
    160 }