Gems/Metastream/Code/Source/DataCache.cpp (393 lines of code) (raw):
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "DataCache.h"
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/JSON/stringbuffer.h>
#include <AzCore/JSON/writer.h>
#include <AzCore/std/smart_ptr/make_shared.h>
namespace Metastream
{
void DataCache::AddToCache(const std::string& tableName, const std::string& key, const char* value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->Add(key, jsonValue);
}
void DataCache::AddToCache(const std::string& tableName, const std::string& key, bool value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->Add(key, jsonValue);
}
void DataCache::AddToCache(const std::string& tableName, const std::string& key, const AZ::Vector3& value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->Add(key, jsonValue);
}
void DataCache::AddToCache(const std::string& tableName, const std::string& key, double value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->Add(key, jsonValue);
}
void DataCache::AddToCache(const std::string& tableName, const std::string& key, AZ::u64 value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->Add(key, jsonValue);
}
void DataCache::AddToCache(const std::string& tableName, const std::string& key, AZ::s64 value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->Add(key, jsonValue);
}
void DataCache::AddToArray(const std::string& tableName, const std::string& arrayName, const char* value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToArray(arrayName, jsonValue);
}
void DataCache::AddToArray(const std::string& tableName, const std::string& arrayName, bool value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToArray(arrayName, jsonValue);
}
void DataCache::AddToArray(const std::string& tableName, const std::string& arrayName, const AZ::Vector3& value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToArray(arrayName, jsonValue);
}
void DataCache::AddToArray(const std::string& tableName, const std::string& arrayName, double value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToArray(arrayName, jsonValue);
}
void DataCache::AddToArray(const std::string& tableName, const std::string& arrayName, AZ::u64 value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToArray(arrayName, jsonValue);
}
void DataCache::AddToArray(const std::string& tableName, const std::string& arrayName, AZ::s64 value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToArray(arrayName, jsonValue);
}
void DataCache::AddToObject(const std::string& tableName, const std::string& objName, const std::string& key, const char* value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToObject(objName, key, jsonValue);
}
void DataCache::AddToObject(const std::string& tableName, const std::string& objName, const std::string& key, bool value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToObject(objName, key, jsonValue);
}
void DataCache::AddToObject(const std::string& tableName, const std::string& objName, const std::string& key, const AZ::Vector3& value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToObject(objName, key, jsonValue);
}
void DataCache::AddToObject(const std::string& tableName, const std::string& objName, const std::string& key, double value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToObject(objName, key, jsonValue);
}
void DataCache::AddToObject(const std::string& tableName, const std::string& objName, const std::string& key, AZ::u64 value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToObject(objName, key, jsonValue);
}
void DataCache::AddToObject(const std::string& tableName, const std::string& objName, const std::string& key, AZ::s64 value)
{
DocumentPtr doc(FindDoc(tableName));
auto jsonValue = doc->ToJson(value);
doc->AddToObject(objName, key, jsonValue);
}
void DataCache::AddArrayToCache(const std::string& tableName, const std::string& key, const std::string& arrayName)
{
DocumentPtr doc(FindDoc(tableName));
doc->AddArray(key, arrayName);
}
void DataCache::AddObjectToCache(const std::string& tableName, const std::string& key, const std::string& objectName)
{
DocumentPtr doc(FindDoc(tableName));
doc->AddObject(key, objectName);
}
void DataCache::AddArrayToObject(const std::string& tableName, const std::string& destObjName, const std::string& key, const std::string& srcArrayName)
{
DocumentPtr doc(FindDoc(tableName));
doc->AddArrayToObject(destObjName, key, srcArrayName);
}
void DataCache::AddObjectToObject(const std::string& tableName, const std::string& destObjName, const std::string& key, const std::string& srcObjName)
{
DocumentPtr doc(FindDoc(tableName));
doc->AddObjectToObject(destObjName, key, srcObjName);
}
void DataCache::AddObjectToArray(const std::string& tableName, const std::string& destArrayName, const std::string& srcObjectName)
{
DocumentPtr doc(FindDoc(tableName));
doc->AddObjectToArray(destArrayName, srcObjectName);
}
std::string DataCache::GetDatabasesJSON() const
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexDatabase);
rapidjson::Document jsonDoc;
jsonDoc.SetObject();
rapidjson::Value dbNames(rapidjson::kArrayType);
for (const auto& i : m_database)
{
rapidjson::Value name;
name.SetString(i.first.c_str(), jsonDoc.GetAllocator());
dbNames.PushBack(name, jsonDoc.GetAllocator());
}
jsonDoc.AddMember("tables", dbNames, jsonDoc.GetAllocator());
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
jsonDoc.Accept(writer);
return std::string(buffer.GetString());
}
std::string DataCache::GetTableKeysJSON(const std::string& tableName) const
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexDatabase);
std::string json;
auto it = m_database.find(tableName);
if (it != m_database.end())
{
json = it->second->GetKeysJSON();
}
return json;
}
std::string DataCache::GetTableKeyValuesJSON(const std::string& tableName, const std::vector<std::string>& keyList) const
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexDatabase);
std::string json;
auto it = m_database.find(tableName);
if (it != m_database.end())
{
json = it->second->GetKeyValuesJSON(keyList);
}
return json;
}
void DataCache::ClearCache()
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexDatabase);
m_database.clear();
}
DataCache::DocumentPtr DataCache::FindDoc(const std::string& tableName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexDatabase);
DocumentPtr doc;
auto docItr = m_database.find(tableName);
if (docItr == m_database.end())
{
doc = AZStd::make_shared<Document>();
m_database[tableName] = doc;
}
else
{
doc = docItr->second;
}
return doc;
}
DataCache::Document::Document()
: m_jsonDoc()
, m_allocator(m_jsonDoc.GetAllocator())
{
m_jsonDoc.SetObject();
}
DataCache::Document::~Document()
{
m_jsonValues.clear();
}
std::string DataCache::Document::GetKeysJSON() const
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
rapidjson::Document jsonDoc;
jsonDoc.SetObject();
rapidjson::Value keyNames(rapidjson::kArrayType);
for (rapidjson::Value::ConstMemberIterator itr = m_jsonDoc.MemberBegin(); itr != m_jsonDoc.MemberEnd(); ++itr)
{
rapidjson::Value name;
name.SetString(itr->name.GetString(), jsonDoc.GetAllocator());
keyNames.PushBack(name, jsonDoc.GetAllocator());
}
jsonDoc.AddMember("keys", keyNames, jsonDoc.GetAllocator());
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
jsonDoc.Accept(writer);
return std::string(buffer.GetString());
}
std::string DataCache::Document::GetKeyValuesJSON(const std::vector<std::string>& keyList) const
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
if ((keyList.size() == 1) && (keyList[0] == "*"))
{
m_jsonDoc.Accept(writer);
}
else
{
rapidjson::Document jsonDoc;
jsonDoc.SetObject();
for (rapidjson::Value::ConstMemberIterator itr = m_jsonDoc.MemberBegin(); itr != m_jsonDoc.MemberEnd(); ++itr)
{
std::string keyName(itr->name.GetString());
if (std::find(keyList.cbegin(), keyList.cend(), keyName) != keyList.cend())
{
// do a deep copy for this key...
rapidjson::Value v;
v.CopyFrom(itr->value, jsonDoc.GetAllocator());
jsonDoc.AddMember(rapidjson::Value().SetString(itr->name.GetString(), jsonDoc.GetAllocator()), v, jsonDoc.GetAllocator());
}
}
jsonDoc.Accept(writer);
}
return std::string(buffer.GetString());
}
std::string DataCache::Document::GetJSON() const
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
rapidjson::StringBuffer buffer;
buffer.Clear();
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
m_jsonDoc.Accept(writer);
return std::string(buffer.GetString());
}
void DataCache::Document::Add(const std::string& key, rapidjson::Value& value)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
if (m_jsonDoc.HasMember(key.c_str()))
m_jsonDoc.RemoveMember(ToJson(key));
m_jsonDoc.AddMember(ToJson(key), value, m_allocator);
}
void DataCache::Document::AddToArray(const std::string& arrayName, rapidjson::Value& value)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr rapidValue(FindValue(arrayName, ValueType::Array));
rapidValue->PushBack(value, m_allocator);
}
void DataCache::Document::AddToObject(const std::string& objectName, const std::string& key, rapidjson::Value& value)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr rapidValue(FindValue(objectName, ValueType::Object));
if (rapidValue->HasMember(key.c_str()))
rapidValue->RemoveMember(ToJson(key));
rapidValue->AddMember(ToJson(key), value, m_allocator);
}
void DataCache::Document::AddArray(const std::string& key, const std::string& arrayName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr rapidValue(FindValue(arrayName, ValueType::Array));
Add(key, *rapidValue);
RemoveValue(arrayName, ValueType::Array);
}
void DataCache::Document::AddObject(const std::string& key, const std::string& objectName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr rapidValue(FindValue(objectName, ValueType::Object));
Add(key, *rapidValue);
RemoveValue(objectName, ValueType::Object);
}
void DataCache::Document::AddArrayToObject(const std::string& destObjName, const std::string& key, const std::string& srcArrayName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr jsonDest(FindValue(destObjName, ValueType::Object));
rapidJsonValuePtr jsonSrc(FindValue(srcArrayName, ValueType::Array));
jsonDest->AddMember(ToJson(key), *jsonSrc, m_allocator);
RemoveValue(srcArrayName, ValueType::Array);
}
void DataCache::Document::AddObjectToObject(const std::string& destObjName, const std::string& key, const std::string& srcObjName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr jsonDest(FindValue(destObjName, ValueType::Object));
rapidJsonValuePtr jsonSrc(FindValue(srcObjName, ValueType::Object));
jsonDest->AddMember(ToJson(key), *jsonSrc, m_allocator);
RemoveValue(srcObjName, ValueType::Object);
}
void DataCache::Document::AddObjectToArray(const std::string& destArrayName, const std::string& srcObjectName)
{
AZStd::lock_guard<AZStd::mutex> lock(m_mutexJsonArray);
rapidJsonValuePtr jsonDest(FindValue(destArrayName, ValueType::Array));
rapidJsonValuePtr jsonSrc(FindValue(srcObjectName, ValueType::Object));
jsonDest->PushBack(*jsonSrc, m_allocator);
RemoveValue(srcObjectName, ValueType::Object);
}
rapidjson::Value DataCache::Document::ToJson(const std::string& value)
{
rapidjson::Value v;
v.SetString(value.c_str(), aznumeric_cast<rapidjson::SizeType>(value.size()), m_allocator);
return v;
}
rapidjson::Value DataCache::Document::ToJson(const char* value)
{
rapidjson::Value v;
v.SetString(value == nullptr ? "" : value, m_allocator);
return v;
}
rapidjson::Value DataCache::Document::ToJson(bool value)
{
rapidjson::Value v;
v.SetBool(value);
return v;
}
rapidjson::Value DataCache::Document::ToJson(const AZ::Vector3& value)
{
rapidjson::Value v(rapidjson::kArrayType);
v.PushBack(ToJson(value.GetX()), m_allocator);
v.PushBack(ToJson(value.GetY()), m_allocator);
v.PushBack(ToJson(value.GetZ()), m_allocator);
return v;
}
rapidjson::Value DataCache::Document::ToJson(double value)
{
return rapidjson::Value(value);
}
rapidjson::Value DataCache::Document::ToJson(AZ::u64 value)
{
uint64_t uintValue = value;
return rapidjson::Value(uintValue);
}
rapidjson::Value DataCache::Document::ToJson(AZ::s64 value)
{
int64_t intValue = value;
return rapidjson::Value(intValue);
}
DataCache::Document::rapidJsonValuePtr DataCache::Document::FindValue(const std::string& name, ValueType type)
{
rapidJsonValuePtr valuePtr;
std::string lookupName(name + std::string((type == ValueType::Array) ? "_Array" : "_Object"));
auto itr = m_jsonValues.find(lookupName);
if (itr == m_jsonValues.end())
{
valuePtr = AZStd::make_shared<rapidjson::Value>((type == ValueType::Array) ? rapidjson::kArrayType : rapidjson::kObjectType);
m_jsonValues[lookupName] = valuePtr;
}
else
{
valuePtr = itr->second;
}
return valuePtr;
}
void DataCache::Document::RemoveValue(const std::string& name, ValueType type)
{
std::string lookupName(name + std::string((type == ValueType::Array) ? "_Array" : "_Object"));
auto itr = m_jsonValues.find(lookupName);
if (itr != m_jsonValues.end())
{
m_jsonValues.erase(itr);
}
}
}