Update set of supported alias-safe types (#158)

Renames `IsChar` to `IsAliasSafe`, removes `signed char` as an alias
safe type and adds in conditional support for `std::byte` as an anlias
safe type if available.

Fixes: #116
diff --git a/runtime/cpp/emboss_cpp_types.h b/runtime/cpp/emboss_cpp_types.h
index 1b02d47..9a1c211 100644
--- a/runtime/cpp/emboss_cpp_types.h
+++ b/runtime/cpp/emboss_cpp_types.h
@@ -17,6 +17,7 @@
 #define EMBOSS_RUNTIME_CPP_EMBOSS_CPP_TYPES_H_
 
 #include <climits>
+#include <cstddef>
 #include <cstdint>
 #include <type_traits>
 
@@ -77,21 +78,23 @@
   using Signed = ::std::int8_t;
 };
 
-// IsChar<T>::value is true if T is a character type; i.e. const? volatile?
-// (signed|unsigned)? char.
+// IsAliasSafe<T>::value is true if T is an alias safe type; i.e. const?
+// volatile? (unsigned)? char | std::byte.
 template <typename T>
-struct IsChar {
+struct IsAliasSafe {
   // Note that 'char' is a distinct type from 'signed char' and 'unsigned char'.
   static constexpr bool value =
       ::std::is_same<char, typename ::std::remove_cv<T>::type>::value ||
-      ::std::is_same<unsigned char,
-                     typename ::std::remove_cv<T>::type>::value ||
-      ::std::is_same<signed char, typename ::std::remove_cv<T>::type>::value;
+      ::std::is_same<unsigned char, typename ::std::remove_cv<T>::type>::value
+#if __cplusplus >= 201703
+      || ::std::is_same<::std::byte, typename ::std::remove_cv<T>::type>::value
+#endif
+      ;
 };
 
 // The static member variable requires a definition.
 template <typename T>
-constexpr bool IsChar<T>::value;
+constexpr bool IsAliasSafe<T>::value;
 
 // AddSourceConst<SourceT, DestT>::Type is DestT's base type with const added if
 // SourceT is const.
diff --git a/runtime/cpp/emboss_memory_util.h b/runtime/cpp/emboss_memory_util.h
index 4195e99..b1c45fa 100644
--- a/runtime/cpp/emboss_memory_util.h
+++ b/runtime/cpp/emboss_memory_util.h
@@ -74,7 +74,7 @@
 struct MemoryAccessor<CharT, 1, 0, kBits> {
   static_assert(kBits % 8 == 0,
                 "MemoryAccessor can only read and write whole-byte values.");
-  static_assert(IsChar<CharT>::value,
+  static_assert(IsAliasSafe<CharT>::value,
                 "MemoryAccessor can only be used on pointers to char types.");
 
   using Unsigned = typename LeastWidthInteger<kBits>::Unsigned;
@@ -323,7 +323,8 @@
   // unlikely that any compiler vendor will actually change it, as there is
   // probably enough real-world code that relies on uint8_t being allowed to
   // alias.
-  static_assert(IsChar<Byte>::value, "ContiguousBuffer requires char type.");
+  static_assert(IsAliasSafe<Byte>::value,
+                "ContiguousBuffer requires char type.");
 
   // Because real-world processors only care about power-of-2 alignments,
   // ContiguousBuffer only supports power-of-2 alignments.  Note that
@@ -378,12 +379,12 @@
   template <
       typename T,
       typename = typename ::std::enable_if<
-          IsChar<typename ::std::remove_cv<typename ::std::remove_reference<
-              decltype(*(::std::declval<T>().data()))>::type>::type>::value
-              && ::std::is_same<
-                  typename AddSourceCV<decltype(*::std::declval<T>().data()),
-                                       Byte>::Type,
-                  Byte>::value>::type>
+          IsAliasSafe<typename ::std::remove_cv<
+              typename ::std::remove_reference<decltype(*(
+                  ::std::declval<T>().data()))>::type>::type>::value && ::std::
+              is_same<typename AddSourceCV<
+                          decltype(*::std::declval<T>().data()), Byte>::Type,
+                      Byte>::value>::type>
   explicit ContiguousBuffer(T *bytes)
       : bytes_{reinterpret_cast<Byte *>(bytes->data())}, size_{bytes->size()} {
     if (bytes != nullptr)
@@ -393,10 +394,10 @@
   // Constructs a ContiguousBuffer from a pointer to a char type and a size.  As
   // with the constructor from a container, above, Byte must be at least as
   // cv-qualified as T.
-  template <
-      typename T,
-      typename = typename ::std::enable_if<IsChar<T>::value && ::std::is_same<
-          typename AddSourceCV<T, Byte>::Type, Byte>::value>>
+  template <typename T,
+            typename = typename ::std::enable_if<
+                IsAliasSafe<T>::value && ::std::is_same<
+                    typename AddSourceCV<T, Byte>::Type, Byte>::value>>
   explicit ContiguousBuffer(T *bytes, ::std::size_t size)
       : bytes_{reinterpret_cast<Byte *>(bytes)},
         size_{bytes == nullptr ? 0 : size} {
@@ -661,7 +662,7 @@
   // depending on the behavior of the given string type.
   template <typename String>
   typename ::std::enable_if<
-      IsChar<typename ::std::remove_reference<
+      IsAliasSafe<typename ::std::remove_reference<
           decltype(*::std::declval<String>().data())>::type>::value,
       String>::type
   ToString() const {
diff --git a/runtime/cpp/test/emboss_cpp_types_test.cc b/runtime/cpp/test/emboss_cpp_types_test.cc
index 6a71d73..c8976b9 100644
--- a/runtime/cpp/test/emboss_cpp_types_test.cc
+++ b/runtime/cpp/test/emboss_cpp_types_test.cc
@@ -100,30 +100,37 @@
       (::std::is_same<LeastWidthInteger<64>::Signed, ::std::int64_t>::value));
 }
 
-TEST(IsChar, CharTypes) {
-  EXPECT_TRUE(IsChar<char>::value);
-  EXPECT_TRUE(IsChar<unsigned char>::value);
-  EXPECT_TRUE(IsChar<signed char>::value);
-  EXPECT_TRUE(IsChar<const char>::value);
-  EXPECT_TRUE(IsChar<const unsigned char>::value);
-  EXPECT_TRUE(IsChar<const signed char>::value);
-  EXPECT_TRUE(IsChar<volatile char>::value);
-  EXPECT_TRUE(IsChar<volatile unsigned char>::value);
-  EXPECT_TRUE(IsChar<volatile signed char>::value);
-  EXPECT_TRUE(IsChar<const volatile char>::value);
-  EXPECT_TRUE(IsChar<const volatile unsigned char>::value);
-  EXPECT_TRUE(IsChar<const volatile signed char>::value);
+TEST(IsAliasSafe, CharTypes) {
+  EXPECT_TRUE(IsAliasSafe<char>::value);
+  EXPECT_TRUE(IsAliasSafe<unsigned char>::value);
+  EXPECT_TRUE(IsAliasSafe<const char>::value);
+  EXPECT_TRUE(IsAliasSafe<const unsigned char>::value);
+  EXPECT_TRUE(IsAliasSafe<volatile char>::value);
+  EXPECT_TRUE(IsAliasSafe<volatile unsigned char>::value);
+  EXPECT_TRUE(IsAliasSafe<const volatile char>::value);
+  EXPECT_TRUE(IsAliasSafe<const volatile unsigned char>::value);
+#if __cplusplus >= 201703
+  EXPECT_TRUE(IsAliasSafe<::std::byte>::value);
+  EXPECT_TRUE(IsAliasSafe<const ::std::byte>::value);
+  EXPECT_TRUE(IsAliasSafe<volatile ::std::byte>::value);
+  EXPECT_TRUE(IsAliasSafe<const volatile ::std::byte>::value);
+#endif
 }
 
-TEST(IsChar, NonCharTypes) {
+TEST(IsAliasSafe, NonCharTypes) {
   struct OneByte {
     char c;
   };
   EXPECT_EQ(1U, sizeof(OneByte));
-  EXPECT_FALSE(IsChar<int>::value);
-  EXPECT_FALSE(IsChar<unsigned>::value);
-  EXPECT_FALSE(IsChar<const int>::value);
-  EXPECT_FALSE(IsChar<OneByte>::value);
+  EXPECT_FALSE(IsAliasSafe<int>::value);
+  EXPECT_FALSE(IsAliasSafe<unsigned>::value);
+  EXPECT_FALSE(IsAliasSafe<const int>::value);
+  EXPECT_FALSE(IsAliasSafe<OneByte>::value);
+
+  EXPECT_FALSE(IsAliasSafe<signed char>::value);
+  EXPECT_FALSE(IsAliasSafe<const signed char>::value);
+  EXPECT_FALSE(IsAliasSafe<volatile signed char>::value);
+  EXPECT_FALSE(IsAliasSafe<const volatile signed char>::value);
 }
 
 TEST(AddSourceConst, AddSourceConst) {
diff --git a/runtime/cpp/test/emboss_memory_util_test.cc b/runtime/cpp/test/emboss_memory_util_test.cc
index 6974e59..6399b4c 100644
--- a/runtime/cpp/test/emboss_memory_util_test.cc
+++ b/runtime/cpp/test/emboss_memory_util_test.cc
@@ -15,6 +15,7 @@
 #include <array>
 #include <string>
 #if __cplusplus >= 201703L
+#include <cstddef>  // std::byte
 #include <string_view>
 #endif  // __cplusplus >= 201703L
 #include <vector>
@@ -38,6 +39,18 @@
 using LittleEndianBitBlockN =
     BitBlock<LittleEndianByteOrderer<ReadWriteContiguousBuffer>, kBits>;
 
+template <typename T, typename... Args>
+std::array<T, sizeof...(Args)> constexpr init_array(Args &&...args) {
+  return {T(std::forward<Args>(args))...};
+}
+
+template <typename Container, typename... Args>
+auto constexpr init_container(Args &&...args) -> Container {
+  using CharType =
+      typename ::std::remove_reference<decltype(*Container().data())>::type;
+  return {CharType(std::forward<Args>(args))...};
+}
+
 TEST(GreatestCommonDivisor, GreatestCommonDivisor) {
   EXPECT_EQ(4U, GreatestCommonDivisor(12, 20));
   EXPECT_EQ(4U, GreatestCommonDivisor(20, 12));
@@ -56,42 +69,42 @@
 template <typename CharT, ::std::size_t kAlignment, ::std::size_t kOffset,
           ::std::size_t kBits>
 void TestMemoryAccessor() {
-  alignas(kAlignment)
-      CharT bytes[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+  alignas(kAlignment) auto bytes =
+      init_array<CharT>(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
   EXPECT_EQ(
       0x0807060504030201UL & (~0x0UL >> (64 - kBits)),
       (MemoryAccessor<CharT, kAlignment, kOffset, kBits>::ReadLittleEndianUInt(
-          bytes)))
+          bytes.data())))
       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
       << "; kBits = " << kBits;
   EXPECT_EQ(
       0x0102030405060708UL >> (64 - kBits),
       (MemoryAccessor<CharT, kAlignment, kOffset, kBits>::ReadBigEndianUInt(
-          bytes)))
+          bytes.data())))
       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
       << "; kBits = " << kBits;
 
   MemoryAccessor<CharT, kAlignment, kOffset, kBits>::WriteLittleEndianUInt(
-      bytes, 0x7172737475767778UL & (~0x0UL >> (64 - kBits)));
-  ::std::vector<CharT> expected_vector_after_write = {
-      {0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71}};
+      bytes.data(), 0x7172737475767778UL & (~0x0UL >> (64 - kBits)));
+  auto expected_vector_after_write = init_container<std::vector<CharT>>(
+      0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71);
   for (int i = kBits / 8; i < 8; ++i) {
-    expected_vector_after_write[i] = i + 1;
+    expected_vector_after_write[i] = CharT(i + 1);
   }
   EXPECT_EQ(expected_vector_after_write,
-            ::std::vector<CharT>(bytes, bytes + sizeof bytes))
+            ::std::vector<CharT>(std::begin(bytes), std::end(bytes)))
       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
       << "; kBits = " << kBits;
 
   MemoryAccessor<CharT, kAlignment, kOffset, kBits>::WriteBigEndianUInt(
-      bytes, 0x7172737475767778UL >> (64 - kBits));
-  expected_vector_after_write = {
-      {0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78}};
+      bytes.data(), 0x7172737475767778UL >> (64 - kBits));
+  expected_vector_after_write = init_container<std::vector<CharT>>(
+      0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78);
   for (int i = kBits / 8; i < 8; ++i) {
-    expected_vector_after_write[i] = i + 1;
+    expected_vector_after_write[i] = CharT(i + 1);
   }
   EXPECT_EQ(expected_vector_after_write,
-            ::std::vector<CharT>(bytes, bytes + sizeof bytes))
+            ::std::vector<CharT>(std::begin(bytes), std::end(bytes)))
       << "kAlignment = " << kAlignment << "; kOffset = " << kOffset
       << "; kBits = " << kBits;
 
@@ -119,15 +132,19 @@
 template <>
 void TestMemoryAccessor<char, 0, 0, 64>() {}
 
+#if __cplusplus >= 201703L
 template <>
-void TestMemoryAccessor<signed char, 0, 0, 64>() {}
+void TestMemoryAccessor<std::byte, 0, 0, 64>() {}
+#endif
 
 template <>
 void TestMemoryAccessor<unsigned char, 0, 0, 64>() {}
 
 TEST(MemoryAccessor, LittleEndianReads) {
   TestMemoryAccessor<char, 8, 0, 64>();
-  TestMemoryAccessor<signed char, 8, 0, 64>();
+#if __cplusplus >= 201703L
+  TestMemoryAccessor<std::byte, 8, 0, 64>();
+#endif
   TestMemoryAccessor<unsigned char, 8, 0, 64>();
 }
 
@@ -227,8 +244,11 @@
 class ReadOnlyContiguousBufferTest : public ::testing::Test {};
 typedef ::testing::Types<
     /**/ ::std::vector<char>, ::std::array<char, 8>,
-    ::std::vector<unsigned char>, ::std::vector<signed char>, ::std::string,
-    ::std::basic_string<char>,
+    ::std::vector<unsigned char>,
+#if __cplusplus >= 201703L
+    ::std::vector<std::byte>,
+#endif
+    ::std::string, ::std::basic_string<char>,
     ::std::vector<unsigned char, NonstandardAllocator<unsigned char>>,
     ::std::basic_string<char, ::std::char_traits<char>,
                         NonstandardAllocator<char>>>
@@ -237,7 +257,8 @@
                  ReadOnlyContiguousContainerTypes);
 
 TYPED_TEST(ReadOnlyContiguousBufferTest, ConstructionFromContainers) {
-  const TypeParam bytes = {{0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}};
+  const TypeParam bytes =
+      init_container<TypeParam>(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01);
   using CharType =
       typename ::std::remove_reference<decltype(*bytes.data())>::type;
   const auto buffer = ContiguousBuffer<const CharType, 1, 0>{&bytes};
@@ -263,14 +284,17 @@
 template <typename T>
 class ReadWriteContiguousBufferTest : public ::testing::Test {};
 typedef ::testing::Types</**/ ::std::vector<char>, ::std::array<char, 8>,
-                         ::std::vector<unsigned char>,
-                         ::std::vector<signed char>>
+#if __cplusplus >= 201703L
+                         ::std::vector<std::byte>,
+#endif
+                         ::std::vector<unsigned char>>
     ReadWriteContiguousContainerTypes;
 TYPED_TEST_SUITE(ReadWriteContiguousBufferTest,
                  ReadWriteContiguousContainerTypes);
 
 TYPED_TEST(ReadWriteContiguousBufferTest, ConstructionFromContainers) {
-  TypeParam bytes = {{0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01}};
+  TypeParam bytes =
+      init_container<TypeParam>(0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01);
   using CharType =
       typename ::std::remove_reference<decltype(*bytes.data())>::type;
   const auto buffer = ContiguousBuffer<CharType, 1, 0>{&bytes};
@@ -281,7 +305,8 @@
   EXPECT_EQ(0x0807060504030201UL, buffer.template ReadBigEndianUInt<64>());
 
   buffer.template WriteBigEndianUInt<64>(0x0102030405060708UL);
-  EXPECT_EQ((TypeParam{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}),
+  EXPECT_EQ((init_container<TypeParam>(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                                       0x08)),
             bytes);
 
   bytes[4] = static_cast<CharType>(255);
@@ -457,11 +482,11 @@
   EXPECT_TRUE(buffer.Ok());
   EXPECT_EQ(buffer.data(), reinterpret_cast<unsigned char *>(data + 1));
 
-  ContiguousBuffer<const signed char, 2, 1> aligned_buffer;
+  ContiguousBuffer<const unsigned char, 2, 1> aligned_buffer;
   aligned_buffer =
       ContiguousBuffer<unsigned char, 4, 3>(data + 3, sizeof data - 3);
   EXPECT_TRUE(aligned_buffer.Ok());
-  EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<signed char *>(data + 3));
+  EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<unsigned char *>(data + 3));
 }
 
 TEST(ContiguousBuffer, ConstructionFromCompatibleContiguousBuffers) {
@@ -471,10 +496,10 @@
   EXPECT_TRUE(buffer.Ok());
   EXPECT_EQ(buffer.data(), reinterpret_cast<unsigned char *>(data + 1));
 
-  ContiguousBuffer<const signed char, 2, 1> aligned_buffer{
+  ContiguousBuffer<const char, 2, 1> aligned_buffer{
       ContiguousBuffer<unsigned char, 4, 3>(data + 3, sizeof data - 3)};
   EXPECT_TRUE(aligned_buffer.Ok());
-  EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<signed char *>(data + 3));
+  EXPECT_EQ(aligned_buffer.data(), reinterpret_cast<char *>(data + 3));
 }
 
 TEST(ContiguousBuffer, ToString) {