fprime/Fw/DataStructures/ArraySetOrMapImpl.hpp
Rob Bocchino bdade025d0
Basic data structure library, phase 1 (#3927)
* Revise SDD for SetBase

* Revise SDD for SetBase

* Revise SDD for Fw/DataStructures

* Revise SDD for FifoQueue

* Revise SDD for Fw/DataStructures

* Revise SDD for MapBase

* Revise SDD for StackBase

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Add StackBase.hpp

* Add ExternalStack.hpp

* Add Stack.hpp

* Add ExternalStackTest

* Revise Stack tests

* Revise ExternalStack

* Revise ExternalStackTest

* Revise ExternalStackTest

* Revise ExternalStackTest

* Revise ExternalStackTest

* Add StackTest

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Add MapIterator

* Add SetIterator

* Add SetOrMapIterator

* Add MapBase.hpp

* Revise SDD for Fw/DataStructures

* Revise SDD for ArraySetOrMapImpl

* Revise SDD for ArraySetOrMapImpl

* Revise SDD for ExternalArray

* Revise SDD for Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise MapBase

* Revise MapBase

* Revise comments

* Revise SDD for ArraySetOrMapImpl

* Revise Fw/DataStructures

* Add ArraySetOrMapImpl

* Add ExternalArrayMap

* Revise ExternalArrayMap

* Revise Fw/DataStructures

* Revise SetBase

* Revise SDD for Fw/DataStructures

* Revise SDD for ExternalArraySet

* Revise SDD for ExternalArraySet

* Revise SDD for ArraySetOrMapImpl

* Revise Fw/DataStructures

* Revise SDD for Fw/DataStructures

* Revise Fw/DataStructures tests

* Revise unit tests for Fw/DataStructures

* Revise tests for ArraySetOrMapImpl

* Revise unit tests for Fw/DataStructures

* Revise unit tests for Fw/DataStructures

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for ArraySetOrMapImpl

* Revise unit tests for Fw/DataStructures

* Revise SDD for SetOrMapIterator

* Add ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise design for sets and maps

* Revert changes to design

* Revise unit tests for Fw/DataStructures

* Revise unit tests for Fw/DataStructures

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise unit tests for ArraySetOrMapImpl

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest and MapTest

* Revise MapTestScenarios

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise ExternalArrayMapTest

* Revise array set and map

Remove at function from interface.
It breaks the array or set abstraction.
It provides little value, since one can use the iterator
provided by SetBase or MapBase to range over the elements.

* Revise ExternalArrayMapTest

* Add ExternalArraySetTest

* Revise ExternalArraySet and ExternalArrayMap

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest

* Revise ExternalArraySetTest and ExternalArrayMapTest

* Revise ArraySetOrMapImplTest

* Revise ExternalArrayMapTest

* Revise ExternalArraySetTest

* Revise SDD for ArrayMap

* Revise SDD for ArraySet

* Revise SDD for ArraySet

* Add ArrayMap

* Revise ArrayMapTest

* Revise Fw/DataStructures

* Revise SDDs for ArrayMap and ArraySet

* Revise Fw/DataStructures

* Refactor map test scenarios

* Refactor data structures tests

* Refactor SetTestScenarios

* Refactor FifoQueueTestScenarios

* Refactor ExternalFifoQueueTest

* Revise Fifo Queue tests

* Refactor ExternalFifoQueueTest

* Revise comments

* Revise Stack tests

* Revise Stack tests

* Refactor Stack tests

* Revise Stack tests

* Revise Array

Remove getStaticSize

* Refactor Fifo tests

* Refactor ArraySetOrMapImplTest

* Revise data structures design

Rename Iterator to Entry

* Revise data structures implementation

Rename Iterator to Entry

* Revise data structures impl and test

Rename Iterator to Entry throughout

* Revise data structures implementation

Rename SetOrMapEntry to SetOrMapImplEntry

* Revise data structure implementation

Rename Entry to ImplEntry

* Revise data structures design

Rename symbols to match implementation

* Revise design for data structures

Add ConstIterator to Map

* Revise ArraySetOrMapImpl

Add ConstIterator

* Add iterators to DS implementation

* Revise map iteration

* Revise unit tests

Use iterators for maps

* Revise iterators

* Revise iterators

* Rename MapEntry to MapConstEntry

* Revise map interface

* Rename SetOrMapImplEntry to SetOrMapImplConstEntry

* Revert "Rename SetOrMapImplEntry to SetOrMapImplConstEntry"

This reverts commit cc6371d03c8f65fa130212d589812cf4ab3714fe.

* Rename SetEntry to SetConstEntry

* Add SetConstIterator

* Revise SetBase and unit tests

Use iterators

* Revise set interface

* Revise comments

* Reformat code

* Revise array set and map impl

Remove forward links

* Revise data structures tests

* Revise Set iterator

* Remove SetConstEntry

* Refactor SetOrMapImplEntry

* Pull in changes from rb-tree branch

* Revise MapBase

* Revise MapBase and docs

* Revise MapBase

* Revise MapBase

* Revise iterators

* Revise MapConstIterator docs

* Rename MapConstEntry to MapEntry

* Revise MapEntry

* Fix MapBase docs

* Revise MapConstIterator

* Revise MapEntry

* Revise MapConstIterator docs

* Revise docs for ExternalArrayMap

* Revise ArrayMap docs

* Revise ArraySetOrMapImpl

* Revise SetOrMapImplEntry

* Revise MapEntry

* Revise map and set interfaces

* Revert changes to map interface

* Rename MapEntry to MapEntryBase

* Revise type aliases

* Reformat code

* Revise SetBase

* Revise map interface

* Revise set and map interface

* Revise ExternalArraySet docs

* Revise ArraySet

* Revise ArraySet docs

* Revise SetConstIterator

* Revise SetBase

* Revise SetBase docs

* Revise SetBase

* Revise ArraySet

* Revise ArraySet docs

* Revise ExternalArraySet docs

* Add SetOrMapImplEntry

* Revise ArraySetOrMapImpl

* Revise Fw/DataStructures

Reformat code

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise Fw/DataStructures

Fix compile errors on Linux

* Fix comments

* Revise Fw/DataStructures

Fix compile errors on Linux

* Revise ArrayMap docs

* Remove helper scripts

* Revise tests for Fw/DataStructures

* Fix spelling

* Fix Markdown link

* Fix uninitialized variable in test

* Fix uninitialized variable in test

* Fix "spelling"

Why is the spelling check enforcing arbitrary rules of style?

* Fix comments

* Revise tests for ArraySetOrMapImpl

* Revise comment

* Revise ArraySetOrMap impl

* Revise formatting

* Revise docs

* Revise docs for Fw/DataStructures

* Revise Array and ExternalArray

Add static assertions

* Revise FifoQueue and Stack

Add static assertions

* Revise ArraySet and ArrayMap

Add static assertions

* Revise ArrayMap tests

* Revise ExternalArraySet tests

* Refactor ArraySetTest

* Revise array initialization

* Revise comments

* Revise Array initialization

* Revise Array design and implementation

* Revert changes to Fw/DataStructures

* Revise Array

* Revise Array

* Revise Array

* Fix formatting

* Add SizedContainer base class

* Revise StackBase

Make it inherit from SizedContainer
Revise stack tests

* Revise MapBase

Make it inherit from SizedContainer
Revise tests

* Revise SetBase

Make it inherit from SizedContainer
Revise tests

* Revise DataStructures design

Add SizedContainer

* Revise SDD for DataStructures

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Revise DataStructures design

* Fix spelling

* Revise zero-arg constructor for Array

* Revise Array interface

Make it consistent with the arrays generated by FPP

* Fix to assertion
2025-08-21 13:56:35 -07:00

290 lines
9.9 KiB
C++

// ======================================================================
// \title ArraySetOrMapImpl
// \author bocchino
// \brief An array-based implementation of a set or map
// ======================================================================
#ifndef Fw_ArraySetOrMapImpl_HPP
#define Fw_ArraySetOrMapImpl_HPP
#include "Fw/DataStructures/ExternalArray.hpp"
#include "Fw/DataStructures/SetOrMapImplConstIterator.hpp"
#include "Fw/DataStructures/SetOrMapImplEntry.hpp"
#include "Fw/Types/Assert.hpp"
#include "Fw/Types/SuccessEnumAc.hpp"
namespace Fw {
template <typename KE, typename VN>
class ArraySetOrMapImpl final {
// ----------------------------------------------------------------------
// Friend class for testing
// ----------------------------------------------------------------------
template <typename KK, typename VV>
friend class ArraySetOrMapImplTester;
public:
// ----------------------------------------------------------------------
// Public types
// ----------------------------------------------------------------------
//! The type of an entry in the set or map
using Entry = SetOrMapImplEntry<KE, VN>;
//! Const iterator
class ConstIterator final : public SetOrMapImplConstIterator<KE, VN> {
public:
using ImplKind = typename SetOrMapImplConstIterator<KE, VN>::ImplKind;
public:
//! Default constructor
ConstIterator() {}
//! Constructor providing the implementation
ConstIterator(const ArraySetOrMapImpl<KE, VN>& impl) : SetOrMapImplConstIterator<KE, VN>(), m_impl(&impl) {}
//! Copy constructor
ConstIterator(const ConstIterator& it)
: SetOrMapImplConstIterator<KE, VN>(), m_impl(it.m_impl), m_index(it.m_index) {}
//! Destructor
~ConstIterator() override = default;
public:
//! Copy assignment operator
ConstIterator& operator=(const ConstIterator& it) {
this->m_impl = it.m_impl;
this->m_index = it.m_index;
return *this;
}
//! Equality comparison operator
bool compareEqual(const ConstIterator& it) const {
bool result = false;
if ((this->m_impl == nullptr) && (it.m_impl == nullptr)) {
result = true;
} else if (this->m_impl == it.m_impl) {
result |= (this->m_index == it.m_index);
result |= (!this->isInRange() and !it.isInRange());
}
return result;
}
//! Return the impl kind
//! \return The impl kind
ImplKind implKind() const override { return ImplKind::ARRAY; }
//! Get the set or map impl entry pointed to by this iterator
//! \return The set or map impl entry
const Entry& getEntry() const override {
FW_ASSERT(this->m_impl != nullptr);
FW_ASSERT(this->isInRange(), static_cast<FwAssertArgType>(this->m_index),
static_cast<FwAssertArgType>(this->m_impl->m_size));
return this->m_impl->m_entries[this->m_index];
}
//! Increment operator
void increment() override {
if (this->isInRange()) {
this->m_index++;
}
}
//! Check whether the iterator is in range
bool isInRange() const override {
FW_ASSERT(this->m_impl != nullptr);
return this->m_index < this->m_impl->m_size;
}
//! Set the iterator to the end value
void setToEnd() {
FW_ASSERT(this->m_impl != nullptr);
this->m_index = this->m_impl->m_size;
}
private:
//! The implementation over which to iterate
const ArraySetOrMapImpl<KE, VN>* m_impl = nullptr;
//! The current iteration index
FwSizeType m_index = 0;
};
public:
// ----------------------------------------------------------------------
// Public constructors and destructors
// ----------------------------------------------------------------------
//! Zero-argument constructor
ArraySetOrMapImpl() = default;
//! Constructor providing typed backing storage.
//! entries must point to at least capacity elements of type Entry.
ArraySetOrMapImpl(Entry* entries, //!< The entries
FwSizeType capacity //!< The capacity
) {
this->setStorage(entries, capacity);
}
//! Constructor providing untyped backing storage.
//! data must be aligned according to getByteArrayAlignment().
//! data must contain at least getByteArraySize(capacity) bytes.
ArraySetOrMapImpl(ByteArray data, //!< The data
FwSizeType capacity //!< The capacity
) {
this->setStorage(data, capacity);
}
//! Copy constructor
ArraySetOrMapImpl(const ArraySetOrMapImpl<KE, VN>& impl) { *this = impl; }
//! Destructor
~ArraySetOrMapImpl() = default;
public:
// ----------------------------------------------------------------------
// Public member functions
// ----------------------------------------------------------------------
//! operator=
ArraySetOrMapImpl<KE, VN>& operator=(const ArraySetOrMapImpl<KE, VN>& impl) {
if (&impl != this) {
m_entries = impl.m_entries;
m_size = impl.m_size;
}
return *this;
}
//! Get the begin iterator
ConstIterator begin() const { return ConstIterator(*this); }
//! Clear the set or map
void clear() { this->m_size = 0; }
//! Get the end iterator
ConstIterator end() const {
auto it = begin();
it.setToEnd();
return it;
}
//! Find a value associated with a key in the map or an element in a set
//! \return SUCCESS if the item was found
Success find(const KE& keyOrElement, //!< The key or element
VN& valueOrNil //!< The value or Nil
) const {
auto status = Success::FAILURE;
for (FwSizeType i = 0; i < this->m_size; i++) {
const auto& e = this->m_entries[i];
if (e.getKey() == keyOrElement) {
valueOrNil = e.getValue();
status = Success::SUCCESS;
break;
}
}
return status;
}
//! Get the capacity of the set or map (max number of entries)
//! \return The capacity
FwSizeType getCapacity() const { return this->m_entries.getSize(); }
//! Get the size (number of entries)
//! \return The size
FwSizeType getSize() const { return this->m_size; }
//! Insert an element in the set or a (key, value) pair in the map
//! \return SUCCESS if there is room in the set or map
Success insert(const KE& keyOrElement, //!< The key or element
const VN& valueOrNil //!< The value or Nil
) {
auto status = Success::FAILURE;
for (FwSizeType i = 0; i < this->m_size; i++) {
auto& e = this->m_entries[i];
if (e.getKey() == keyOrElement) {
e.setValueOrNil(valueOrNil);
status = Success::SUCCESS;
break;
}
}
if ((status == Success::FAILURE) && (this->m_size < this->getCapacity())) {
this->m_entries[this->m_size] = Entry(keyOrElement, valueOrNil);
this->m_size++;
status = Success::SUCCESS;
}
return status;
}
//! Remove an element from the set or a (key, value) pair from the map
//! \return SUCCESS if the key or element was there
Success remove(const KE& keyOrElement, //!< The key or element
VN& valueOrNil //!< The value or Nil
) {
auto status = Success::FAILURE;
for (FwSizeType i = 0; i < this->m_size; i++) {
if (this->m_entries[i].getKey() == keyOrElement) {
valueOrNil = this->m_entries[i].getValue();
if (i < this->m_size - 1) {
this->m_entries[i] = this->m_entries[this->m_size - 1];
}
this->m_size--;
status = Success::SUCCESS;
break;
}
}
return status;
}
//! Set the backing storage (typed data)
//! entries must point to at least capacity elements of type Entry.
void setStorage(Entry* entries, //!< The entries
FwSizeType capacity //!< The capacity
) {
this->m_entries.setStorage(entries, capacity);
this->clear();
}
//! Set the backing storage (untyped data)
//! data must be aligned according to getByteArrayAlignment().
//! data must contain at least getByteArraySize(capacity) bytes.
void setStorage(ByteArray data, //!< The data
FwSizeType capacity //!< The capacity
) {
this->m_entries.setStorage(data, capacity);
this->clear();
}
public:
// ----------------------------------------------------------------------
// Public static functions
// ----------------------------------------------------------------------
//! Get the alignment of the storage for an ArraySetOrMapImpl
//! \return The alignment
static constexpr U8 getByteArrayAlignment() { return ExternalArray<Entry>::getByteArrayAlignment(); }
//! Get the size of the storage for an ExternalArray of the specified capacity,
//! as a byte array
//! \return The byte array size
static constexpr FwSizeType getByteArraySize(FwSizeType capacity //!< The capacity
) {
return ExternalArray<Entry>::getByteArraySize(capacity);
}
private:
// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------
//! The array for storing the set or map entries
ExternalArray<Entry> m_entries = {};
//! The number of entries in the set or map
FwSizeType m_size = 0;
};
} // namespace Fw
#endif