pw_kvs: Define mutable iterator for EntryCache
Template the EntryCache iterator to support both const and mutable
iterators.
Change-Id: I1f2102325414d9703ecc0afc26633fec22b16a3c
diff --git a/pw_kvs/entry_cache_test.cc b/pw_kvs/entry_cache_test.cc
index 3b9d1a1..615d78c 100644
--- a/pw_kvs/entry_cache_test.cc
+++ b/pw_kvs/entry_cache_test.cc
@@ -166,6 +166,34 @@
}
}
+TEST_F(EmptyEntryCache, Iterator_Mutable_CanModify) {
+ entries_.AddNew(kDescriptor, 1);
+ EntryCache::iterator it = entries_.begin();
+
+ static_assert(kRedundancy > 1);
+ it->AddNewAddress(1234);
+
+ EXPECT_EQ(1u, it->first_address());
+ EXPECT_EQ(1u, (*it).addresses()[0]);
+ EXPECT_EQ(1234u, it->addresses()[1]);
+}
+
+TEST_F(EmptyEntryCache, Iterator_Const) {
+ entries_.AddNew(kDescriptor, 99);
+ EntryCache::const_iterator it = entries_.cbegin();
+
+ EXPECT_EQ(99u, (*it).first_address());
+ EXPECT_EQ(99u, it->first_address());
+}
+
+TEST_F(EmptyEntryCache, Iterator_Const_CanBeAssignedFromMutable) {
+ entries_.AddNew(kDescriptor, 99);
+ EntryCache::const_iterator it = entries_.begin();
+
+ EXPECT_EQ(99u, (*it).first_address());
+ EXPECT_EQ(99u, it->first_address());
+}
+
constexpr auto kTheEntry = AsBytes(uint32_t(12345), // magic
uint32_t(0), // checksum
uint8_t(0), // alignment (16 B)
diff --git a/pw_kvs/key_value_store.cc b/pw_kvs/key_value_store.cc
index 13708ae..d0ab512 100644
--- a/pw_kvs/key_value_store.cc
+++ b/pw_kvs/key_value_store.cc
@@ -381,7 +381,7 @@
}
KeyValueStore::iterator KeyValueStore::begin() const {
- internal::EntryCache::iterator cache_iterator = entry_cache_.begin();
+ internal::EntryCache::const_iterator cache_iterator = entry_cache_.begin();
// Skip over any deleted entries at the start of the descriptor list.
while (cache_iterator != entry_cache_.end() &&
cache_iterator->state() != EntryState::kValid) {
diff --git a/pw_kvs/public/pw_kvs/internal/entry_cache.h b/pw_kvs/public/pw_kvs/internal/entry_cache.h
index 99c2008..48688a6 100644
--- a/pw_kvs/public/pw_kvs/internal/entry_cache.h
+++ b/pw_kvs/public/pw_kvs/internal/entry_cache.h
@@ -16,6 +16,7 @@
#include <cstddef>
#include <cstdint>
#include <string_view>
+#include <type_traits>
#include "pw_containers/vector.h"
#include "pw_kvs/flash_memory.h"
@@ -74,7 +75,61 @@
// Tracks entry metadata. Combines KeyDescriptors and with their associated
// addresses.
class EntryCache {
+ private:
+ enum Constness : bool { kMutable = false, kConst = true };
+
+ // Iterates over the EntryCache as EntryMetadata objects.
+ template <Constness kIsConst>
+ class Iterator {
+ public:
+ using value_type =
+ std::conditional_t<kIsConst, const EntryMetadata, EntryMetadata>;
+
+ Iterator& operator++() {
+ ++metadata_.descriptor_;
+ return *this;
+ }
+ Iterator& operator++(int) { return operator++(); }
+
+ // Updates the internal EntryMetadata object.
+ value_type& operator*() const {
+ metadata_.addresses_ = entry_cache_->addresses(
+ metadata_.descriptor_ - entry_cache_->descriptors_.begin());
+ return metadata_;
+ }
+ value_type* operator->() const { return &operator*(); }
+
+ constexpr bool operator==(const Iterator& rhs) const {
+ return metadata_.descriptor_ == rhs.metadata_.descriptor_;
+ }
+ constexpr bool operator!=(const Iterator& rhs) const {
+ return metadata_.descriptor_ != rhs.metadata_.descriptor_;
+ }
+
+ // Allow non-const to convert to const.
+ operator Iterator<kConst>() const {
+ return {entry_cache_, metadata_.descriptor_};
+ }
+
+ private:
+ friend class EntryCache;
+
+ using Cache = std::conditional_t<kIsConst, const EntryCache, EntryCache>;
+
+ constexpr Iterator(Cache* entry_cache, KeyDescriptor* descriptor)
+ : entry_cache_(entry_cache), metadata_(*descriptor, {}) {}
+
+ Cache* entry_cache_;
+
+ // Mark this mutable so it can be updated in the const operator*() method.
+ // This allows lazy updating of the EntryMetadata.
+ mutable EntryMetadata metadata_;
+ };
+
public:
+ using iterator = Iterator<kMutable>;
+ using const_iterator = Iterator<kConst>;
+
using Address = FlashPartition::Address;
// The type to use for an address list with the specified number of entries
@@ -152,47 +207,13 @@
// The maximum number of entries supported by this EntryCache.
size_t max_entries() const { return descriptors_.max_size(); }
- // Iterates over the EntryCache as EntryMetadata objects.
- class iterator {
- public:
- iterator& operator++() {
- ++metadata_.descriptor_;
- return *this;
- }
- iterator& operator++(int) { return operator++(); }
+ iterator begin() { return {this, descriptors_.begin()}; }
+ const_iterator begin() const { return cbegin(); }
+ const_iterator cbegin() const { return {this, descriptors_.begin()}; }
- // Updates the EntryMetadata object.
- const EntryMetadata& operator*() const {
- metadata_.addresses_ = entry_cache_.addresses(
- metadata_.descriptor_ - entry_cache_.descriptors_.begin());
- return metadata_;
- }
- const EntryMetadata* operator->() const { return &operator*(); }
-
- constexpr bool operator==(const iterator& rhs) const {
- return metadata_.descriptor_ == rhs.metadata_.descriptor_;
- }
- constexpr bool operator!=(const iterator& rhs) const {
- return metadata_.descriptor_ != rhs.metadata_.descriptor_;
- }
-
- private:
- friend class EntryCache;
-
- constexpr iterator(const EntryCache* entry_cache, KeyDescriptor* descriptor)
- : entry_cache_(*entry_cache), metadata_(*descriptor, {}) {}
-
- const EntryCache& entry_cache_;
-
- // Mark this mutable so it can be updated in the const operator*() method.
- // This allows lazy updating of the EntryMetadata.
- mutable EntryMetadata metadata_;
- };
-
- using const_iterator = iterator;
-
- iterator begin() const { return iterator(this, descriptors_.begin()); }
- iterator end() const { return iterator(this, descriptors_.end()); }
+ iterator end() { return {this, descriptors_.end()}; }
+ const_iterator end() const { return cend(); }
+ const_iterator cend() const { return {this, descriptors_.end()}; }
private:
int FindIndex(uint32_t key_hash) const;
diff --git a/pw_kvs/public/pw_kvs/key_value_store.h b/pw_kvs/public/pw_kvs/key_value_store.h
index fe705b6..69193e4 100644
--- a/pw_kvs/public/pw_kvs/key_value_store.h
+++ b/pw_kvs/public/pw_kvs/key_value_store.h
@@ -213,13 +213,13 @@
friend class iterator;
constexpr Item(const KeyValueStore& kvs,
- const internal::EntryCache::iterator& iterator)
+ const internal::EntryCache::const_iterator& iterator)
: kvs_(kvs), iterator_(iterator), key_buffer_{} {}
void ReadKey();
const KeyValueStore& kvs_;
- internal::EntryCache::iterator iterator_;
+ internal::EntryCache::const_iterator iterator_;
// Buffer large enough for a null-terminated version of any valid key.
std::array<char, internal::Entry::kMaxKeyLength + 1> key_buffer_;
@@ -253,7 +253,7 @@
friend class KeyValueStore;
constexpr iterator(const KeyValueStore& kvs,
- const internal::EntryCache::iterator& iterator)
+ const internal::EntryCache::const_iterator& iterator)
: item_(kvs, iterator) {}
Item item_;