diff --git a/src/PermissionManager.cpp b/src/PermissionManager.cpp index 0f50ae7..fa1a147 100644 --- a/src/PermissionManager.cpp +++ b/src/PermissionManager.cpp @@ -1205,14 +1205,41 @@ const v2::PermissionContainer v2::PermissionManager::channel_permission(const Pe return empty_channel_permission; } -void v2::PermissionManager::set_permission(const PermissionType &permission, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { +inline v2::PermissionContainer duplicate_permission_container(const v2::PermissionContainer& original) { + v2::PermissionContainer result{}; + result.flags = original.flags; + result.values.grant = original.values.grant; + result.values.value = original.values.value; + return result; +} + +static v2::PermissionContainer kEmptyPermissionContainer{ + .flags = v2::PermissionFlags{ + .database_reference = false, + .channel_specific = false, + + .value_set = false, + .grant_set = false, + + .skip = false, + .negate = false, + + .flag_value_update = false, + .flag_grant_update = false + }, + .values = v2::PermissionValues{0, 0} +}; + +v2::PermissionContainer v2::PermissionManager::set_permission(const PermissionType &permission, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { if(permission < 0 || permission >= PermissionType::permission_id_max) - return; + return kEmptyPermissionContainer; const auto block = this->calculate_block(permission); this->ref_allocate_block(block); auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + auto old_state = duplicate_permission_container(data); + if(action_value == v2::PermissionUpdateType::set_value) { data.flags.value_set = true; data.flags.flag_value_update = true; @@ -1245,11 +1272,13 @@ void v2::PermissionManager::set_permission(const PermissionType &permission, con this->unref_block(block); this->trigger_db_update(); + + return old_state; } -void v2::PermissionManager::set_channel_permission(const PermissionType &permission, ChannelId channel_id, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { +v2::PermissionContainer v2::PermissionManager::set_channel_permission(const PermissionType &permission, ChannelId channel_id, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { if(permission < 0 || permission >= PermissionType::permission_id_max) - return; + return kEmptyPermissionContainer; unique_lock channel_perm_lock(this->channel_list_lock); ChannelPermissionContainer* permission_container = nullptr; @@ -1259,13 +1288,13 @@ void v2::PermissionManager::set_channel_permission(const PermissionType &permiss break; } - /* register a new permission if we have no permission already*/ - if(!permission_container || !permission_container->flags.permission_set()) { /* if the permission isn't set then we have to register it again */ - if(action_value != v2::PermissionUpdateType::set_value && action_grant == v2::PermissionUpdateType::set_value) { - return; /* we were never willing to set this permission */ + /* register a new permission if we have no permission already */ + if(!permission_container) { /* if the permission isn't set then we have to register it again */ + if(action_value != v2::PermissionUpdateType::set_value && action_grant != v2::PermissionUpdateType::set_value) { + return kEmptyPermissionContainer; /* we were never willing to set this permission */ } - if(!permission_container) { + { auto container = make_unique(); container->permission = permission; container->channel_id = channel_id; @@ -1274,13 +1303,16 @@ void v2::PermissionManager::set_channel_permission(const PermissionType &permiss } /* now set the channel flag for that permission */ - const auto block = this->calculate_block(permission); - this->ref_allocate_block(block); + { + const auto block = this->calculate_block(permission); + this->ref_allocate_block(block); - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - data.flags.channel_specific = true; - this->unref_block(block); + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + data.flags.channel_specific = true; + this->unref_block(block); + } } + auto old_state = duplicate_permission_container(*permission_container); if(action_value == v2::PermissionUpdateType::set_value) { permission_container->flags.value_set = true; @@ -1321,6 +1353,7 @@ void v2::PermissionManager::set_channel_permission(const PermissionType &permiss } } this->trigger_db_update(); + return old_state; } const std::vector> v2::PermissionManager::permissions() { diff --git a/src/PermissionManager.h b/src/PermissionManager.h index 8d1de53..38239bc 100644 --- a/src/PermissionManager.h +++ b/src/PermissionManager.h @@ -757,7 +757,7 @@ namespace ts { bool flag_value_update: 1; bool flag_grant_update: 1; - ts_always_inline bool permission_set() { + [[nodiscard]] ts_always_inline bool permission_set() const { return this->value_set || this->grant_set; } }; @@ -863,24 +863,24 @@ namespace ts { /* general getters/setters */ const PermissionFlags permission_flags(const PermissionType&); /* we return a "copy" because the actual permission could be deleted while we're analyzing the flags */ - ts_always_inline const PermissionFlags permission_flags(const std::shared_ptr& permission_info) { return this->permission_flags(permission_info->type); } + ts_always_inline PermissionFlags permission_flags(const std::shared_ptr& permission_info) { return this->permission_flags(permission_info->type); } const PermissionValues permission_values(const PermissionType&); - ts_always_inline const PermissionValues permission_values(const std::shared_ptr& permission_info) { return this->permission_values(permission_info->type); } + ts_always_inline PermissionValues permission_values(const std::shared_ptr& permission_info) { return this->permission_values(permission_info->type); } const PermissionFlaggedValue permission_value_flagged(const PermissionType&); - ts_always_inline const PermissionFlaggedValue permission_value_flagged(const std::shared_ptr& permission_info) { return this->permission_value_flagged(permission_info->type); } + ts_always_inline PermissionFlaggedValue permission_value_flagged(const std::shared_ptr& permission_info) { return this->permission_value_flagged(permission_info->type); } const PermissionFlaggedValue permission_granted_flagged(const PermissionType&); - ts_always_inline const PermissionFlaggedValue permission_granted_flagged(const std::shared_ptr& permission_info) { return this->permission_granted_flagged(permission_info->type); } + ts_always_inline PermissionFlaggedValue permission_granted_flagged(const std::shared_ptr& permission_info) { return this->permission_granted_flagged(permission_info->type); } /* only worth looking up if channel_specific is set */ const PermissionContainer channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */); - ts_always_inline const PermissionContainer channel_permission(const std::shared_ptr& permission_info, ChannelId channel_id) { return this->channel_permission(permission_info->type, channel_id); } + ts_always_inline PermissionContainer channel_permission(const std::shared_ptr& permission_info, ChannelId channel_id) { return this->channel_permission(permission_info->type, channel_id); } /* modifiers */ - void set_permission(const PermissionType& /* permission */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); - void set_channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); + PermissionContainer set_permission(const PermissionType& /* permission */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); + PermissionContainer set_channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); /* bulk info */ const std::vector> permissions(); diff --git a/src/query/command3.h b/src/query/command3.h index 028fbe5..cc092df 100644 --- a/src/query/command3.h +++ b/src/query/command3.h @@ -181,22 +181,22 @@ namespace ts { friend class command_builder_impl; public: inline void reserve(size_t length, bool accumulative = true) { - this->bulk.reserve(length + (accumulative ? this->bulk.size() : 0)); + this->bulk->reserve(length + (accumulative ? this->bulk->size() : 0)); } inline void reset() { - this->bulk.clear(); + this->bulk->clear(); } inline void put(const std::string_view& key, const std::string_view& value) { size_t begin, end; - if(impl::value_raw_impl(this->bulk, key, begin, &end)) { + if(impl::value_raw_impl(*this->bulk, key, begin, &end)) { std::string result{}; - result.reserve(this->bulk.size()); + result.reserve(this->bulk->size()); - result.append(this->bulk, 0, begin - key.size() - 1); /* key incl = */ - result.append(this->bulk, end + 1); /* get rid of the space */ - this->bulk = result; + result.append(*this->bulk, 0, begin - key.size() - 1); /* key incl = */ + result.append(*this->bulk, end + 1); /* get rid of the space */ + *this->bulk = result; } this->impl_put_unchecked(key, value); } @@ -239,25 +239,42 @@ namespace ts { auto data = converter::to_string(value); this->put_unchecked(key, std::string_view{data}); } + + protected: + explicit command_builder_bulk(bool& change_flag, std::string& bulk) : flag_changed{&change_flag}, bulk{&bulk} {} + private: - bool& flag_changed; - std::string& bulk; - explicit command_builder_bulk(bool& change_flag, std::string& bulk) : flag_changed{change_flag}, bulk{bulk} {} + bool* flag_changed; + std::string* bulk; void impl_put_unchecked(const std::string_view& key, const std::string_view& value) { auto escaped_value = ts::query::escape(std::string{value}); - this->bulk.reserve(this->bulk.length() + key.size() + escaped_value.size() + 2); - this->bulk.append(key); + this->bulk->reserve(this->bulk->length() + key.size() + escaped_value.size() + 2); + this->bulk->append(key); if(!escaped_value.empty()) { - this->bulk.append("="); - this->bulk.append(escaped_value); + this->bulk->append("="); + this->bulk->append(escaped_value); } - this->bulk.append(" "); - this->flag_changed = true; + this->bulk->append(" "); + *this->flag_changed = true; } }; + class standalone_command_builder_bulk : public command_builder_bulk { + public: + explicit standalone_command_builder_bulk(size_t expected_length = 0) : command_builder_bulk{this->flag_changed_, this->buffer_} { + if(expected_length > 0) + this->buffer_.reserve(expected_length); + } + + [[nodiscard]] inline const std::string& buffer() const { return this->buffer_; } + [[nodiscard]] inline std::string& buffer() { return this->buffer_; } + private: + bool flag_changed_{}; + std::string buffer_{}; + }; + template > class command_builder_impl { public: @@ -324,6 +341,18 @@ namespace ts { return result; } + inline void push_bulk(standalone_command_builder_bulk&& bulk) { + this->bulks.push_back(std::move(bulk.buffer())); + this->flag_changed = true; + } + + inline void set_bulk(size_t index, standalone_command_builder_bulk&& bulk) { + while(this->bulks.size() <= index) + this->bulks.emplace_back("").reserve(expected_bulk_size); + this->bulks[index] = std::move(bulk.buffer()); + this->flag_changed = true; + } + inline void reset() { for(auto& bulk : this->bulks) bulk = " "; diff --git a/src/sql/SqlQuery.h b/src/sql/SqlQuery.h index f78f9c6..ae8da15 100644 --- a/src/sql/SqlQuery.h +++ b/src/sql/SqlQuery.h @@ -262,25 +262,27 @@ namespace sql { friend class ::sql::command; friend class ::sql::model; public: + explicit command_base(nullptr_t) : _data{nullptr} {} + command_base(SqlManager* handle, const std::string &sql, std::initializer_list values) { assert(handle); assert(!sql.empty()); this->_data = handle->allocateCommandData(); this->_data->handle = handle; this->_data->sql_command = sql; - this->__data = this->_data.get(); - for(const auto& val : values) this->value(val); + for(const auto& val : values) + this->value(val); } template - command_base(SqlManager* handle, std::string sql, Ts&&... vars) : command_base(handle, sql, {}) { values(vars...); } + command_base(SqlManager* handle, const std::string& sql, Ts&&... vars) : command_base(handle, sql, {}) { values(vars...); } - command_base(const command_base& ref) : _data(ref._data), __data(ref._data.get()) {} - command_base(command_base&& ref) noexcept : _data(ref._data), __data(ref._data.get()) { } + command_base(const command_base& ref) : _data(ref._data) {} + command_base(command_base&& ref) noexcept : _data(ref._data) { } virtual ~command_base() = default; - virtual SelfType& value(const variable& val) { + SelfType& value(const variable& val) { this->_data->variables.push_back(val); return *(SelfType*) this; } @@ -303,10 +305,20 @@ namespace sql { std::string sqlCommand(){ return _data->sql_command; } SqlManager* handle(){ return _data->handle; } + + command_base& operator=(const command_base& other) { + this->_data = other._data; + return *this; + } + + command_base& operator=(command_base&& other) { + this->_data = std::move(other._data); + return *this; + } + protected: - explicit command_base(const std::shared_ptr& data) : _data(data), __data(data.get()) {} + explicit command_base(std::shared_ptr data) : _data(std::move(data)) {} std::shared_ptr _data; - CommandData* __data = nullptr; }; } @@ -317,13 +329,13 @@ namespace sql { template model(SqlManager* handle, const std::string &sql, Ts... vars) : model(handle, sql, {}) { values(vars...); } - model(const model& v) : command_base(v) {}; - model(model&& v) noexcept : command_base(v){}; - ~model() override {}; + explicit model(nullptr_t) : command_base{nullptr} {}; + //model(const model& v) : command_base{v} {}; + //model(model&& v) noexcept : command_base{std::forward(v)} {}; + ~model() override = default; sql::command command(); sql::model copy(); - private: explicit model(const std::shared_ptr&); };