Add a class to handle RDE BEJ dictionary data

This class is used to store RDE BEJ dictionary data transmitted
through bios-bmc circular buffer interface.

Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Idf7726a9f4647885ede615229d507f233ffb13c5
diff --git a/src/rde/rde_dictionary_manager.cpp b/src/rde/rde_dictionary_manager.cpp
new file mode 100644
index 0000000..a71114c
--- /dev/null
+++ b/src/rde/rde_dictionary_manager.cpp
@@ -0,0 +1,125 @@
+#include "rde/rde_dictionary_manager.hpp"
+
+#include <fmt/format.h>
+
+namespace bios_bmc_smm_error_logger
+{
+namespace rde
+{
+
+DictionaryManager::DictionaryManager() : validDictionaryCount(0)
+{}
+
+void DictionaryManager::startDictionaryEntry(
+    uint32_t resourceId, const std::span<const uint8_t> data)
+{
+    // Check whether the resourceId is already available.
+    auto itemIt = dictionaries.find(resourceId);
+    if (itemIt == dictionaries.end())
+    {
+        dictionaries[resourceId] =
+            std::make_unique<DictionaryEntry>(false, data);
+        return;
+    }
+
+    // Since we are creating a new dictionary on an existing entry, invalidate
+    // the existing entry.
+    invalidateDictionaryEntry(*itemIt->second);
+
+    // Flush the existing data.
+    itemIt->second->data.clear();
+    itemIt->second->data.insert(itemIt->second->data.begin(), data.begin(),
+                                data.end());
+}
+
+bool DictionaryManager::markDataComplete(uint32_t resourceId)
+{
+    auto itemIt = dictionaries.find(resourceId);
+    if (itemIt == dictionaries.end())
+    {
+        fmt::print(stderr, "Resource ID {} not found.\n", resourceId);
+        return false;
+    }
+    validateDictionaryEntry(*itemIt->second);
+    return true;
+}
+
+bool DictionaryManager::addDictionaryData(uint32_t resourceId,
+                                          const std::span<const uint8_t> data)
+{
+    auto itemIt = dictionaries.find(resourceId);
+    if (itemIt == dictionaries.end())
+    {
+        fmt::print(stderr, "Resource ID {} not found.\n", resourceId);
+        return false;
+    }
+    // Since we are modifying an existing entry, invalidate the existing entry.
+    invalidateDictionaryEntry(*itemIt->second);
+    itemIt->second->data.insert(itemIt->second->data.end(), data.begin(),
+                                data.end());
+    return true;
+}
+
+std::optional<std::span<const uint8_t>>
+    DictionaryManager::getDictionary(uint32_t resourceId)
+{
+    auto itemIt = dictionaries.find(resourceId);
+    if (itemIt == dictionaries.end())
+    {
+        fmt::print(stderr, "Resource ID {} not found.\n", resourceId);
+        return std::nullopt;
+    }
+
+    if (!itemIt->second->valid)
+    {
+        fmt::print(stderr,
+                   "Requested an incomplete dictionary. Resource ID {}\n",
+                   resourceId);
+        return std::nullopt;
+    }
+    return itemIt->second->data;
+}
+
+std::optional<std::span<const uint8_t>>
+    DictionaryManager::getAnnotationDictionary()
+{
+    return getDictionary(annotationResourceId);
+}
+
+uint32_t DictionaryManager::getDictionaryCount()
+{
+    return validDictionaryCount;
+}
+
+void DictionaryManager::invalidateDictionaries()
+{
+    // We won't flush the existing data. The data will be flushed if a new entry
+    // is added for an existing resource ID.
+    for (const auto& element : dictionaries)
+    {
+        element.second->valid = false;
+    }
+    validDictionaryCount = 0;
+}
+
+void DictionaryManager::invalidateDictionaryEntry(DictionaryEntry& entry)
+{
+    // If this is a valid entry, reduce the valid dictionary count.
+    if (entry.valid)
+    {
+        --validDictionaryCount;
+    }
+    entry.valid = false;
+}
+
+void DictionaryManager::validateDictionaryEntry(DictionaryEntry& entry)
+{
+    if (!entry.valid)
+    {
+        ++validDictionaryCount;
+    }
+    entry.valid = true;
+}
+
+} // namespace rde
+} // namespace bios_bmc_smm_error_logger