tor-browser

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

copy_test.cc (6466B)


      1 // Copyright 2022 Google LLC
      2 // SPDX-License-Identifier: Apache-2.0
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 
     16 #include <stddef.h>
     17 
     18 #include "hwy/aligned_allocator.h"
     19 
     20 // clang-format off
     21 #undef HWY_TARGET_INCLUDE
     22 #define HWY_TARGET_INCLUDE "hwy/contrib/algo/copy_test.cc"
     23 #include "hwy/foreach_target.h"  // IWYU pragma: keep
     24 #include "hwy/highway.h"
     25 #include "hwy/contrib/algo/copy-inl.h"
     26 #include "hwy/tests/test_util-inl.h"
     27 // clang-format on
     28 
     29 // If your project requires C++14 or later, you can ignore this and pass lambdas
     30 // directly to Transform, without requiring an lvalue as we do here for C++11.
     31 #if __cplusplus < 201402L
     32 #define HWY_GENERIC_LAMBDA 0
     33 #else
     34 #define HWY_GENERIC_LAMBDA 1
     35 #endif
     36 
     37 HWY_BEFORE_NAMESPACE();
     38 namespace hwy {
     39 namespace HWY_NAMESPACE {
     40 namespace {
     41 
     42 // Returns random integer in [0, 128), which fits in any lane type.
     43 template <typename T>
     44 T Random7Bit(RandomState& rng) {
     45  return ConvertScalarTo<T>(Random32(&rng) & 127);
     46 }
     47 
     48 // In C++14, we can instead define these as generic lambdas next to where they
     49 // are invoked.
     50 #if !HWY_GENERIC_LAMBDA
     51 
     52 struct IsOdd {
     53  template <class D, class V>
     54  Mask<D> operator()(D d, V v) const {
     55    return TestBit(v, Set(d, TFromD<D>{1}));
     56  }
     57 };
     58 
     59 #endif  // !HWY_GENERIC_LAMBDA
     60 
     61 // Invokes Test (e.g. TestCopyIf) with all arg combinations. T comes from
     62 // ForFloatTypes.
     63 template <class Test>
     64 struct ForeachCountAndMisalign {
     65  template <typename T, class D>
     66  HWY_NOINLINE void operator()(T /*unused*/, D d) const {
     67    RandomState rng;
     68    const size_t N = Lanes(d);
     69    const size_t misalignments[3] = {0, N / 4, 3 * N / 5};
     70 
     71    for (size_t count = 0; count < 2 * N; ++count) {
     72      for (size_t ma : misalignments) {
     73        for (size_t mb : misalignments) {
     74          Test()(d, count, ma, mb, rng);
     75        }
     76      }
     77    }
     78  }
     79 };
     80 
     81 struct TestFill {
     82  template <class D>
     83  void operator()(D d, size_t count, size_t misalign_a, size_t misalign_b,
     84                  RandomState& rng) {
     85    using T = TFromD<D>;
     86    // HWY_MAX prevents error when misalign == count == 0.
     87    AlignedFreeUniquePtr<T[]> pa =
     88        AllocateAligned<T>(HWY_MAX(1, misalign_a + count));
     89    AlignedFreeUniquePtr<T[]> pb = AllocateAligned<T>(misalign_b + count + 1);
     90    HWY_ASSERT(pa && pb);
     91    T* expected = pa.get() + misalign_a;
     92    const T value = Random7Bit<T>(rng);
     93    for (size_t i = 0; i < count; ++i) {
     94      expected[i] = value;
     95    }
     96    T* actual = pb.get() + misalign_b;
     97 
     98    actual[count] = ConvertScalarTo<T>(0);  // sentinel
     99    Fill(d, value, count, actual);
    100    HWY_ASSERT_EQ(ConvertScalarTo<T>(0), actual[count]);  // no write past end
    101 
    102    const auto info = hwy::detail::MakeTypeInfo<T>();
    103    const char* target_name = hwy::TargetName(HWY_TARGET);
    104    hwy::detail::AssertArrayEqual(info, expected, actual, count, target_name,
    105                                  __FILE__, __LINE__);
    106  }
    107 };
    108 
    109 void TestAllFill() {
    110  ForAllTypes(ForPartialVectors<ForeachCountAndMisalign<TestFill>>());
    111 }
    112 
    113 struct TestCopy {
    114  template <class D>
    115  void operator()(D d, size_t count, size_t misalign_a, size_t misalign_b,
    116                  RandomState& rng) {
    117    using T = TFromD<D>;
    118    // Prevents error if size to allocate is zero.
    119    AlignedFreeUniquePtr<T[]> pa =
    120        AllocateAligned<T>(HWY_MAX(1, misalign_a + count));
    121    AlignedFreeUniquePtr<T[]> pb =
    122        AllocateAligned<T>(HWY_MAX(1, misalign_b + count));
    123    HWY_ASSERT(pa && pb);
    124    T* a = pa.get() + misalign_a;
    125    for (size_t i = 0; i < count; ++i) {
    126      a[i] = Random7Bit<T>(rng);
    127    }
    128    T* b = pb.get() + misalign_b;
    129 
    130    Copy(d, a, count, b);
    131 
    132    const auto info = hwy::detail::MakeTypeInfo<T>();
    133    const char* target_name = hwy::TargetName(HWY_TARGET);
    134    hwy::detail::AssertArrayEqual(info, a, b, count, target_name, __FILE__,
    135                                  __LINE__);
    136  }
    137 };
    138 
    139 void TestAllCopy() {
    140  ForAllTypes(ForPartialVectors<ForeachCountAndMisalign<TestCopy>>());
    141 }
    142 
    143 struct TestCopyIf {
    144  template <class D>
    145  void operator()(D d, size_t count, size_t misalign_a, size_t misalign_b,
    146                  RandomState& rng) {
    147    using T = TFromD<D>;
    148    const size_t padding = Lanes(ScalableTag<T>());
    149 
    150    // Prevents error if size to allocate is zero.
    151    AlignedFreeUniquePtr<T[]> pa =
    152        AllocateAligned<T>(HWY_MAX(1, misalign_a + count));
    153    AlignedFreeUniquePtr<T[]> pb =
    154        AllocateAligned<T>(HWY_MAX(1, misalign_b + count + padding));
    155    AlignedFreeUniquePtr<T[]> expected = AllocateAligned<T>(HWY_MAX(1, count));
    156    HWY_ASSERT(pa && pb && expected);
    157 
    158    T* a = pa.get() + misalign_a;
    159    for (size_t i = 0; i < count; ++i) {
    160      a[i] = Random7Bit<T>(rng);
    161    }
    162    T* b = pb.get() + misalign_b;
    163 
    164    size_t num_odd = 0;
    165    for (size_t i = 0; i < count; ++i) {
    166      if (a[i] & 1) {
    167        expected[num_odd++] = a[i];
    168      }
    169    }
    170 
    171 #if HWY_GENERIC_LAMBDA
    172    const auto is_odd = [](const auto d2, const auto v) HWY_ATTR {
    173      return TestBit(v, Set(d2, TFromD<decltype(d2)>{1}));
    174    };
    175 #else
    176    const IsOdd is_odd;
    177 #endif
    178    T* end = CopyIf(d, a, count, b, is_odd);
    179    const size_t num_written = static_cast<size_t>(end - b);
    180    HWY_ASSERT_EQ(num_odd, num_written);
    181 
    182    const auto info = hwy::detail::MakeTypeInfo<T>();
    183    const char* target_name = hwy::TargetName(HWY_TARGET);
    184    hwy::detail::AssertArrayEqual(info, expected.get(), b, num_odd, target_name,
    185                                  __FILE__, __LINE__);
    186  }
    187 };
    188 
    189 void TestAllCopyIf() {
    190  ForUI163264(ForPartialVectors<ForeachCountAndMisalign<TestCopyIf>>());
    191 }
    192 
    193 }  // namespace
    194 // NOLINTNEXTLINE(google-readability-namespace-comments)
    195 }  // namespace HWY_NAMESPACE
    196 }  // namespace hwy
    197 HWY_AFTER_NAMESPACE();
    198 
    199 #if HWY_ONCE
    200 namespace hwy {
    201 namespace {
    202 HWY_BEFORE_TEST(CopyTest);
    203 HWY_EXPORT_AND_TEST_P(CopyTest, TestAllFill);
    204 HWY_EXPORT_AND_TEST_P(CopyTest, TestAllCopy);
    205 HWY_EXPORT_AND_TEST_P(CopyTest, TestAllCopyIf);
    206 HWY_AFTER_TEST();
    207 }  // namespace
    208 }  // namespace hwy
    209 HWY_TEST_MAIN();
    210 #endif  // HWY_ONCE