pw_kvs: Make kvs compile with C++14

A series of small changes to ensure KVS compiles with C++14.

Change-Id: Idd514c20583b9f3ed192baa38cc5824e3c1ac1a3
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/27141
Commit-Queue: Rob Oliver <rgoliver@google.com>
Reviewed-by: Wyatt Hepler <hepler@google.com>
diff --git a/pw_kvs/BUILD.gn b/pw_kvs/BUILD.gn
index 407c2fa..6015a8b 100644
--- a/pw_kvs/BUILD.gn
+++ b/pw_kvs/BUILD.gn
@@ -61,9 +61,11 @@
   ]
   public_deps = [
     dir_pw_assert,
+    dir_pw_bytes,
     dir_pw_containers,
     dir_pw_span,
     dir_pw_status,
+    dir_pw_string,
   ]
   deps = [
     ":config",
diff --git a/pw_kvs/public/pw_kvs/alignment.h b/pw_kvs/public/pw_kvs/alignment.h
index 56d0c08..e86ec73 100644
--- a/pw_kvs/public/pw_kvs/alignment.h
+++ b/pw_kvs/public/pw_kvs/alignment.h
@@ -20,6 +20,7 @@
 #include <span>
 #include <utility>
 
+#include "pw_bytes/span.h"
 #include "pw_kvs/io.h"
 #include "pw_status/status_with_size.h"
 
@@ -71,7 +72,8 @@
   StatusWithSize Write(std::span<const std::byte> data);
 
   StatusWithSize Write(const void* data, size_t size) {
-    return Write(std::span(static_cast<const std::byte*>(data), size));
+    return Write(
+        std::span<const std::byte>(static_cast<const std::byte*>(data), size));
   }
 
   // Reads size bytes from the input and writes them to the output.
@@ -83,7 +85,7 @@
   StatusWithSize Flush();
 
  private:
-  static constexpr std::byte kPadByte = std::byte{0};
+  static constexpr std::byte kPadByte = static_cast<std::byte>(0);
 
   StatusWithSize AddBytesToBuffer(size_t bytes_added);
 
@@ -122,7 +124,8 @@
   AlignedWriterBuffer<kBufferSize> buffer(alignment_bytes, output);
 
   for (const std::span<const std::byte>& chunk : data) {
-    if (StatusWithSize result = buffer.Write(chunk); !result.ok()) {
+    StatusWithSize result = buffer.Write(chunk);
+    if (!result.ok()) {
       return result;
     }
   }
@@ -137,7 +140,9 @@
     size_t alignment_bytes,
     std::initializer_list<std::span<const std::byte>> data) {
   return AlignedWrite<kBufferSize>(
-      output, alignment_bytes, std::span(data.begin(), data.size()));
+      output,
+      alignment_bytes,
+      std::span<const ConstByteSpan>(data.begin(), data.size()));
 }
 
 }  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/checksum.h b/pw_kvs/public/pw_kvs/checksum.h
index 5899566..6a42e00 100644
--- a/pw_kvs/public/pw_kvs/checksum.h
+++ b/pw_kvs/public/pw_kvs/checksum.h
@@ -19,7 +19,8 @@
 #include "pw_kvs/alignment.h"
 #include "pw_status/status.h"
 
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
 
 class ChecksumAlgorithm {
  public:
@@ -31,7 +32,8 @@
 
   // Updates the checksum from a pointer and size.
   void Update(const void* data, size_t size_bytes) {
-    return Update(std::span(static_cast<const std::byte*>(data), size_bytes));
+    return Update(std::span<const std::byte>(
+        static_cast<const std::byte*>(data), size_bytes));
   }
 
   // Returns the final result of the checksum. Update() can no longer be called
@@ -110,8 +112,12 @@
 
   virtual void FinalizeAligned() = 0;
 
-  OutputToMethod<&AlignedChecksum::UpdateAligned> output_;
+  OutputToMethod<void (AlignedChecksum<kAlignmentBytes, kBufferSize>::*)(
+                     std::span<const std::byte>),
+                 &AlignedChecksum::UpdateAligned>
+      output_;
   AlignedWriterBuffer<kBufferSize> writer_;
 };
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/crc16_checksum.h b/pw_kvs/public/pw_kvs/crc16_checksum.h
index 1cbff63..852e192 100644
--- a/pw_kvs/public/pw_kvs/crc16_checksum.h
+++ b/pw_kvs/public/pw_kvs/crc16_checksum.h
@@ -22,7 +22,8 @@
 
 class ChecksumCrc16 final : public ChecksumAlgorithm {
  public:
-  ChecksumCrc16() : ChecksumAlgorithm(std::as_bytes(std::span(&crc_, 1))) {}
+  ChecksumCrc16()
+      : ChecksumAlgorithm(std::as_bytes(std::span<uint16_t>(&crc_, 1))) {}
 
   void Reset() override { crc_ = checksum::Crc16Ccitt::kInitialValue; }
 
diff --git a/pw_kvs/public/pw_kvs/flash_memory.h b/pw_kvs/public/pw_kvs/flash_memory.h
index d1864b4..3b25d88 100644
--- a/pw_kvs/public/pw_kvs/flash_memory.h
+++ b/pw_kvs/public/pw_kvs/flash_memory.h
@@ -23,7 +23,8 @@
 #include "pw_status/status.h"
 #include "pw_status/status_with_size.h"
 
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
 
 enum class PartitionPermission : bool {
   kReadOnly,
@@ -41,7 +42,7 @@
               size_t alignment,
               uint32_t start_address = 0,
               uint32_t sector_start = 0,
-              std::byte erased_memory_content = std::byte{0xFF})
+              std::byte erased_memory_content = std::byte(0xFF))
       : sector_size_(sector_size),
         flash_sector_count_(sector_count),
         alignment_(alignment),
@@ -78,7 +79,8 @@
   virtual StatusWithSize Read(Address address, std::span<std::byte> output) = 0;
 
   StatusWithSize Read(Address address, void* buffer, size_t len) {
-    return Read(address, std::span(static_cast<std::byte*>(buffer), len));
+    return Read(address,
+                std::span<std::byte>(static_cast<std::byte*>(buffer), len));
   }
 
   // Writes bytes to flash. Blocking call. Returns:
@@ -93,8 +95,9 @@
   StatusWithSize Write(Address destination_flash_address,
                        const void* data,
                        size_t len) {
-    return Write(destination_flash_address,
-                 std::span(static_cast<const std::byte*>(data), len));
+    return Write(
+        destination_flash_address,
+        std::span<const std::byte>(static_cast<const std::byte*>(data), len));
   }
 
   // Convert an Address to an MCU pointer, this can be used for memory
@@ -207,7 +210,8 @@
   virtual StatusWithSize Read(Address address, std::span<std::byte> output);
 
   StatusWithSize Read(Address address, size_t length, void* output) {
-    return Read(address, std::span(static_cast<std::byte*>(output), length));
+    return Read(address,
+                std::span<std::byte>(static_cast<std::byte*>(output), length));
   }
 
   // Writes bytes to flash. Address and data.size_bytes() must both be a
@@ -296,4 +300,5 @@
   const PartitionPermission permission_;
 };
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw
\ No newline at end of file
diff --git a/pw_kvs/public/pw_kvs/format.h b/pw_kvs/public/pw_kvs/format.h
index 19cd174..309f786 100644
--- a/pw_kvs/public/pw_kvs/format.h
+++ b/pw_kvs/public/pw_kvs/format.h
@@ -18,7 +18,8 @@
 
 #include "pw_kvs/checksum.h"
 
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
 
 struct EntryFormat;
 
@@ -104,4 +105,5 @@
   ChecksumAlgorithm* checksum;
 };
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/entry.h b/pw_kvs/public/pw_kvs/internal/entry.h
index 56ad721..aa94cbb 100644
--- a/pw_kvs/public/pw_kvs/internal/entry.h
+++ b/pw_kvs/public/pw_kvs/internal/entry.h
@@ -29,7 +29,9 @@
 #include "pw_kvs/internal/key_descriptor.h"
 #include "pw_kvs/key.h"
 
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
 
 // Entry represents a key-value entry in a flash partition.
 class Entry {
@@ -198,7 +200,7 @@
   }
 
   std::span<const std::byte> checksum_bytes() const {
-    return std::as_bytes(std::span(&header_.checksum, 1));
+    return std::as_bytes(std::span<const uint32_t>(&header_.checksum, 1));
   }
 
   std::span<const std::byte> CalculateChecksum(
@@ -219,4 +221,6 @@
   EntryHeader header_;
 };
 
-}  // namespace pw::kvs::internal
+}  // namespace internal
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/entry_cache.h b/pw_kvs/public/pw_kvs/internal/entry_cache.h
index 8016b53..18e3484 100644
--- a/pw_kvs/public/pw_kvs/internal/entry_cache.h
+++ b/pw_kvs/public/pw_kvs/internal/entry_cache.h
@@ -25,7 +25,9 @@
 #include "pw_kvs/internal/sectors.h"
 #include "pw_kvs/key.h"
 
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
 
 // Caches information about a key-value entry. Facilitates quickly finding
 // entries without having to read flash.
@@ -57,7 +59,7 @@
   // than allowed by the redundancy.
   void AddNewAddress(Address address) {
     addresses_[addresses_.size()] = address;
-    addresses_ = std::span(addresses_.begin(), addresses_.size() + 1);
+    addresses_ = std::span<Address>(addresses_.begin(), addresses_.size() + 1);
   }
 
   // Remove an address from the entry metadata.
@@ -230,4 +232,6 @@
   const size_t redundancy_;
 };
 
-}  // namespace pw::kvs::internal
+}  // namespace internal
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/hash.h b/pw_kvs/public/pw_kvs/internal/hash.h
index b0e60d4..e56fe88 100644
--- a/pw_kvs/public/pw_kvs/internal/hash.h
+++ b/pw_kvs/public/pw_kvs/internal/hash.h
@@ -17,7 +17,9 @@
 
 #include "pw_kvs/key.h"
 
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
 
 // The hash function used to hash keys.
 constexpr uint32_t Hash(Key string) {
@@ -32,4 +34,6 @@
   return hash;
 }
 
-}  // namespace pw::kvs::internal
+}  // namespace internal
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/key_descriptor.h b/pw_kvs/public/pw_kvs/internal/key_descriptor.h
index a7c7183..8e05b3f 100644
--- a/pw_kvs/public/pw_kvs/internal/key_descriptor.h
+++ b/pw_kvs/public/pw_kvs/internal/key_descriptor.h
@@ -15,7 +15,9 @@
 
 #include <cstdint>
 
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
 
 // Whether an entry is present or deleted.
 enum class EntryState : bool { kValid, kDeleted };
@@ -28,4 +30,6 @@
   EntryState state;  // TODO: Pack into transaction ID? or something?
 };
 
-}  // namespace pw::kvs::internal
+}  // namespace internal
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/sectors.h b/pw_kvs/public/pw_kvs/internal/sectors.h
index d2f4565..50fda8d 100644
--- a/pw_kvs/public/pw_kvs/internal/sectors.h
+++ b/pw_kvs/public/pw_kvs/internal/sectors.h
@@ -21,7 +21,9 @@
 #include "pw_containers/vector.h"
 #include "pw_kvs/flash_memory.h"
 
-namespace pw::kvs::internal {
+namespace pw {
+namespace kvs {
+namespace internal {
 
 // Tracks the available and used space in each sector used by the KVS.
 class SectorDescriptor {
@@ -225,4 +227,6 @@
   const SectorDescriptor** const temp_sectors_to_skip_;
 };
 
-}  // namespace pw::kvs::internal
+}  // namespace internal
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/internal/span_traits.h b/pw_kvs/public/pw_kvs/internal/span_traits.h
index 89966a9..f85f0d6 100644
--- a/pw_kvs/public/pw_kvs/internal/span_traits.h
+++ b/pw_kvs/public/pw_kvs/internal/span_traits.h
@@ -16,7 +16,8 @@
 #include <iterator>
 #include <type_traits>
 
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
 namespace internal {
 
 // This borrows the `make_span` function from Chromium and uses to see if a type
@@ -90,4 +91,5 @@
     : public std::bool_constant<
           internal::ConvertsToSpan<std::remove_reference_t<T>>(0)> {};
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/io.h b/pw_kvs/public/pw_kvs/io.h
index 80a0ef0..341b80a 100644
--- a/pw_kvs/public/pw_kvs/io.h
+++ b/pw_kvs/public/pw_kvs/io.h
@@ -43,7 +43,8 @@
 
   // Convenience wrapper for writing data from a pointer and length.
   StatusWithSize Write(const void* data, size_t size_bytes) {
-    return Write(std::span(static_cast<const std::byte*>(data), size_bytes));
+    return Write(std::span<const std::byte>(static_cast<const std::byte*>(data),
+                                            size_bytes));
   }
 
  protected:
@@ -59,7 +60,8 @@
 
   // Convenience wrapper for reading data from a pointer and length.
   StatusWithSize Read(void* data, size_t size_bytes) {
-    return Read(std::span(static_cast<std::byte*>(data), size_bytes));
+    return Read(
+        std::span<std::byte>(static_cast<std::byte*>(data), size_bytes));
   }
 
  protected:
@@ -72,7 +74,7 @@
 // Output adapter that calls a method on a class with a std::span of bytes. If
 // the method returns void instead of the expected Status, Write always returns
 // Status::Ok().
-template <auto kMethod>
+template <typename T, T kMethod>
 class OutputToMethod final : public Output {
   using Class = typename internal::FunctionTraits<decltype(kMethod)>::Class;
 
@@ -80,15 +82,26 @@
   constexpr OutputToMethod(Class* object) : object_(*object) {}
 
  private:
-  StatusWithSize DoWrite(std::span<const std::byte> data) override {
-    using Return = typename internal::FunctionTraits<decltype(kMethod)>::Return;
+  using Return = typename internal::FunctionTraits<decltype(kMethod)>::Return;
+  template <T kMethodImpl = kMethod>
+  typename std::enable_if<std::is_void<typename internal::FunctionTraits<
+                              decltype(kMethodImpl)>::Return>::value,
+                          StatusWithSize>::type
+  DoWriteImpl(std::span<const std::byte> data) {
+    (object_.*kMethod)(data);
+    return StatusWithSize(data.size());
+  }
 
-    if constexpr (std::is_void_v<Return>) {
-      (object_.*kMethod)(data);
-      return StatusWithSize(data.size());
-    } else {
-      return (object_.*kMethod)(data);
-    }
+  template <T kMethodImpl = kMethod>
+  typename std::enable_if<!std::is_void<typename internal::FunctionTraits<
+                              decltype(kMethodImpl)>::Return>::value,
+                          StatusWithSize>::type
+  DoWriteImpl(std::span<const std::byte> data) {
+    return (object_.*kMethod)(data);
+  }
+
+  StatusWithSize DoWrite(std::span<const std::byte> data) override {
+    return DoWriteImpl(data);
   }
 
  private:
diff --git a/pw_kvs/public/pw_kvs/key.h b/pw_kvs/public/pw_kvs/key.h
index df86571..62b8532 100644
--- a/pw_kvs/public/pw_kvs/key.h
+++ b/pw_kvs/public/pw_kvs/key.h
@@ -14,13 +14,17 @@
 #pragma once
 
 #include <cstring>
+#include <limits>
 #include <string>
 
 #if __cplusplus >= 201703L
 #include <string_view>
 #endif  // __cplusplus >= 201703L
 
-namespace pw::kvs {
+#include "pw_string/util.h"
+
+namespace pw {
+namespace kvs {
 
 // Key is a simplified string_view used for KVS. This helps KVS work on
 // platforms without C++17.
@@ -30,7 +34,8 @@
   constexpr Key() : str_{nullptr}, length_{0} {}
   constexpr Key(const Key&) = default;
   constexpr Key(const char* str)
-      : str_{str}, length_{std::char_traits<char>::length(str)} {}
+      : str_{str},
+        length_{string::Length(str, std::numeric_limits<size_t>::max())} {}
   constexpr Key(const char* str, size_t len) : str_{str}, length_{len} {}
   Key(const std::string& str) : str_{str.data()}, length_{str.length()} {}
 
@@ -73,4 +78,5 @@
   size_t length_;
 };
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index a63c5fd..f5d4695 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -32,7 +32,8 @@
 #include "pw_status/status.h"
 #include "pw_status/status_with_size.h"
 
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
 
 enum class GargbageCollectOnWrite {
   // Disable all automatic garbage collection on write.
@@ -124,7 +125,7 @@
   // std::as_writable_bytes(std::span(array)), or pass a pointer to the array
   // instead of the array itself.
   template <typename Pointer,
-            typename = std::enable_if_t<std::is_pointer_v<Pointer>>>
+            typename = std::enable_if_t<std::is_pointer<Pointer>::value>>
   Status Get(const Key& key, const Pointer& pointer) const {
     using T = std::remove_reference_t<std::remove_pointer_t<Pointer>>;
     CheckThatObjectCanBePutOrGet<T>();
@@ -148,14 +149,17 @@
   //   FAILED_PRECONDITION: the KVS is not initialized
   //      INVALID_ARGUMENT: key is empty or too long or value is too large
   //
-  template <typename T>
+  template <typename T,
+            typename std::enable_if_t<ConvertsToSpan<T>::value>* = nullptr>
   Status Put(const Key& key, const T& value) {
-    if constexpr (ConvertsToSpan<T>::value) {
-      return PutBytes(key, std::as_bytes(std::span(value)));
-    } else {
-      CheckThatObjectCanBePutOrGet<T>();
-      return PutBytes(key, std::as_bytes(std::span(&value, 1)));
-    }
+    return PutBytes(key, std::as_bytes(internal::make_span(value)));
+  }
+
+  template <typename T,
+            typename std::enable_if_t<!ConvertsToSpan<T>::value>* = nullptr>
+  Status Put(const Key& key, const T& value) {
+    CheckThatObjectCanBePutOrGet<T>();
+    return PutBytes(key, std::as_bytes(std::span<const T>(&value, 1)));
   }
 
   // Removes a key-value entry from the KVS.
@@ -225,7 +229,7 @@
     }
 
     template <typename Pointer,
-              typename = std::enable_if_t<std::is_pointer_v<Pointer>>>
+              typename = std::enable_if_t<std::is_pointer<Pointer>::value>>
     Status Get(const Pointer& pointer) const {
       using T = std::remove_reference_t<std::remove_pointer_t<Pointer>>;
       CheckThatObjectCanBePutOrGet<T>();
@@ -360,7 +364,7 @@
   template <typename T>
   static constexpr void CheckThatObjectCanBePutOrGet() {
     static_assert(
-        std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>,
+        std::is_trivially_copyable<T>::value && !std::is_pointer<T>::value,
         "Only trivially copyable, non-pointer objects may be Put and Get by "
         "value. Any value may be stored by converting it to a byte std::span "
         "with std::as_bytes(std::span(&value, 1)) or "
@@ -571,7 +575,8 @@
                       const Options& options = {})
       : KeyValueStoreBuffer(
             partition,
-            std::span(reinterpret_cast<const EntryFormat (&)[1]>(format)),
+            std::span<const EntryFormat, kEntryFormats>(
+                reinterpret_cast<const EntryFormat (&)[1]>(format)),
             options) {
     static_assert(kEntryFormats == 1,
                   "kEntryFormats EntryFormats must be specified");
@@ -622,4 +627,5 @@
   std::array<EntryFormat, kEntryFormats> formats_;
 };
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw
diff --git a/pw_kvs/public/pw_kvs/test_key_value_store.h b/pw_kvs/public/pw_kvs/test_key_value_store.h
index 73aa609..e57e74f 100644
--- a/pw_kvs/public/pw_kvs/test_key_value_store.h
+++ b/pw_kvs/public/pw_kvs/test_key_value_store.h
@@ -15,8 +15,10 @@
 
 #include "pw_kvs/key_value_store.h"
 
-namespace pw::kvs {
+namespace pw {
+namespace kvs {
 
 KeyValueStore& TestKvs();
 
-}  // namespace pw::kvs
+}  // namespace kvs
+}  // namespace pw