Better ClassId. Thread-safe Environment::Components

This commit is contained in:
lganzzzo 2021-11-03 03:37:30 +02:00
parent 95a7fe0067
commit 46fe7d68fe
17 changed files with 223 additions and 92 deletions

View File

@ -43,9 +43,6 @@
namespace oatpp { namespace base {
std::shared_ptr<Logger> Environment::m_logger;
std::unordered_map<std::string, std::unordered_map<std::string, void*>> Environment::m_components;
v_atomicCounter Environment::m_objectsCount(0);
v_atomicCounter Environment::m_objectsCreated(0);
@ -54,6 +51,18 @@ thread_local v_counter Environment::m_threadLocalObjectsCount = 0;
thread_local v_counter Environment::m_threadLocalObjectsCreated = 0;
#endif
std::mutex& Environment::getComponentsMutex() {
static std::mutex componentsMutex;
return componentsMutex;
}
std::unordered_map<std::string, std::unordered_map<std::string, void*>>& Environment::getComponents() {
static std::unordered_map<std::string, std::unordered_map<std::string, void*>> components;
return components;
}
std::shared_ptr<Logger> Environment::m_logger;
DefaultLogger::DefaultLogger(const Config& config)
: m_config(config)
{}
@ -196,15 +205,21 @@ void Environment::init(const std::shared_ptr<Logger>& logger) {
m_threadLocalObjectsCreated = 0;
#endif
if(m_components.size() > 0) {
throw std::runtime_error("[oatpp::base::Environment::init()]: Error. Invalid state. Components were created before call to Environment::init()");
{
std::lock_guard<std::mutex> lock(getComponentsMutex());
if (getComponents().size() > 0) {
throw std::runtime_error("[oatpp::base::Environment::init()]: Error. "
"Invalid state. Components were created before call to Environment::init()");
}
}
}
void Environment::destroy(){
if(m_components.size() > 0) {
throw std::runtime_error("[oatpp::base::Environment::destroy()]: Error. Invalid state. Leaking components");
if(getComponents().size() > 0) {
std::lock_guard<std::mutex> lock(getComponentsMutex());
throw std::runtime_error("[oatpp::base::Environment::destroy()]: Error. "
"Invalid state. Leaking components");
}
m_logger.reset();
@ -364,7 +379,8 @@ void Environment::vlogFormatted(v_uint32 priority, const std::string& tag, const
}
void Environment::registerComponent(const std::string& typeName, const std::string& componentName, void* component) {
auto& bucket = m_components[typeName];
std::lock_guard<std::mutex> lock(getComponentsMutex());
auto& bucket = getComponents()[typeName];
auto it = bucket.find(componentName);
if(it != bucket.end()){
throw std::runtime_error("[oatpp::base::Environment::registerComponent()]: Error. Component with given name already exists: name='" + componentName + "'");
@ -373,8 +389,10 @@ void Environment::registerComponent(const std::string& typeName, const std::stri
}
void Environment::unregisterComponent(const std::string& typeName, const std::string& componentName) {
auto bucketIt = m_components.find(typeName);
if(bucketIt == m_components.end() || bucketIt->second.size() == 0) {
std::lock_guard<std::mutex> lock(getComponentsMutex());
auto& components = getComponents();
auto bucketIt = getComponents().find(typeName);
if(bucketIt == components.end() || bucketIt->second.size() == 0) {
throw std::runtime_error("[oatpp::base::Environment::unregisterComponent()]: Error. Component of given type doesn't exist: type='" + typeName + "'");
}
auto& bucket = bucketIt->second;
@ -384,13 +402,15 @@ void Environment::unregisterComponent(const std::string& typeName, const std::st
}
bucket.erase(componentIt);
if(bucket.size() == 0) {
m_components.erase(bucketIt);
components.erase(bucketIt);
}
}
void* Environment::getComponent(const std::string& typeName) {
auto bucketIt = m_components.find(typeName);
if(bucketIt == m_components.end() || bucketIt->second.size() == 0) {
std::lock_guard<std::mutex> lock(getComponentsMutex());
auto& components = getComponents();
auto bucketIt = components.find(typeName);
if(bucketIt == components.end() || bucketIt->second.size() == 0) {
throw std::runtime_error("[oatpp::base::Environment::getComponent()]: Error. Component of given type doesn't exist: type='" + typeName + "'");
}
auto bucket = bucketIt->second;
@ -401,8 +421,10 @@ void* Environment::getComponent(const std::string& typeName) {
}
void* Environment::getComponent(const std::string& typeName, const std::string& componentName) {
auto bucketIt = m_components.find(typeName);
if(bucketIt == m_components.end() || bucketIt->second.size() == 0) {
std::lock_guard<std::mutex> lock(getComponentsMutex());
auto& components = getComponents();
auto bucketIt = components.find(typeName);
if(bucketIt == components.end() || bucketIt->second.size() == 0) {
throw std::runtime_error("[oatpp::base::Environment::getComponent()]: Error. Component of given type doesn't exist: type='" + typeName + "'");
}
auto bucket = bucketIt->second;

View File

@ -293,12 +293,14 @@ private:
static thread_local v_counter m_threadLocalObjectsCount;
static thread_local v_counter m_threadLocalObjectsCreated;
#endif
private:
static std::mutex& getComponentsMutex();
static std::unordered_map<std::string, std::unordered_map<std::string, void*>>& getComponents();
private:
static std::shared_ptr<Logger> m_logger;
static void checkTypes();
private:
static std::unordered_map<std::string, std::unordered_map<std::string, void*>> m_components;
public:
/**

View File

@ -46,7 +46,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type *getType() {
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}

View File

@ -622,8 +622,10 @@ namespace __class {
private:
static Type createType() {
Type type(__class::AbstractEnum::CLASS_ID, type::EnumMeta<T>::getInfo()->nameQualifier, new PolymorphicDispatcher());
return type;
Type::Info info;
info.nameQualifier = type::EnumMeta<T>::getInfo()->nameQualifier;
info.polymorphicDispatcher = new PolymorphicDispatcher();
return Type(__class::AbstractEnum::CLASS_ID, info);
}
public:

View File

@ -141,9 +141,10 @@ namespace __class {
private:
static Type createType() {
Type type(__class::AbstractList::CLASS_ID, nullptr, new PolymorphicDispatcher());
type.params.push_back(T::Class::getType());
return type;
Type::Info info;
info.params.push_back(T::Class::getType());
info.polymorphicDispatcher = new PolymorphicDispatcher();
return Type(__class::AbstractList::CLASS_ID, info);
}
public:

View File

@ -229,6 +229,13 @@ namespace __class {
return properties;
}
static Type* createType() {
Type::Info info;
info.nameQualifier = T::Z__CLASS_TYPE_NAME();
info.polymorphicDispatcher = new PolymorphicDispatcher();
return new Type(CLASS_ID, info);
}
public:
/**
@ -236,7 +243,7 @@ namespace __class {
* @return - &id:oatpp::data::mapping::type::Type;
*/
static Type* getType() {
static Type* type = new Type(CLASS_ID, T::Z__CLASS_TYPE_NAME(), new PolymorphicDispatcher());
static Type* type = createType();
return type;
}

View File

@ -168,10 +168,11 @@ public:
private:
static Type createType() {
Type type(__class::AbstractPairList::CLASS_ID, nullptr, new PolymorphicDispatcher());
type.params.push_back(Key::Class::getType());
type.params.push_back(Value::Class::getType());
return type;
Type::Info info;
info.params.push_back(Key::Class::getType());
info.params.push_back(Value::Class::getType());
info.polymorphicDispatcher = new PolymorphicDispatcher();
return Type(__class::AbstractPairList::CLASS_ID, info);
}
public:

View File

@ -537,7 +537,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -548,7 +548,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -559,7 +559,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -570,7 +570,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -581,7 +581,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -592,7 +592,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -603,7 +603,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -614,7 +614,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -625,7 +625,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -636,7 +636,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -647,7 +647,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -658,7 +658,7 @@ namespace __class {
static const ClassId CLASS_ID;
static Type* getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}

View File

@ -31,7 +31,7 @@ namespace __class {
const ClassId Void::CLASS_ID("Void");
Type* Void::getType(){
static Type type(CLASS_ID, nullptr);
static Type type(CLASS_ID);
return &type;
}
@ -40,28 +40,46 @@ namespace __class {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ClassId
std::atomic_int ClassId::ID_COUNTER(0);
std::mutex& ClassId::getClassMutex() {
static std::mutex classMutex;
return classMutex;
}
std::vector<const char*>& ClassId::getClassNames() {
static std::vector<const char*> classNames;
return classNames;
}
v_int32 ClassId::registerClassName(const char* name) {
std::lock_guard<std::mutex> lock(getClassMutex());
getClassNames().push_back(name);
return getClassNames().size() - 1;
}
ClassId::ClassId(const char* pName)
: name(pName)
, id(ID_COUNTER ++)
, id(registerClassName(pName))
{}
int ClassId::getClassCount() {
return ID_COUNTER;
std::lock_guard<std::mutex> lock(getClassMutex());
return getClassNames().size();
}
std::vector<const char*> ClassId::getRegisteredClassNames() {
std::lock_guard<std::mutex> lock(getClassMutex());
return std::vector<const char*>(getClassNames());
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Type
Type::Type(const ClassId& pClassId,
const char* pNameQualifier,
void* pPolymorphicDispatcher,
InterpretationMap&& pInterpretationMap)
Type::Type(const ClassId& pClassId, const Info& typeInfo)
: classId(pClassId)
, nameQualifier(pNameQualifier)
, polymorphicDispatcher(pPolymorphicDispatcher)
, interpretationMap(pInterpretationMap)
, nameQualifier(typeInfo.nameQualifier)
, params(typeInfo.params)
, polymorphicDispatcher(typeInfo.polymorphicDispatcher)
, interpretationMap(typeInfo.interpretationMap)
{}
const Type::AbstractInterpretation* Type::findInterpretation(const std::vector<std::string>& names) const {

View File

@ -42,13 +42,21 @@ class Type; // FWD
*/
class ClassId {
private:
static std::atomic_int ID_COUNTER;
static std::mutex& getClassMutex();
static std::vector<const char*>& getClassNames();
static v_int32 registerClassName(const char* name);
public:
/**
* Get count of all type classes created.
* @return
*/
static int getClassCount();
/**
* Get registered class names.
* @return
*/
static std::vector<const char*> getRegisteredClassNames();
public:
/**
@ -67,6 +75,17 @@ public:
* *Note: class type IDs are integer values incremented continuously from [0 to `getClassCount()`]*
*/
const v_int32 id;
public:
inline bool operator == (const ClassId& other) const {
return id == other.id;
}
inline bool operator != (const ClassId& other) const {
return id != other.id;
}
};
@ -362,19 +381,47 @@ public:
typedef std::unordered_map<std::string, const AbstractInterpretation*> InterpretationMap;
public:
/**
* Type info.
*/
struct Info {
/**
* Default constructor.
*/
Info() {}
/**
* Type name qualifier.
*/
const char* nameQualifier = nullptr;
/**
* List of type parameters - for templated types.
*/
std::vector<const Type*> params;
/**
* PolymorphicDispatcher is responsible for forwarding polymorphic calls to a correct object of type `Type`.
*/
void* polymorphicDispatcher = nullptr;
/**
* Map of type Interpretations.
*/
InterpretationMap interpretationMap;
};
public:
/**
* Constructor.
* @param pClassId - type class id.
* @param pNameQualifier - type name qualifier.
* @param pPolymorphicDispatcher - is an object to forward polymorphic calls to a correct object of type `Type`.
* @param pInterpretationMap - Map of type Interpretations.
* @param typeInfo - type creation info. &l:Type::Info;.
*/
Type(const ClassId& pClassId,
const char* pNameQualifier,
void* pPolymorphicDispatcher = nullptr,
InterpretationMap&& pInterpretationMap = InterpretationMap{});
Type(const ClassId& pClassId, const Info& typeInfo = Info());
/**
* type class id.
@ -389,7 +436,7 @@ public:
/**
* List of type parameters - for templated types.
*/
std::list<const Type*> params;
const std::vector<const Type*> params;
/**
* PolymorphicDispatcher - is an object to forward polymorphic calls to a correct object of type `Type`.
@ -460,6 +507,18 @@ public: \
namespace std {
template<>
struct hash<oatpp::data::mapping::type::ClassId> {
typedef oatpp::data::mapping::type::ClassId argument_type;
typedef v_uint64 result_type;
result_type operator()(argument_type const& v) const noexcept {
return v.id;
}
};
template<>
struct hash<oatpp::data::mapping::type::Void> {

View File

@ -141,10 +141,11 @@ namespace __class {
private:
static Type createType() {
Type type(__class::AbstractUnorderedMap::CLASS_ID, nullptr, new PolymorphicDispatcher());
type.params.push_back(Key::Class::getType());
type.params.push_back(Value::Class::getType());
return type;
Type::Info info;
info.params.push_back(Key::Class::getType());
info.params.push_back(Value::Class::getType());
info.polymorphicDispatcher = new PolymorphicDispatcher();
return Type(__class::AbstractUnorderedMap::CLASS_ID, info);
}
public:

View File

@ -143,9 +143,10 @@ public:
private:
static Type createType() {
Type type(__class::AbstractUnorderedSet::CLASS_ID, nullptr, new PolymorphicDispatcher());
type.params.push_back(T::Class::getType());
return type;
Type::Info info;
info.params.push_back(T::Class::getType());
info.polymorphicDispatcher = new PolymorphicDispatcher();
return Type(__class::AbstractUnorderedSet::CLASS_ID, info);
}
public:

View File

@ -139,9 +139,10 @@ namespace __class {
private:
static Type createType() {
Type type(__class::AbstractVector::CLASS_ID, nullptr, new PolymorphicDispatcher());
type.params.push_back(T::Class::getType());
return type;
Type::Info info;
info.params.push_back(T::Class::getType());
info.polymorphicDispatcher = new PolymorphicDispatcher();
return Type(__class::AbstractVector::CLASS_ID, info);
}
public:

View File

@ -67,11 +67,10 @@ Deserializer::Deserializer(const std::shared_ptr<Config>& config)
void Deserializer::setDeserializerMethod(const data::mapping::type::ClassId& classId, DeserializerMethod method) {
const v_uint32 id = classId.id;
if(id < m_methods.size()) {
m_methods[id] = method;
} else {
throw std::runtime_error("[oatpp::parser::json::mapping::Deserializer::setDeserializerMethod()]: Error. Unknown classId");
if(id >= m_methods.size()) {
m_methods.resize(id + 1, nullptr);
}
m_methods[id] = method;
}
void Deserializer::skipScope(oatpp::parser::Caret& caret, v_char8 charOpen, v_char8 charClose){

View File

@ -68,11 +68,10 @@ Serializer::Serializer(const std::shared_ptr<Config>& config)
void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) {
const v_uint32 id = classId.id;
if(id < m_methods.size()) {
m_methods[id] = method;
} else {
throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::setSerializerMethod()]: Error. Unknown classId");
if(id >= m_methods.size()) {
m_methods.resize(id + 1, nullptr);
}
m_methods[id] = method;
}
void Serializer::serializeString(data::stream::ConsistentOutputStream* stream, const char* data, v_buff_size size, v_uint32 escapeFlags) {

View File

@ -79,6 +79,14 @@ void runTests() {
OATPP_LOGD("Tests", "action size=%d", sizeof(oatpp::async::Action));
OATPP_LOGD("Tests", "class count=%d", oatpp::data::mapping::type::ClassId::getClassCount());
auto names = oatpp::data::mapping::type::ClassId::getRegisteredClassNames();
v_int32 i = 0;
for(auto& name : names) {
OATPP_LOGD("CLASS", "%d --> '%s'", i, name);
i ++;
}
OATPP_RUN_TEST(oatpp::test::base::CommandLineArgumentsTest);
OATPP_RUN_TEST(oatpp::test::base::LoggerTest);

View File

@ -88,18 +88,23 @@ namespace __class {
};
private:
static oatpp::Type* createType() {
oatpp::Type::Info info;
info.interpretationMap = {
{"test", new Inter()}
};
return new Type(CLASS_ID, info);
}
public:
static const oatpp::ClassId CLASS_ID;
static oatpp::Type* getType(){
static Type type(
CLASS_ID, nullptr, nullptr,
{
{"test", new Inter()}
}
);
return &type;
static Type* type = createType();
return type;
}
};
@ -137,18 +142,23 @@ namespace __class {
};
private:
static oatpp::Type* createType() {
oatpp::Type::Info info;
info.interpretationMap = {
{"test", new Inter()}
};
return new oatpp::Type(CLASS_ID, info);
}
public:
static const oatpp::ClassId CLASS_ID;
static oatpp::Type* getType(){
static Type type(
CLASS_ID, nullptr, nullptr,
{
{"test", new Inter()}
}
);
return &type;
static Type* type = createType();
return type;
}
};