diff --git a/src/BasicChannel.cpp b/src/BasicChannel.cpp index 8ed07ab..54c7306 100644 --- a/src/BasicChannel.cpp +++ b/src/BasicChannel.cpp @@ -13,7 +13,7 @@ using namespace std::chrono; using namespace ts; BasicChannel::BasicChannel(ChannelId parentId, ChannelId channelId) { - this->setProperties(make_shared()); + this->setProperties(make_shared()); this->_properties->register_property_type(); this->properties()[property::CHANNEL_ID] = channelId; @@ -27,7 +27,7 @@ void BasicChannel::setPermissionManager(const std::shared_ptrupdate_properties_from_permissions(flag_view_update); } -void BasicChannel::setProperties(const std::shared_ptr& props) { +void BasicChannel::setProperties(const std::shared_ptr& props) { if(this->_properties) { (*props)[property::CHANNEL_ID] = this->channelId(); (*props)[property::CHANNEL_PID] = this->properties()[property::CHANNEL_PID].value(); @@ -60,7 +60,7 @@ std::vector BasicChannel::update_properties_from_pe auto fvalue = permission_manager->permission_value_flagged(permission::i_icon_id); if(fvalue.has_value) target_icon_id = (IconId) fvalue.value; - if(this->properties()[property::CHANNEL_ICON_ID] != target_icon_id) { + if(this->properties()[property::CHANNEL_ICON_ID].as_or(0) != target_icon_id) { this->properties()[property::CHANNEL_ICON_ID] = target_icon_id; result.push_back(property::CHANNEL_ICON_ID); } @@ -72,7 +72,7 @@ std::vector BasicChannel::update_properties_from_pe auto fvalue = permission_manager->permission_value_flagged(permission::i_client_needed_talk_power); if(fvalue.has_value) talk_power = fvalue.value; - if(this->properties()[property::CHANNEL_NEEDED_TALK_POWER] != talk_power) { + if(this->properties()[property::CHANNEL_NEEDED_TALK_POWER].as_or(0) != talk_power) { this->properties()[property::CHANNEL_NEEDED_TALK_POWER] = talk_power; result.push_back(property::CHANNEL_NEEDED_TALK_POWER); } @@ -108,8 +108,8 @@ BasicChannel::BasicChannel(std::shared_ptr parent, ChannelId chann BasicChannel::~BasicChannel() { } ChannelType::ChannelType BasicChannel::channelType() { - if (this->properties()[property::CHANNEL_FLAG_PERMANENT].as()) return ChannelType::ChannelType::permanent; - else if (this->properties()[property::CHANNEL_FLAG_SEMI_PERMANENT].as()) return ChannelType::ChannelType::semipermanent; + if (this->properties()[property::CHANNEL_FLAG_PERMANENT].as_unchecked()) return ChannelType::ChannelType::permanent; + else if (this->properties()[property::CHANNEL_FLAG_SEMI_PERMANENT].as_unchecked()) return ChannelType::ChannelType::semipermanent; else return ChannelType::ChannelType::temporary; } @@ -119,21 +119,22 @@ void BasicChannel::setChannelType(ChannelType::ChannelType type) { } bool BasicChannel::passwordMatch(std::string password, bool hashed) { - if (!this->properties()[property::CHANNEL_FLAG_PASSWORD].as() || this->properties()[property::CHANNEL_PASSWORD].value().empty()) return true; + if (!this->properties()[property::CHANNEL_FLAG_PASSWORD].as_unchecked() || this->properties()[property::CHANNEL_PASSWORD].value().empty()) return true; if (password.empty()) return false; - if(this->properties()[property::CHANNEL_PASSWORD].as() == password) + if(this->properties()[property::CHANNEL_PASSWORD].as_unchecked() == password) return true; password = base64::encode(digest::sha1(password)); - return this->properties()[property::CHANNEL_PASSWORD].as() == password; + return this->properties()[property::CHANNEL_PASSWORD].as_unchecked() == password; } int64_t BasicChannel::emptySince() { if (!properties().hasProperty(property::CHANNEL_LAST_LEFT)) return 0; - time_point lastLeft = time_point() + milliseconds(properties()[property::CHANNEL_LAST_LEFT].as()); + time_point lastLeft = time_point() + milliseconds( + properties()[property::CHANNEL_LAST_LEFT].as_unchecked()); return (int64_t) duration_cast(system_clock::now() - lastLeft).count(); } @@ -280,7 +281,7 @@ bool BasicChannelTree::setDefaultChannel(const shared_ptr &ch) { std::shared_ptr BasicChannelTree::getDefaultChannel() { for (auto elm : this->channels()) - if (elm->properties()[property::CHANNEL_FLAG_DEFAULT].as()) return elm; + if (elm->properties()[property::CHANNEL_FLAG_DEFAULT].as_unchecked()) return elm; return nullptr; } diff --git a/src/BasicChannel.h b/src/BasicChannel.h index a42ffcc..11e8635 100644 --- a/src/BasicChannel.h +++ b/src/BasicChannel.h @@ -45,7 +45,7 @@ namespace ts { inline std::string name(){ return properties()[property::CHANNEL_NAME]; } inline ChannelId channelOrder(){ return this->previousChannelId(); } - inline Properties& properties() const { return *this->_properties; } + inline PropertyManager& properties() const { return *this->_properties; } ChannelType::ChannelType channelType(); void setChannelType(ChannelType::ChannelType); @@ -55,7 +55,8 @@ namespace ts { int64_t emptySince(); inline std::chrono::system_clock::time_point createdTimestamp() { - return std::chrono::system_clock::time_point() + std::chrono::milliseconds(this->properties()[property::CHANNEL_CREATED_AT].as()); + return std::chrono::system_clock::time_point() + std::chrono::milliseconds( + this->properties()[property::CHANNEL_CREATED_AT].as_unchecked()); } ts_always_inline bool permission_require_property_update(const permission::PermissionType& permission) { @@ -76,7 +77,7 @@ namespace ts { ts_always_inline std::shared_ptr permissions(){ return this->_permissions; } virtual void setPermissionManager(const std::shared_ptr&); - virtual void setProperties(const std::shared_ptr&); + virtual void setProperties(const std::shared_ptr&); private: ts_always_inline static bool permission_granted(const permission::v2::PermissionFlaggedValue& channel_permission_value, const permission::v2::PermissionFlaggedValue& granted_value, bool require_granted_value) { @@ -97,7 +98,7 @@ namespace ts { void setLinkedHandle(const std::weak_ptr &) override; protected: std::weak_ptr _link; - std::shared_ptr _properties; + std::shared_ptr _properties; std::shared_ptr _permissions; permission::v2::PermissionFlaggedValue last_view_power{0, false}; diff --git a/src/Properties.cpp b/src/Properties.cpp index a876939..9ea9c91 100644 --- a/src/Properties.cpp +++ b/src/Properties.cpp @@ -8,68 +8,76 @@ using namespace ts; using namespace ts::property; using namespace std; -Properties::Properties() { - memtrack::allocated(this); +PropertyManager::PropertyManager() { + memtrack::allocated(this); } -Properties::~Properties() { - memtrack::freed(this); +PropertyManager::~PropertyManager() { + memtrack::freed(this); } -bool Properties::has(property::PropertyType type, int index) { +bool PropertyManager::has(property::PropertyType type, int index) { for(auto it = this->properties.begin(); it != this->properties.end(); it++) { - if(!*it) continue; - if(it->get()->type != type) continue; + auto& bundle = *it; + if(bundle->type != type) { + continue; + } - return index < it->get()->length; + return index < bundle->property_count; } return false; } -PropertyWrapper Properties::find(property::PropertyType type, int index) { +Property PropertyManager::get(property::PropertyType type, int index) { for (auto &bulk : this->properties) { - if(!bulk) continue; - if(bulk->type != type) + if(bulk->type != type) { continue; + } - if(index >= bulk->length) + if(index >= bulk->property_count) { break; + } - return PropertyWrapper{this, &bulk->properties[index], bulk}; + return Property{this->weak_from_this().lock(), &bulk->properties[index], bulk}; } throw std::invalid_argument("missing property type"); } -std::vector Properties::list_properties(ts::property::flag_type flagMask, ts::property::flag_type negatedFlagMask) { - vector result; +std::vector PropertyManager::list_properties(ts::property::flag_type flagMask, ts::property::flag_type negatedFlagMask) { + std::vector result{}; result.reserve(this->properties_count); + auto self_ref = this->weak_from_this().lock(); for (auto &bulk : this->properties) { - for(int index = 0; index < bulk->length; index++) { + for(int index = 0; index < bulk->property_count; index++) { auto& property = bulk->properties[index]; - if((property.description->flags & flagMask) > 0 && (property.description->flags & negatedFlagMask) == 0) - result.emplace_back(this, &property, bulk); + if((property.description->flags & flagMask) > 0 && (property.description->flags & negatedFlagMask) == 0) { + result.emplace_back(self_ref, &property, bulk); + } } } return result; } -std::vector Properties::all_properties() { - vector result; +std::vector PropertyManager::all_properties() { + std::vector result{}; result.reserve(this->properties_count); + auto self_ref = this->weak_from_this().lock(); for (auto &bulk : this->properties) { - for(int index = 0; index < bulk->length; index++) - result.emplace_back(this, &bulk->properties[index], bulk); + for(int index = 0; index < bulk->property_count; index++) { + result.emplace_back(self_ref, &bulk->properties[index], bulk); + } } return result; } -PropertyWrapper::PropertyWrapper(ts::Properties* handle, ts::PropertyData *data, std::shared_ptr bundle_lock) : handle{handle}, data_ptr{data}, bundle_lock{std::move(bundle_lock)} { +Property::Property(std::shared_ptr handle, ts::PropertyData *data, std::shared_ptr bundle_lock) + : handle{std::move(handle)}, property_data{data}, bundle_lock{std::move(bundle_lock)} { } -void PropertyWrapper::trigger_update() { - this->data_ptr->flag_modified = true; +void Property::trigger_update() { + this->property_data->flag_modified = true; if(this->handle) { for(const auto& elm : this->handle->notifyFunctions) @@ -77,43 +85,46 @@ void PropertyWrapper::trigger_update() { } } -bool Properties::register_property_type(ts::property::PropertyType type, size_t length) { - for(auto& bulk : this->properties) - if(bulk->type == type) - return false; +void PropertyManager::do_register_property_type(ts::property::PropertyType type, size_t length) { + for(auto& bulk : this->properties) { + if(bulk->type == type) { + return; + } + } const auto alloc_length = sizeof(PropertyBundle) + sizeof(PropertyData) * length; auto ptr = shared_ptr((PropertyBundle*) malloc(alloc_length), [](PropertyBundle* bundle) { - if(!bundle) return; + if(!bundle) { + return; + } - for(int index = 0; index < bundle->length; index++) { + for(int index = 0; index < bundle->property_count; index++) { auto& property = bundle->properties[index]; property.value.~string(); - property.value_lock.~spin_mutex(); property.casted_value.~any(); } + ::free(bundle); }); ptr->type = type; - ptr->length = length; + ptr->property_count = length; for(int index = 0; index < length; index++) { auto& property = ptr->properties[index]; - new (&property.casted_value) any(); - new (&property.value_lock) spin_mutex(); - new (&property.value) string(); + new (&property.casted_value) any{}; + new (&property.value) string{}; property.description = &property::describe(type, index); property.flag_modified = false; - property.flag_db_reference = false; + property.flag_database_reference = false; property.value = property.description->default_value; this->properties_count++; } this->properties.push_back(ptr); - return false; + return; } namespace ts { diff --git a/src/Properties.h b/src/Properties.h index 40a008e..d7d2941 100644 --- a/src/Properties.h +++ b/src/Properties.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "misc/spin_mutex.h" #include "converters/converter.h" @@ -495,31 +497,55 @@ namespace ts { } template - constexpr inline PropertyType type_from_enum(); + struct type_from_enum_t { + constexpr static auto supported{false}; + constexpr static auto type{PropertyType::PROP_TYPE_UNKNOWN}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_SERVER; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_SERVER}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_CHANNEL; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_CHANNEL}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_CLIENT; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_CLIENT}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_CONNECTION; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_CONNECTION}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_GROUP; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_GROUP}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_INSTANCE; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_INSTANCE}; + }; template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_PLAYLIST; } + struct type_from_enum_t { + constexpr static auto supported{true}; + constexpr static auto type{PropertyType::PROP_TYPE_PLAYLIST}; + }; - template<> - constexpr inline PropertyType type_from_enum() { return PropertyType::PROP_TYPE_UNKNOWN; } + template + constexpr inline PropertyType type_from_enum() { return type_from_enum_t::type; } struct PropertyDescription { std::string_view name{}; @@ -545,7 +571,7 @@ namespace ts { template ::value, int>::type = 0> constexpr inline bool operator==(const PropertyEnumType& other) const { - return this->property_index == (int) other && this->type_property == type_from_enum(); + return this->property_index == (int) other && this->type_property == type_from_enum_t::type; } [[nodiscard]] inline bool is_undefined() const { return property_index == 0; } @@ -645,20 +671,27 @@ namespace ts { } inline const auto& find(PropertyType type, const std::string_view& name) { - if(type >= property_list_info.end_index.size()) return undefined_property_description; + if(type >= property_list_info.end_index.size()) { + return undefined_property_description; + } constexpr static auto buffer_size{128}; /* no property is longer than 128 bytes */ - if(name.size() >= buffer_size) return undefined_property_description; + if(name.size() >= buffer_size) { + return undefined_property_description; + } char buffer[buffer_size]; - for(size_t index{0}; index < name.size(); index++) + for(size_t index{0}; index < name.size(); index++) { buffer[index] = (char) tolower(name[index]); + } const std::string_view lower_name{buffer, name.size()}; const auto begin = property_list_info.begin_index[type]; const auto end = property_list_info.end_index[type]; - for(size_t index{begin}; index < end; index++) - if(property_list[index].name == lower_name) + for(size_t index{begin}; index < end; index++) { + if(property_list[index].name == lower_name) { return property_list[index]; + } + } return property_list[begin]; /* begin index MUST be the undefined */ } @@ -697,15 +730,14 @@ namespace ts { #undef const_modifier } - class Properties; + class PropertyManager; struct PropertyData { - spin_mutex value_lock; std::any casted_value; std::string value; const property::PropertyDescription* description; - bool flag_db_reference; + bool flag_database_reference; bool flag_modified; }; @@ -714,106 +746,118 @@ namespace ts { #pragma warning( disable : 4200 ) #endif struct PropertyBundle { + std::mutex value_mutex{}; property::PropertyType type; - size_t length; + size_t property_count; PropertyData properties[0]; }; #ifdef WIN32 #pragma warning( pop ) #endif - - template - struct PropertyAccess { - inline static T get(PropertyData* data_ptr) { - std::lock_guard lock(data_ptr->value_lock); - if(data_ptr->casted_value.type() == typeid(T)) - return std::any_cast(data_ptr->casted_value); - - data_ptr->casted_value = ts::converter::from_string_view(std::string_view{data_ptr->value}); - return std::any_cast(data_ptr->casted_value); - } - }; - - template <> - struct PropertyAccess { - inline static std::string get(PropertyData* data_ptr) { return data_ptr->value; } - }; - - struct PropertyWrapper { - friend class Properties; + struct Property { + friend class PropertyManager; public: - bool operator==(const PropertyWrapper& other) { - if(this->data_ptr == other.data_ptr) - return true; - - return this->data_ptr->value == other.data_ptr->value; - } + explicit Property(std::shared_ptr /* handle */, PropertyData* /* ptr */, std::shared_ptr /* bundle */); template - bool operator==(const T& other){ - return this->as() == other; + bool operator==(const T& other) { + auto value = this->as(); + return value.has_value() && *value == other; } + template bool operator!=(const T& other){ - return !operator==(other); + return !(*this == other); } + /* //Math operators - PropertyWrapper&operator++(){ return operator=(as() + 1); } - PropertyWrapper&operator++(int){ return operator=(as() + 1); } - PropertyWrapper&operator+=(uint16_t val){ return operator=(as() + val); } - PropertyWrapper&operator+=(int64_t val){ return operator=(as() + val); } - PropertyWrapper&operator+=(uint64_t val){ return operator=(as() + val); } + inline Property&operator++() { return operator=(this->as_unchecked() + 1); } + inline Property&operator++(int) { return operator=(this->as_unchecked() + 1); } + inline Property&operator+=(uint16_t val) { return operator=(this->as_unchecked() + val); } + inline Property&operator+=(int64_t val) { return operator=(this->as_unchecked() + val); } + inline Property&operator+=(uint64_t val) { return operator=(this->as_unchecked() + val); } + */ - [[nodiscard]] bool hasDbReference() const { return this->data_ptr->flag_db_reference; } - void setDbReference(bool flag){ this->data_ptr->flag_db_reference = flag; } + /** + * Get the property manager for this property. + * Note: The handle might be null if the manager hasn't been created with + * `std::make_shared<..>()`. + */ + [[nodiscard]] inline const auto& get_handle() { return this->handle; } - [[nodiscard]] bool isModified() const { return this->data_ptr->flag_modified; } - void setModified(bool flag){ this->data_ptr->flag_modified = flag; } - - template - [[nodiscard]] T as() const { - static_assert(ts::converter::supported, "as isn't supported for type"); - - return PropertyAccess::get(this->data_ptr); - } + [[nodiscard]] bool hasDbReference() const { return this->property_data->flag_database_reference; } + void setDbReference(bool flag){ this->property_data->flag_database_reference = flag; } + [[nodiscard]] bool isModified() const { return this->property_data->flag_modified; } + void setModified(bool flag){ this->property_data->flag_modified = flag; } #ifndef WIN32 template - [[nodiscard]] operator T(){ return this->as(); } + [[nodiscard]] operator T(){ return this->as_unchecked(); } #endif template - [[nodiscard]] T as_save(const std::function defaultValue = []{ return T{}; }) const { - try { - std::lock_guard lock(this->data_ptr->value_lock); - if(this->data_ptr->casted_value.type() == typeid(T)) - return std::any_cast(this->data_ptr->casted_value); + [[nodiscard]] std::optional as() const { + static_assert(ts::converter::supported, "as isn't supported for type"); + static_assert(!ts::converter::references, "as only supports non reference types"); - this->data_ptr->casted_value = ts::converter::from_string_view(this->data_ptr->value); - return std::any_cast(this->data_ptr->casted_value); + try { + std::lock_guard value_lock{this->bundle_lock->value_mutex}; + if(this->property_data->casted_value.type() == typeid(T)) { + const auto& value = std::any_cast(this->property_data->casted_value); + return std::make_optional(value); + } + + auto value = ts::converter::from_string_view(this->property_data->value); + this->property_data->casted_value = value; + return std::make_optional(std::move(value)); + } catch(std::exception&) { + return std::nullopt; + } + } + + template + [[nodiscard]] T as_or(T fallback_value) const { + try { + std::lock_guard value_lock{this->bundle_lock->value_mutex}; + if(this->property_data->casted_value.type() == typeid(T)) { + return std::any_cast(this->property_data->casted_value); + } + + this->property_data->casted_value = ts::converter::from_string_view(this->property_data->value); + return std::any_cast(this->property_data->casted_value); + } catch(std::exception&) { + return fallback_value; + } + } + + template + [[nodiscard]] T as_or_get(const std::function defaultValue = [] { return T{}; }) const { + try { + std::lock_guard value_lock{this->bundle_lock->value_mutex}; + if(this->property_data->casted_value.type() == typeid(T)) { + return std::any_cast(this->property_data->casted_value); + } + + this->property_data->casted_value = ts::converter::from_string_view(this->property_data->value); + return std::any_cast(this->property_data->casted_value); } catch(std::exception&) { return defaultValue(); } } - [[nodiscard]] const property::PropertyDescription& type() const { return *this->data_ptr->description; } - [[nodiscard]] std::string value() const { - std::lock_guard lock{this->data_ptr->value_lock}; - return this->data_ptr->value; + /* TODO: Depricate */ + template + [[nodiscard]] T as_unchecked() const { + return std::move(*this->as()); } - void value(const std::string &value, bool trigger_update = true){ - { - std::lock_guard lock(this->data_ptr->value_lock); - if(this->data_ptr->value == value) - return; - this->data_ptr->casted_value.reset(); - this->data_ptr->value = value; - } - if(trigger_update) - this->trigger_update(); + [[nodiscard]] const property::PropertyDescription& type() const { return *this->property_data->description; } + + [[nodiscard]] std::string value() const { + std::lock_guard value_lock{this->bundle_lock->value_mutex}; + return this->property_data->value; } [[nodiscard]] const std::string_view& default_value() const { @@ -821,92 +865,105 @@ namespace ts { } template - PropertyWrapper& operator=(const T& value) { - this->update_value(value); - return *this; - } - - - template - bool update_value(const T& value) { + bool update_value(T value) { static_assert(ts::converter::supported, "type isn't supported for type"); { - std::any any_value{value}; + std::any any_value{std::move(value)}; auto value_string = ts::converter::to_string(any_value); - std::lock_guard lock(this->data_ptr->value_lock); - if(value_string == this->data_ptr->value) { + std::lock_guard value_lock{this->bundle_lock->value_mutex}; + if(value_string == this->property_data->value) { return false; } - this->data_ptr->casted_value = any_value; - this->data_ptr->value = value_string; + this->property_data->casted_value = any_value; + this->property_data->value = std::move(value_string); } this->trigger_update(); return true; } - PropertyWrapper& operator=(const std::string& value) { - this->value(value); + template + Property& operator=(const T& value) { + this->update_value(value); return *this; } - PropertyWrapper& operator=(const char* value) { - this->value(value); + + Property& operator=(const char* value) { + this->update_value(std::string_view{value}); return *this; } template - PropertyWrapper& operator=(char(value)[N]) { - this->value(value); + Property& operator=(char(value)[N]) { + this->update_value(std::string_view{value, N}); return *this; } - void trigger_update(); + /** + * Increment the value, if numeric, by the given value. + * If the value isn't cast able to T `false` will be returned. + * Note: This action is not atomic. + * @tparam T + * @param value + * @return + */ + template::value, int> = 0> + bool increment_by(T value) { + auto current_value = this->as(); + if(current_value.has_value()) { + this->update_value(*current_value + value); + return true; + } else { + return false; + } + } - PropertyWrapper(Properties* /* handle */, PropertyData* /* ptr */, std::shared_ptr /* bundle */); - - [[nodiscard]] inline Properties* get_handle() { return this->handle; } private: - Properties* handle = nullptr; - PropertyData* data_ptr = nullptr; + /* Will be initialized by the constructor */ + PropertyData* property_data; + std::shared_ptr handle; std::shared_ptr bundle_lock; + + void trigger_update(); }; - typedef PropertyWrapper Property; - typedef std::function PropertyNotifyFn; - class Properties { - friend struct PropertyWrapper; + typedef std::function PropertyNotifyFn; + + class PropertyManager : public std::enable_shared_from_this { + friend struct Property; public: - Properties(); - ~Properties(); - Properties(const Properties&) = delete; - Properties(Properties&&) = default; + PropertyManager(); + ~PropertyManager(); - std::vector list_properties(property::flag_type flagMask = (property::flag_type) ~0UL, property::flag_type negatedFlagMask = 0); - std::vector all_properties(); + PropertyManager(const PropertyManager&) = delete; + PropertyManager(PropertyManager&&) = default; + + std::vector list_properties(property::flag_type flagMask = (property::flag_type) ~0UL, property::flag_type negatedFlagMask = 0); + std::vector all_properties(); template - bool register_property_type() { + void register_property_type() { constexpr auto type = property::type_from_enum(); - return this->register_property_type(type, property::property_count()); + this->do_register_property_type(type, property::property_count()); } template bool hasProperty(T type) { return this->has(property::type_from_enum(), type); } - template ::value, int>::type = 0> - PropertyWrapper operator[](T type) { - return this->find(property::type_from_enum(), type); + template ::supported, int>::type = 0> + [[nodiscard]] Property operator[](T type) { + return this->get(property::type_from_enum_t::type, type); } - PropertyWrapper operator[](const property::PropertyDescription& type) { - return this->find(type.type_property, type.property_index); + [[nodiscard]] Property operator[](const property::PropertyDescription& type) { + return this->get(type.type_property, type.property_index); } - PropertyWrapper operator[](const property::PropertyDescription* type) { - return this->find(type->type_property, type->property_index); + [[nodiscard]] Property operator[](const property::PropertyDescription* type) { + return this->get(type->type_property, type->property_index); } void registerNotifyHandler(const PropertyNotifyFn &fn){ @@ -914,26 +971,28 @@ namespace ts { } void triggerAllModified(){ - for(auto& prop : this->all_properties()) - if(prop.isModified()) - for(auto& elm : notifyFunctions) + for(auto& prop : this->all_properties()) { + if(prop.isModified()) { + for(auto& elm : this->notifyFunctions) { elm(prop); + } + } + } } void toggleSave(bool flag) { this->save = flag; } - bool isSaveEnabled(){ return this->save; } + [[nodiscard]] bool isSaveEnabled(){ return this->save; } - - PropertyWrapper find(property::PropertyType type, int index); - bool has(property::PropertyType type, int index); + [[nodiscard]] Property get(property::PropertyType type, int index); + [[nodiscard]] bool has(property::PropertyType type, int index); template ::value, int>::type = 0> - bool has(T type) { return this->has(property::type_from_enum(), (int) type); } + [[nodiscard]] bool has(T type) { return this->has(property::type_from_enum(), (int) type); } private: - bool register_property_type(property::PropertyType /* type */, size_t /* length */); + void do_register_property_type(property::PropertyType /* type */, size_t /* length */); bool save{true}; - std::vector> notifyFunctions{}; + std::vector> notifyFunctions{}; size_t properties_count{0}; std::vector> properties; diff --git a/src/converters/converter.h b/src/converters/converter.h index 761ed4c..21a8c25 100644 --- a/src/converters/converter.h +++ b/src/converters/converter.h @@ -10,16 +10,18 @@ namespace ts { /* Converter stuff */ template struct converter { - static constexpr bool supported = false; + static constexpr bool supported{false}; + static constexpr bool references{false}; static constexpr std::string(*to_string)(const std::any&) = nullptr; static constexpr T(*from_string_view)(const std::string_view&) = nullptr; }; - #define DECLARE_CONVERTER(type, decode, encode) \ + #define DECLARE_CONVERTER(type, decode, encode, references_) \ template <> \ struct converter { \ - static constexpr bool supported = true; \ + static constexpr bool supported{true}; \ + static constexpr bool references{references_}; \ \ static constexpr std::string(*to_string)(const std::any&) = encode; \ static constexpr type(*from_string_view)(const std::string_view&) = decode; \ @@ -29,38 +31,38 @@ namespace ts { #define CONVERTER_METHOD_ENCODE(type, name) std::string name(const std::any& value) /* helper for primitive types */ - #define CONVERTER_PRIMITIVE(type) \ + #define CONVERTER_PRIMITIVE(type, references) \ namespace impl { \ CONVERTER_METHOD_DECODE(type, converter_ ##type ##_decode); \ CONVERTER_METHOD_ENCODE(type, converter_ ##type ##_encode); \ } \ - DECLARE_CONVERTER(type, ::ts::impl::converter_ ##type ##_decode, ::ts::impl::converter_ ##type ##_encode); + DECLARE_CONVERTER(type, ::ts::impl::converter_ ##type ##_decode, ::ts::impl::converter_ ##type ##_encode, references); - CONVERTER_PRIMITIVE(bool); - CONVERTER_PRIMITIVE(float); - CONVERTER_PRIMITIVE(double); - CONVERTER_PRIMITIVE(long_double); + CONVERTER_PRIMITIVE(bool, false); + CONVERTER_PRIMITIVE(float, false); + CONVERTER_PRIMITIVE(double, false); + CONVERTER_PRIMITIVE(long_double, false); - CONVERTER_PRIMITIVE(int8_t); - CONVERTER_PRIMITIVE(uint8_t); + CONVERTER_PRIMITIVE(int8_t, false); + CONVERTER_PRIMITIVE(uint8_t, false); - CONVERTER_PRIMITIVE(int16_t); - CONVERTER_PRIMITIVE(uint16_t); + CONVERTER_PRIMITIVE(int16_t, false); + CONVERTER_PRIMITIVE(uint16_t, false); - CONVERTER_PRIMITIVE(int32_t); - CONVERTER_PRIMITIVE(uint32_t); + CONVERTER_PRIMITIVE(int32_t, false); + CONVERTER_PRIMITIVE(uint32_t, false); - CONVERTER_PRIMITIVE(int64_t); - CONVERTER_PRIMITIVE(uint64_t); + CONVERTER_PRIMITIVE(int64_t, false); + CONVERTER_PRIMITIVE(uint64_t, false); #if __x86_64__ - CONVERTER_PRIMITIVE(long_long_unsigned_int_t); + CONVERTER_PRIMITIVE(long_long_unsigned_int_t, false); #endif typedef std::string std__string; typedef std::string_view std__string_view; typedef const char* const_char__; - CONVERTER_PRIMITIVE(std__string); - CONVERTER_PRIMITIVE(std__string_view); - CONVERTER_PRIMITIVE(const_char__); + CONVERTER_PRIMITIVE(std__string, false); + CONVERTER_PRIMITIVE(std__string_view, true); + CONVERTER_PRIMITIVE(const_char__, true); /* const expr char literal */ template @@ -78,13 +80,14 @@ namespace ts { namespace ts { \ template <> \ struct converter { \ - static constexpr bool supported = true; \ + static constexpr bool supported{true}; \ + static constexpr bool references{false}; \ \ - static constexpr std::string(*to_string)(const std::any&) = [](const std::any& val) { \ - return std::to_string(std::any_cast(val)); \ - }; \ - static constexpr class(*from_string_view)(const std::string_view&) = [](const std::string_view& val) { \ - return ((class(*)(const std::string_view&)) ts::converter::from_string_view)(val); \ + static constexpr std::string(*to_string)(const std::any&) = [](const std::any& val) { \ + return std::to_string(std::any_cast(val)); \ + }; \ + static constexpr class(*from_string_view)(const std::string_view&) = [](const std::string_view& val) { \ + return ((class(*)(const std::string_view&)) ts::converter::from_string_view)(val); \ }; \ }; \ }