pw_kvs: Add to build; get tests passing

Change-Id: Idfd357beaf60b94ebaf9b4b1f8cd1b3d712e9b10
diff --git a/pw_kvs/public/pw_kvs/assert.h b/pw_kvs/public/pw_kvs/assert.h
new file mode 100644
index 0000000..36f232b
--- /dev/null
+++ b/pw_kvs/public/pw_kvs/assert.h
@@ -0,0 +1,69 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <algorithm>
+#include <type_traits>
+
+// Compares the provided value to nullptr and returns it. This is intended to be
+// used as part of another statement.
+#define CHECK_NOTNULL(value) \
+  ::pw::log::CheckNotNull("", __LINE__, #value " != nullptr", value)
+
+// In release builds, DCHECK_NOTNULL simply passes along the value.
+// DCHECK_NOTNULL must not be used as a standalone expression, since the result
+// would be unused on release builds. Use DCHECK_NE instead.
+//#define DCHECK_NOTNULL(value) value
+
+#define DCHECK_NOTNULL(value) \
+  ::pw::log::DCheckNotNull("", __LINE__, #value " != nullptr", value)
+
+namespace pw::log {
+
+template <typename T>
+constexpr T CheckNotNull(const char* /* file */,
+                         unsigned /* line */,
+                         const char* /* message */,
+                         T&& value) {
+  static_assert(!std::is_null_pointer<T>(),
+                "CHECK_NOTNULL statements cannot be passed nullptr");
+  if (value == nullptr) {
+    std::exit(1);
+  }
+  return std::forward<T>(value);
+}
+
+// DCHECK_NOTNULL cannot be used in standalone expressions, so add a
+// [[nodiscard]] attribute to prevent this in debug builds. Standalone
+// DCHECK_NOTNULL statements in release builds trigger an unused-value warning.
+template <typename T>
+[[nodiscard]] constexpr T DCheckNotNull(const char* file,
+                                        unsigned line,
+                                        const char* message,
+                                        T&& value) {
+  return CheckNotNull<T>(file, line, message, std::forward<T>(value));
+}
+
+}  // namespace pw::log
+
+// Assert stubs
+#define DCHECK CHECK
+#define DCHECK_EQ CHECK_EQ
+
+#define CHECK(...)
+#define CHECK_EQ(...)
+#define CHECK_GE(...)
+#define CHECK_GT(...)
+#define CHECK_LE(...)
+#define CHECK_LT(...)
diff --git a/pw_kvs/public/pw_kvs/flash.h b/pw_kvs/public/pw_kvs/flash.h
index 5cb80cd..6eecea7 100644
--- a/pw_kvs/public/pw_kvs/flash.h
+++ b/pw_kvs/public/pw_kvs/flash.h
@@ -13,9 +13,9 @@
 // the License.
 #pragma once
 
-#include "pw_kvs/devices/flash_memory.h"
+#include "pw_kvs/flash_memory.h"
 
-namespace pw {
+namespace pw::kvs {
 
 // Writes a buffer which is not guaranteed to be aligned, pads remaining
 // bytes with 0.
@@ -30,4 +30,4 @@
                      FlashPartition::Address address,
                      uint16_t size);
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/flash_memory.h b/pw_kvs/public/pw_kvs/flash_memory.h
index 707f128..d62f794 100644
--- a/pw_kvs/public/pw_kvs/flash_memory.h
+++ b/pw_kvs/public/pw_kvs/flash_memory.h
@@ -14,14 +14,16 @@
 #pragma once
 
 #include <algorithm>
+#include <cinttypes>
+#include <cstring>
 
 #include "pw_kvs/assert.h"
-#include "pw_kvs/logging.h"
-#include "pw_kvs/peripherals/partition_table_entry.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/status_macros.h"
+#include "pw_kvs/partition_table_entry.h"
+#include "pw_log/log.h"
+#include "pw_status/status.h"
 
-namespace pw {
+namespace pw::kvs {
+
 class FlashMemory {
  public:
   // The flash address is in the range of: 0 to FlashSize.
@@ -39,6 +41,8 @@
         sector_start_(sector_start),
         erased_memory_content_(erased_memory_content) {}
 
+  virtual ~FlashMemory() = default;
+
   virtual Status Enable() = 0;
   virtual Status Disable() = 0;
   virtual bool IsEnabled() const = 0;
@@ -72,9 +76,7 @@
 
   // Convert an Address to an MCU pointer, this can be used for memory
   // mapped reads. Return NULL if the memory is not memory mapped.
-  virtual uint8_t* FlashAddressToMcuAddress(Address address) const {
-    return nullptr;
-  }
+  virtual uint8_t* FlashAddressToMcuAddress(Address) const { return nullptr; }
 
   // GetStartSector() is useful for FlashMemory instances where the
   // sector start is not 0. (ex.: cases where there are portions of flash
@@ -137,9 +139,7 @@
   bool IsEnabled() const override { return flash_.IsEnabled(); }
   Status SelfTest() override { return flash_.SelfTest(); }
 
-  Status Erase(Address flash_address, uint32_t num_sectors) override {
-    return Status::UNIMPLEMENTED;
-  }
+  Status Erase(Address, uint32_t) override { return Status::UNIMPLEMENTED; }
 
   Status Read(uint8_t* destination_ram_address,
               Address source_flash_address,
@@ -185,6 +185,8 @@
                       entry.partition_start_sector_index + 1),
         permission_(entry.partition_permission) {}
 
+  virtual ~FlashPartition() = default;
+
   // Erase num_sectors starting at a given address. Blocking call.
   // Address should be on a sector boundary.
   // Returns: OK, on success.
@@ -193,9 +195,14 @@
   //          PERMISSION_DENIED, if partition is read only.
   //          UNKNOWN, on HAL error
   virtual Status Erase(Address address, uint32_t num_sectors) {
-    RETURN_STATUS_IF(permission_ == PartitionPermission::kReadOnly,
-                     Status::PERMISSION_DENIED);
-    RETURN_IF_ERROR(CheckBounds(address, num_sectors * GetSectorSizeBytes()));
+    if (permission_ == PartitionPermission::kReadOnly) {
+      return Status::PERMISSION_DENIED;
+    }
+    if (Status status =
+            CheckBounds(address, num_sectors * GetSectorSizeBytes());
+        !status.ok()) {
+      return status;
+    }
     return flash_.Erase(PartitionToFlashAddress(address), num_sectors);
   }
 
@@ -207,7 +214,9 @@
   virtual Status Read(uint8_t* destination_ram_address,
                       Address source_flash_address,
                       uint32_t len) {
-    RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+    if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+      return status;
+    }
     return flash_.Read(destination_ram_address,
                        PartitionToFlashAddress(source_flash_address),
                        len);
@@ -222,9 +231,13 @@
   virtual Status Write(Address destination_flash_address,
                        const uint8_t* source_ram_address,
                        uint32_t len) {
-    RETURN_STATUS_IF(permission_ == PartitionPermission::kReadOnly,
-                     Status::PERMISSION_DENIED);
-    RETURN_IF_ERROR(CheckBounds(destination_flash_address, len));
+    if (permission_ == PartitionPermission::kReadOnly) {
+      return Status::PERMISSION_DENIED;
+    }
+    if (Status status = CheckBounds(destination_flash_address, len);
+        !status.ok()) {
+      return status;
+    }
     return flash_.Write(PartitionToFlashAddress(destination_flash_address),
                         source_ram_address,
                         len);
@@ -243,24 +256,31 @@
     // function. Using 16 because it's the alignment of encrypted flash.
     const uint8_t kMaxAlignment = 16;
     // Relying on Read() to check address and len arguments.
-    RETURN_STATUS_IF(!is_erased, Status::INVALID_ARGUMENT);
+    if (!is_erased) {
+      return Status::INVALID_ARGUMENT;
+    }
     uint8_t alignment = GetAlignmentBytes();
-    RETURN_STATUS_IF(alignment > kMaxAlignment, Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(kMaxAlignment % alignment, Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(len % alignment, Status::INVALID_ARGUMENT);
+    if (alignment > kMaxAlignment || kMaxAlignment % alignment ||
+        len % alignment) {
+      return Status::INVALID_ARGUMENT;
+    }
 
     uint8_t buffer[kMaxAlignment];
     uint8_t erased_pattern_buffer[kMaxAlignment];
     size_t offset = 0;
-    memset(erased_pattern_buffer,
-           flash_.GetErasedMemoryContent(),
-           sizeof(erased_pattern_buffer));
+    std::memset(erased_pattern_buffer,
+                flash_.GetErasedMemoryContent(),
+                sizeof(erased_pattern_buffer));
     *is_erased = false;
     while (len > 0) {
       // Check earlier that len is aligned, no need to round up
       uint16_t read_size = std::min(static_cast<uint32_t>(sizeof(buffer)), len);
-      RETURN_IF_ERROR(Read(buffer, source_flash_address + offset, read_size));
-      if (memcmp(buffer, erased_pattern_buffer, read_size)) {
+      if (Status status =
+              Read(buffer, source_flash_address + offset, read_size);
+          !status.ok()) {
+        return status;
+      }
+      if (std::memcmp(buffer, erased_pattern_buffer, read_size)) {
         // Detected memory chunk is not entirely erased
         return Status::OK;
       }
@@ -301,8 +321,11 @@
  protected:
   Status CheckBounds(Address address, uint32_t len) const {
     if (address + len > GetSizeBytes()) {
-      LOG(ERROR) << "Attempted out-of-bound flash memory access (address:"
-                 << address << " length:" << len << ")";
+      PW_LOG_ERROR(
+          "Attempted out-of-bound flash memory access (address: %" PRIu32
+          " length: %zu)",
+          address,
+          len);
       return Status::INVALID_ARGUMENT;
     }
     return Status::OK;
@@ -331,14 +354,20 @@
         sector_count_(sector_count) {}
 
   Status Erase(Address address, uint32_t num_sectors) override {
-    RETURN_IF_ERROR(CheckBounds(address, num_sectors * GetSectorSizeBytes()));
+    if (Status status =
+            CheckBounds(address, num_sectors * GetSectorSizeBytes());
+        !status.ok()) {
+      return status;
+    }
     return partition_->Erase(ParentAddress(address), num_sectors);
   }
 
   Status Read(uint8_t* destination_ram_address,
               Address source_flash_address,
               uint32_t len) override {
-    RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+    if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+      return status;
+    }
     return partition_->Read(
         destination_ram_address, ParentAddress(source_flash_address), len);
   }
@@ -346,7 +375,10 @@
   Status Write(Address destination_flash_address,
                const uint8_t* source_ram_address,
                uint32_t len) override {
-    RETURN_IF_ERROR(CheckBounds(destination_flash_address, len));
+    if (Status status = CheckBounds(destination_flash_address, len);
+        !status.ok()) {
+      return status;
+    }
     return partition_->Write(
         ParentAddress(destination_flash_address), source_ram_address, len);
   }
@@ -354,7 +386,9 @@
   Status IsChunkErased(Address source_flash_address,
                        uint32_t len,
                        bool* is_erased) override {
-    RETURN_IF_ERROR(CheckBounds(source_flash_address, len));
+    if (Status status = CheckBounds(source_flash_address, len); !status.ok()) {
+      return status;
+    }
     return partition_->IsChunkErased(
         ParentAddress(source_flash_address), len, is_erased);
   }
@@ -374,4 +408,4 @@
   const uint32_t sector_count_;
 };
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/in_memory_fake_flash.h b/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
index a67c770..d2ea67c 100644
--- a/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
+++ b/pw_kvs/public/pw_kvs/in_memory_fake_flash.h
@@ -15,11 +15,10 @@
 
 #include <array>
 
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/status.h"
-#include "pw_kvs/status_macros.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
 
-namespace pw {
+namespace pw::kvs {
 
 // This creates a buffer which mimics the behaviour of flash (requires erase,
 // before write, checks alignments, and is addressed in sectors).
@@ -40,12 +39,15 @@
   //          INVALID_ARGUMENT, if address or sector count is invalid.
   //          UNKNOWN, on HAL error
   Status Erase(Address addr, uint32_t num_sectors) override {
-    RETURN_STATUS_IF(addr % GetSectorSizeBytes() != 0,
-                     Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(
-        addr / GetSectorSizeBytes() + num_sectors > GetSectorCount(),
-        Status::UNKNOWN);
-    RETURN_STATUS_IF(addr % GetAlignmentBytes() != 0, Status::INVALID_ARGUMENT);
+    if (addr % GetSectorSizeBytes() != 0) {
+      return Status::INVALID_ARGUMENT;
+    }
+    if (addr / GetSectorSizeBytes() + num_sectors > GetSectorCount()) {
+      return Status::UNKNOWN;
+    }
+    if (addr % GetAlignmentBytes() != 0) {
+      return Status::INVALID_ARGUMENT;
+    }
     memset(&buffer_[addr], 0xFF, GetSectorSizeBytes() * num_sectors);
     return Status::OK;
   }
@@ -57,9 +59,9 @@
   Status Read(uint8_t* dest_ram_addr,
               Address source_flash_addr,
               uint32_t len) override {
-    RETURN_STATUS_IF(
-        (source_flash_addr + len) >= GetSectorCount() * GetSizeBytes(),
-        Status::INVALID_ARGUMENT);
+    if ((source_flash_addr + len) >= GetSectorCount() * GetSizeBytes()) {
+      return Status::INVALID_ARGUMENT;
+    }
     memcpy(dest_ram_addr, &buffer_[source_flash_addr], len);
     return Status::OK;
   }
@@ -71,15 +73,16 @@
   Status Write(Address dest_flash_addr,
                const uint8_t* source_ram_addr,
                uint32_t len) override {
-    RETURN_STATUS_IF(
-        (dest_flash_addr + len) >= GetSectorCount() * GetSizeBytes(),
-        Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(dest_flash_addr % GetAlignmentBytes() != 0,
-                     Status::INVALID_ARGUMENT);
-    RETURN_STATUS_IF(len % GetAlignmentBytes() != 0, Status::INVALID_ARGUMENT);
+    if ((dest_flash_addr + len) >= GetSectorCount() * GetSizeBytes() ||
+        dest_flash_addr % GetAlignmentBytes() != 0 ||
+        len % GetAlignmentBytes() != 0) {
+      return Status::INVALID_ARGUMENT;
+    }
     // Check in erased state
     for (unsigned i = 0; i < len; i++) {
-      RETURN_STATUS_IF(buffer_[dest_flash_addr + i] != 0xFF, Status::UNKNOWN);
+      if (buffer_[dest_flash_addr + i] != 0xFF) {
+        return Status::UNKNOWN;
+      }
     }
     memcpy(&buffer_[dest_flash_addr], source_ram_addr, len);
     return Status::OK;
@@ -89,4 +92,4 @@
   std::array<uint8_t, kSectorCount * kSectorSize> buffer_;
 };
 
-}  // namespace pw
+}  // namespace pw::kvs
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index dca6507..d9bb34f 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -16,17 +16,37 @@
 #include <algorithm>
 #include <type_traits>
 
-#include "pw_kvs/devices/flash_memory.h"
-#include "pw_kvs/logging.h"
-#include "pw_kvs/os/mutex.h"
-#include "pw_kvs/status.h"
+#include "pw_kvs/flash_memory.h"
+#include "pw_status/status.h"
 
-namespace pw {
+namespace cfg {
+
+// KVS requires a temporary buffer for some operations, this config allows
+// tuning the buffer size. This is a trade-off between a value which is large
+// and therefore requires more RAM, or having a value which is small which will
+// result in some operations taking longer, as the operations are broken into
+// smaller chunks.
+// NOTE: This value can not be smaller then the flash alignment, and it will
+//       round the size down to be a multiple of the flash alignment for all
+//       operations.
+inline constexpr size_t kKvsBufferSize = 64;
+
+// This represents the maximum amount of keys which can be in the KVS at any
+// given time.
+inline constexpr uint8_t kKvsMaxKeyCount = 50;
+
+// This is the maximum amount of sectors the KVS can operate on, an invalid
+// value will cause an error during enable.
+inline constexpr uint32_t kKvsMaxSectorCount = 20;
+
+}  // namespace cfg
+
+namespace pw::kvs {
 
 // This object is very large and should not be placed on the stack.
 class KeyValueStore {
  public:
-  KeyValueStore(FlashPartition* partition) : partition_(*partition) {}
+  constexpr KeyValueStore(FlashPartition* partition) : partition_(*partition) {}
 
   // Enable the KVS, scans the sectors of the partition for any current KVS
   // data. Erases and initializes any sectors which are not initialized.
@@ -39,7 +59,7 @@
     if (enabled_ == false) {
       return;
     }
-    os::MutexLock lock(&lock_);
+    // TODO: LOCK MUTEX
     enabled_ = false;
   }
 
@@ -67,9 +87,14 @@
   Status Get(const char* key, T* value) {
     static_assert(std::is_trivially_copyable<T>(), "KVS values must copyable");
     static_assert(!std::is_pointer<T>(), "KVS values cannot be pointers");
+
     uint16_t value_size = 0;
-    RETURN_IF_ERROR(GetValueSize(key, &value_size));
-    RETURN_STATUS_IF(value_size != sizeof(T), Status::INVALID_ARGUMENT);
+    if (Status status = GetValueSize(key, &value_size)) {
+      return status;
+    }
+    if (value_size != sizeof(T)) {
+      return Status::INVALID_ARGUMENT;
+    }
     return Get(key, value, sizeof(T));
   }
 
@@ -107,11 +132,11 @@
   // CleanAll cleans each sector which is currently marked for cleaning.
   // Note: if any data is invalid/corrupt it could be lost.
   Status CleanAll() {
-    os::MutexLock lock(&lock_);
+    // TODO: LOCK MUTEX
     return CleanAllInternal();
   }
   size_t PendingCleanCount() {
-    os::MutexLock lock(&lock_);
+    // TODO: LOCK MUTEX
     size_t ret = 0;
     for (size_t i = 0; i < SectorCount(); i++) {
       ret += sector_space_remaining_[i] == 0 ? 1 : 0;
@@ -345,7 +370,7 @@
   }
 
   FlashPartition& partition_;
-  os::Mutex lock_;
+  // TODO: MUTEX
   bool enabled_ = false;
   uint8_t alignment_bytes_ = 0;
   uint64_t next_sector_clean_order_ = 0;
@@ -353,7 +378,7 @@
   // Free space available in each sector, set to 0 when clean is pending/active
   uint32_t sector_space_remaining_[kSectorCountMax] = {0};
   uint64_t sector_clean_order_[kSectorCountMax] = {kSectorCleanNotPending};
-  KeyMap key_map_[kListCapacityMax] = {{{0}}};
+  KeyMap key_map_[kListCapacityMax] = {};
   KeyIndex map_size_ = 0;
 
   // +1 for nul-terminator since keys are stored as Length + Value and no nul
@@ -363,4 +388,4 @@
   uint8_t temp_buffer_[cfg::kKvsBufferSize] = {0};
 };
 
-}  // namespace pw
+}  // namespace pw::kvs