Arduino KVComm  master
Key-Value pair communication library for Arduino
KV_Iterator.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #ifdef ARDUINO
4 
5 #include <KVComm/include/KVComm/KV_Error.hpp> // KV_ERROR
6 #include <KVComm/include/KVComm/KV_Helpers.hpp> // nextWord, roundUpToWordSizeMultiple
7 #include <KVComm/include/KVComm/KV_Types.hpp> // KV_Type<T>
8 
9 #include <AH/STL/array> // std::array
10 #include <AH/STL/cstddef> // size_t
11 #include <AH/STL/cstdint> // uint8_t, uint16_t
12 #include <AH/STL/iterator> // iterator traits
13 #include <AH/STL/vector> // std::vector
14 
15 #include <WString.h>
16 
17 #else
18 
19 #include <KVComm/KV_Error.hpp> // KV_ERROR
20 #include <KVComm/KV_Helpers.hpp> // nextWord, roundUpToWordSizeMultiple
21 #include <KVComm/KV_Types.hpp> // KV_Type<T>
22 
23 #include <array> // std::array
24 #include <cstddef> // size_t
25 #include <cstdint> // uint8_t, uint16_t
26 #include <iterator> // iterator traits
27 #include <vector> // std::vector
28 
29 #endif
30 
33 
40 class KV_Iterator {
43  public:
44  KV_Iterator(const uint8_t *buffer, size_t length)
45  : buffer(buffer), bufferSize(length) {}
46 
47  class KV {
48  public:
50  KV(const uint8_t *buffer) : buffer(buffer) {}
52  uint8_t getTypeID() const { return buffer[1]; }
54  uint16_t getIDLength() const { return buffer[0]; }
56  uint16_t getDataLength() const {
57  return (buffer[2] << 0) | (buffer[3] << 8);
58  }
60  const uint8_t *getBuffer() const { return buffer; }
62  const char *getID() const { return (const char *) buffer + 4; }
64  const uint8_t *getData() const {
65  return buffer + nextWord(getIDLength()) + 4;
66  }
68  explicit operator bool() const { return buffer != nullptr; }
69 
71  template <class T>
72  uint16_t getArraySize() const {
74  }
75 
95  template <class T>
96  void get(T &t, size_t index = 0) const {
97  if (!*this) {
98  KV_ERROR(F("Trying to extract data from non-existent entry"),
99  0x7566);
100  return; // LCOV_EXCL_LINE
101  }
102  if (!checkType<T>())
103  return; // LCOV_EXCL_LINE
104  if (index * KV_Type<T>::getLength() >= getDataLength()) {
105  KV_ERROR(F("Index out of range"), 0x7564);
106  return; // LCOV_EXCL_LINE
107  }
108  auto readlocation = getData() + KV_Type<T>::getLength() * index;
109  KV_Type<T>::readFromBuffer(t, readlocation);
110  }
111 
131  template <class T>
132  T getAs(size_t index = 0) const {
133  T t;
134  get(t, index);
135  return t;
136  }
137 
153  template <class T>
154  std::vector<T> getVector() const {
155  if (!*this) {
156  KV_ERROR(F("Trying to extract data from non-existent entry"),
157  0x7566);
158  return {}; // LCOV_EXCL_LINE
159  }
160  if (!checkType<T>())
161  return {}; // LCOV_EXCL_LINE
162  size_t size = getDataLength() / KV_Type<T>::getLength();
163  std::vector<T> result(size);
164  auto readlocation = getData();
165  for (T &t : result) {
166  KV_Type<T>::readFromBuffer(t, readlocation);
167  readlocation += KV_Type<T>::getLength();
168  }
169  return result;
170  }
171 
192  template <class T, size_t N>
193  std::array<T, N> getArray() const {
194  if (!*this) {
195  KV_ERROR(F("Trying to extract data from non-existent entry"),
196  0x7566);
197  return {{}}; // LCOV_EXCL_LINE
198  }
199  if (!checkType<T>())
200  return {{}}; // LCOV_EXCL_LINE
201  if (N * KV_Type<T>::getLength() != getDataLength()) {
202  KV_ERROR(F("Incorrect length"), 0x7565);
203  return {{}}; // LCOV_EXCL_LINE
204  }
205  std::array<T, N> result;
206  auto readlocation = getData();
207  for (T &t : result) {
208  KV_Type<T>::readFromBuffer(t, readlocation);
209  readlocation += KV_Type<T>::getLength();
210  }
211  return result;
212  }
213 
214 #if !defined(ARDUINO) || defined(DOXYGEN)
215 
229  std::string getString() const;
230 #else
231  String getString() const;
232 #endif
233 
245  template <class T>
246  bool hasType() const {
247  return this->getTypeID() == KV_Type<T>::getTypeID();
248  }
249 
250  protected:
252  template <class T>
253  bool checkType() const {
254  if (!hasType<T>()) {
255  KV_ERROR(F("Type mismatch (typeid=")
256  << getTypeID() << F(", conversion requested to ")
257  << KV_Type<T>::getTypeID() << ')',
258  0x7563);
259  return false; // LCOV_EXCL_LINE
260  }
261  return true;
262  }
263 
264  private:
265  const uint8_t *buffer;
266  };
267 
268  class iterator {
269  public:
271  iterator();
276  iterator(const uint8_t *buffer, size_t length);
277 
279  iterator &operator++();
280 #if 0
281  bool operator==(const iterator &other) const;
284 #endif
285  bool operator!=(const iterator &other) const;
288 
289  const KV &operator*() const { return kv; }
290  const KV *operator->() const { return &kv; }
291 
293  explicit operator bool() const { return !!kv; }
294 
295  using difference_type = void;
296  using value_type = KV;
297  using pointer = KV *;
298  using reference = KV &;
299  using iterator_category = std::input_iterator_tag;
300 
301  protected:
302  void checkLength();
303 
304  private:
307  };
308 
310  iterator begin() const { return {buffer, bufferSize}; }
312  static iterator end() { return {}; }
313 
315  iterator find(const char *key) const;
316 
317  private:
318  const uint8_t *buffer;
319  size_t bufferSize;
320 };
321 
322 /// @}
KV_Iterator
Class for iterating over a dictionary generated by the KV_Builder, used for parsing and for checking ...
Definition: KV_Iterator.hpp:42
KV_Iterator::iterator::operator->
const KV * operator->() const
Definition: KV_Iterator.hpp:290
KV_Iterator::find
iterator find(const char *key) const
Find the entry with the given key (iterates over entire dictionary).
Definition: KV_Iterator.cpp:75
KV_Iterator::KV::getVector
std::vector< T > getVector() const
Get the data of the element as a vector of the given type.
Definition: KV_Iterator.hpp:154
KV_Iterator::iterator::kv
KV kv
Definition: KV_Iterator.hpp:305
KV_Type
Template struct for making types serializable.
Definition: KV_Types.hpp:43
KV_Iterator::KV::getArray
std::array< T, N > getArray() const
Get the data of the element as an array of the given type.
Definition: KV_Iterator.hpp:193
KV_Iterator::KV
Definition: KV_Iterator.hpp:47
KV_Iterator::iterator::iterator_category
std::input_iterator_tag iterator_category
Definition: KV_Iterator.hpp:299
KV_Type::readFromBuffer
static T readFromBuffer(const uint8_t *buffer)
KV_Iterator::iterator::checkLength
void checkLength()
Definition: KV_Iterator.cpp:47
KV_Iterator::KV::checkType
bool checkType() const
Assert that the type of this entry matches the given type T.
Definition: KV_Iterator.hpp:253
KV_Types.hpp
KV_Type type definitions for fundamental types (int::_t, uint::_t, float, double, bool,...
KV_Iterator::bufferSize
size_t bufferSize
Definition: KV_Iterator.hpp:319
KV_Iterator::iterator::operator*
const KV & operator*() const
Definition: KV_Iterator.hpp:289
KV_Type::getTypeID
constexpr static uint8_t getTypeID()
KV_Iterator::KV::getTypeID
uint8_t getTypeID() const
Get the type ID of the current element.
Definition: KV_Iterator.hpp:52
KV_Iterator::KV::getString
std::string getString() const
Get the character array as an std::string.
Definition: KV_Iterator.cpp:57
nextWord
size_t nextWord(size_t i)
Get the offset of the next 4-byte word.
Definition: KV_Helpers.hpp:18
KV_Iterator::KV::getData
const uint8_t * getData() const
Get a pointer to the data of the current element.
Definition: KV_Iterator.hpp:64
KV_Iterator::KV::getDataLength
uint16_t getDataLength() const
Get the length of the data of the current element.
Definition: KV_Iterator.hpp:56
KV_Iterator::KV::getAs
T getAs(size_t index=0) const
Get the data as the given type.
Definition: KV_Iterator.hpp:132
KV_Iterator::iterator::remainingBufferLength
size_t remainingBufferLength
Definition: KV_Iterator.hpp:306
KV_Iterator::KV::getIDLength
uint16_t getIDLength() const
Get the length of the identifier / key of the current element.
Definition: KV_Iterator.hpp:54
KV_Iterator::KV::KV
KV(const uint8_t *buffer)
Constructor.
Definition: KV_Iterator.hpp:50
KV_Iterator::iterator
Definition: KV_Iterator.hpp:268
KV_Iterator::iterator::operator++
iterator & operator++()
Advance the iterator.
Definition: KV_Iterator.cpp:26
KV_Iterator::KV::buffer
const uint8_t * buffer
Definition: KV_Iterator.hpp:265
KV_Iterator::KV::getBuffer
const uint8_t * getBuffer() const
Get a pointer to the beginning of the current element.
Definition: KV_Iterator.hpp:60
KV_Iterator::buffer
const uint8_t * buffer
Definition: KV_Iterator.hpp:318
KV_Error.hpp
F
#define F(x)
Definition: KV_Error.hpp:38
KV_Iterator::end
static iterator end()
End/sentinel iterator.
Definition: KV_Iterator.hpp:312
KV_Iterator::iterator::iterator
iterator()
Default constructor. Used as "end" iterator (sentinel).
Definition: KV_Iterator.cpp:19
KV_Iterator::KV::getArraySize
uint16_t getArraySize() const
Get the number of elements in the array of data.
Definition: KV_Iterator.hpp:72
KV_ERROR
#define KV_ERROR(msg, errc)
Throw an error.
Definition: KV_Error.hpp:26
KV_Iterator::KV::getID
const char * getID() const
Get the identifier / key of the current element.
Definition: KV_Iterator.hpp:62
KV_Iterator::iterator::operator!=
bool operator!=(const iterator &other) const
Compare the iterator to the "end" iterator.
Definition: KV_Iterator.cpp:36
KV_Iterator::KV_Iterator
KV_Iterator(const uint8_t *buffer, size_t length)
Definition: KV_Iterator.hpp:44
KV_Helpers.hpp
Helpers for address manipulation used to layout dictionary entries in memory.
AH::operator==
bool operator==(ArraySlice< T1, N1, Reverse1, Const1 > a, ArraySlice< T2, N2, Reverse2, Const2 > b)
Slice == Slice.
Definition: Array.hpp:307
KV_Iterator::KV::hasType
bool hasType() const
Check if the type of this element is the same as the given type.
Definition: KV_Iterator.hpp:246
KV_Iterator::begin
iterator begin() const
Iterator to the first key-value entry of the dictionary.
Definition: KV_Iterator.hpp:310
KV_Iterator::iterator::difference_type
void difference_type
Definition: KV_Iterator.hpp:295
KV_Iterator::KV::get
void get(T &t, size_t index=0) const
Get the data as the given type.
Definition: KV_Iterator.hpp:96
KV_Type::getLength
constexpr static size_t getLength()