text: // Copyright 2020 The Fuchsia Authors
  //
  // Use of this source code is governed by a MIT-style
  // license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT
  
  #include <lib/unittest/unittest.h>
  
  #include <ktl/byte.h>
  #include <ktl/span.h>
  #include <ktl/type_traits.h>
  
  namespace {
  
  static constexpr int kDigitsArray[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  static constexpr ktl::span<const int> kDigits = kDigitsArray;  // T (const &)[N] constructor
  static constexpr ktl::span<const int> kMiddleDigits = kDigits.subspan(3, 4);
  static constexpr ktl::span<const int> kLastDigits = kDigits.subspan(7);
  static constexpr ktl::span<const int> kEmpty = kDigits.subspan(0, 0);
  static constexpr ktl::span<const int> kDefault;  // default constructor
  
  bool FrontTest() {
    BEGIN_TEST;
  
    EXPECT_EQ(kDigits.front(), 9);
    EXPECT_EQ(kMiddleDigits.front(), 6);
    EXPECT_EQ(kLastDigits.front(), 2);
  
    END_TEST;
  }
  
  bool BackTest() {
    BEGIN_TEST;
  
    EXPECT_EQ(kDigits.back(), 0);
    EXPECT_EQ(kMiddleDigits.back(), 3);
    EXPECT_EQ(kLastDigits.back(), 0);
  
    END_TEST;
  }
  
  bool IndexTest() {
    BEGIN_TEST;
  
    EXPECT_EQ(kDigits[0], 9);
    EXPECT_EQ(kDigits[9], 0);
    EXPECT_EQ(kDigits[4], 5);
  
    EXPECT_EQ(kMiddleDigits[0], 6);
    EXPECT_EQ(kMiddleDigits[3], 3);
    EXPECT_EQ(kMiddleDigits[1], 5);
  
    EXPECT_EQ(kLastDigits[0], 2);
    EXPECT_EQ(kLastDigits[1], 1);
    EXPECT_EQ(kLastDigits[2], 0);
  
    END_TEST;
  }
  
  bool SizeEmptyTest() {
    BEGIN_TEST;
  
    EXPECT_EQ(kDigits.size(), 10u);
    EXPECT_EQ(kMiddleDigits.size(), 4u);
    EXPECT_EQ(kLastDigits.size(), 3u);
    EXPECT_EQ(kEmpty.size(), 0u);
    EXPECT_EQ(kDefault.size(), 0u);
  
    EXPECT_FALSE(kDigits.empty());
    EXPECT_FALSE(kMiddleDigits.empty());
    EXPECT_FALSE(kLastDigits.empty());
    EXPECT_TRUE(kEmpty.empty());
    EXPECT_TRUE(kDefault.empty());
  
    EXPECT_EQ(kDigits.size_bytes(), 10 * sizeof(int));
    EXPECT_EQ(kMiddleDigits.size_bytes(), 4 * sizeof(int));
    EXPECT_EQ(kLastDigits.size_bytes(), 3 * sizeof(int));
    EXPECT_EQ(kEmpty.size_bytes(), 0u);
    EXPECT_EQ(kDefault.size_bytes(), 0u);
  
    END_TEST;
  }
  
  bool DataReferencesTest() {
    BEGIN_TEST;
  
    EXPECT_EQ(kDigits.data(), kDigitsArray);
    EXPECT_EQ(kMiddleDigits.data(), kDigitsArray + 3);
    EXPECT_EQ(kLastDigits.data(), kDigitsArray + 7);
  
    EXPECT_EQ(&*kDigits.begin(), kDigitsArray);
    EXPECT_EQ(&*kDigits.end(), kDigitsArray + 10);
    EXPECT_EQ(&*kMiddleDigits.begin(), kDigitsArray + 3);
  
    EXPECT_EQ(&kDigits[0], kDigitsArray);
    EXPECT_EQ(&kDigits.back(), kDigitsArray + 9);
    EXPECT_EQ(&kMiddleDigits[2], kDigitsArray + 5);
  
    END_TEST;
  }
  
  bool IteratorsTest() {
    BEGIN_TEST;
  
    int digits_array[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  
    ktl::span<int> digits = digits_array;
  
    auto i = 9;
  
    for (auto x : digits) {
      EXPECT_EQ(x, i);
      --i;
    }
  
    for (auto& x : digits) {
      x = 7;
    }
  
    for (auto x : digits) {
      EXPECT_EQ(x, 7);
    }
  
    END_TEST;
  }
  
  bool AsBytesTest() {
    BEGIN_TEST;
  
    int digits_array[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
  
    ktl::span<int> digits = digits_array;
  
    ktl::span<ktl::byte> write_bytes = ktl::as_writable_bytes(digits);
  
    for (size_t i = 0; i < sizeof(int); ++i) {
      write_bytes[i] = ktl::byte(i);
    }
  
    ktl::span<const ktl::byte> bytes = ktl::as_bytes(digits);
  
    for (size_t i = 0; i < sizeof(int); ++i) {
      EXPECT_EQ(bytes[i], ktl::byte(i));
    }
  
    EXPECT_EQ(digits_array[0], 0x03020100);
  
    END_TEST;
  }
  
  bool DynamicExtentTest() {
    BEGIN_TEST;
  
    int array_of_ints[3] = {1, 2, 3};
  
    ktl::span<int> ints = array_of_ints;
    EXPECT_EQ(ints.size(), 3u);
  
    ktl::span<int, 3> fixed_ints = ints;
    EXPECT_EQ(fixed_ints.size(), 3u);
  
    ktl::span<int> some_ints = { &array_of_ints[0], 2 };
    EXPECT_EQ(some_ints.size(), 2u);
  
    ktl::span some_more_ints = some_ints;
    EXPECT_EQ(some_more_ints.size(), 2u);
  
    END_TEST;
  }
  
  struct SpannableContainer {
    using value_type = int;
    int* data() { return reinterpret_cast<int*>(0x1234); }
    const int* data() const { return reinterpret_cast<const int*>(0x1234); }
    size_t size() const { return 50; }
  };
  
  bool ContainerTest() {
    BEGIN_TEST;
  
    SpannableContainer writable;
  
    ktl::span<int> container_span = writable;
  
    const SpannableContainer not_writable;
  
    ktl::span<const int> const_container_span = not_writable;
  
    EXPECT_EQ(container_span.data(), reinterpret_cast<int*>(0x1234));
    EXPECT_EQ(container_span.size(), 50u);
  
    EXPECT_EQ(const_container_span.data(), reinterpret_cast<int*>(0x1234));
    EXPECT_EQ(const_container_span.size(), 50u);
  
    END_TEST;
  }
  
  struct Incomplete;
  
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::value_type, Incomplete>);
  static_assert(ktl::is_same_v<ktl::span<const Incomplete>::value_type, Incomplete>);
  static_assert(ktl::is_same_v<ktl::span<volatile Incomplete>::value_type, Incomplete>);
  
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::pointer, Incomplete*>);
  static_assert(ktl::is_same_v<ktl::span<const Incomplete>::pointer, const Incomplete*>);
  
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::const_pointer, const Incomplete*>);
  static_assert(ktl::is_same_v<ktl::span<const Incomplete>::const_pointer, const Incomplete*>);
  
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::size_type, size_t>);
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::difference_type, ptrdiff_t>);
  
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::reference, Incomplete&>);
  static_assert(ktl::is_same_v<ktl::span<const Incomplete>::reference, const Incomplete&>);
  
  static_assert(ktl::is_same_v<ktl::span<Incomplete>::const_reference, const Incomplete&>);
  static_assert(ktl::is_same_v<ktl::span<const Incomplete>::const_reference, const Incomplete&>);
  
  }  // namespace
  
  UNITTEST_START_TESTCASE(span_tests)
  UNITTEST("FrontTest", FrontTest)
  UNITTEST("BackTest", BackTest)
  UNITTEST("IndexTest", IndexTest)
  UNITTEST("SizeEmptyTest", SizeEmptyTest)
  UNITTEST("DataReferencesTest", DataReferencesTest)
  UNITTEST("IteratorsTest", IteratorsTest)
  UNITTEST("AsBytesTest", AsBytesTest)
  UNITTEST("DynamicExtentTest", DynamicExtentTest)
  UNITTEST("ContainerTest", ContainerTest)
  UNITTEST_END_TESTCASE(span_tests, "span", "ktl::span tests")
  