/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef UpdateField_h__ #define UpdateField_h__ #include "ObjectGuid.h" #include "Optional.h" #include "UpdateMask.h" #include #include #include #include class ByteBuffer; class Object; namespace UF { enum class UpdateFieldFlag : uint8 { None = 0, Owner = 0x01, PartyMember = 0x02, UnitAll = 0x04, Empath = 0x08 }; DEFINE_ENUM_FLAG(UpdateFieldFlag); template class UpdateFieldBase; template class UpdateField; template class UpdateFieldArrayBaseWithoutSize; template class UpdateFieldArrayBase; template class UpdateFieldArray; template class DynamicUpdateFieldBase; template class DynamicUpdateField; template class OptionalUpdateFieldBase; template class OptionalUpdateField; template inline constexpr std::type_identity VariantCase; template class VariantUpdateFieldBase; template class VariantUpdateField; template struct MutableFieldReferenceWithChangesMask; template struct MutableFieldReferenceNoChangesMask; template struct MutableNestedFieldReference; struct IsUpdateFieldStructureTag { }; struct HasChangesMaskTag { }; struct IsUpdateFieldHolderTag { }; template struct UpdateFieldPrivateSetter { using value_type = T; template friend bool SetUpdateFieldValue(UpdateFieldPrivateSetter& setter, typename UpdateFieldPrivateSetter::value_type&& value); UpdateFieldPrivateSetter(T& value) : _value(value) { } T GetValue() const { return _value; } private: bool SetValue(T value) { if (_value != value) { _value = std::move(value); return true; } return false; } T& _value; }; // Same as UpdateFieldSetter but with public setter, used to set member fields for values added to dynamic fields template struct UpdateFieldPublicSetter { using value_type = T; UpdateFieldPublicSetter(T& value) : _value(value) { } T GetValue() const { return _value; } void SetValue(T value) { _value = std::move(value); } private: T& _value; }; template using UpdateFieldSetter = std::conditional_t, UpdateFieldPrivateSetter>; template using MutableFieldReference = std::conditional_t, MutableFieldReferenceWithChangesMask, MutableFieldReferenceNoChangesMask>; template struct DynamicUpdateFieldSetter { using value_type = T; using insert_result = std::conditional_t, MutableFieldReference, T&>; template friend typename DynamicUpdateFieldSetter::insert_result AddDynamicUpdateFieldValue(DynamicUpdateFieldSetter& setter); template friend typename DynamicUpdateFieldSetter::insert_result InsertDynamicUpdateFieldValue(DynamicUpdateFieldSetter& setter, uint32 index); template friend void RemoveDynamicUpdateFieldValue(DynamicUpdateFieldSetter& setter, uint32 index); template friend void ClearDynamicUpdateFieldValues(DynamicUpdateFieldSetter& setter); DynamicUpdateFieldSetter(std::vector& values, std::vector& updateMask) : _values(values), _updateMask(updateMask) { } private: insert_result AddValue() { MarkChanged(_values.size()); T& value = _values.emplace_back(); if constexpr (std::is_base_of_v) value._changesMask.SetAll(); return { value }; } insert_result InsertValue(std::size_t index) { _values.emplace(_values.begin() + index); for (std::size_t i = index; i < _values.size(); ++i) { MarkChanged(i); // also mark all fields of value as changed if constexpr (std::is_base_of_v) _values[i]._changesMask.SetAll(); } return { _values[index] }; } void RemoveValue(std::size_t index) { // remove by shifting entire container - client might rely on values being sorted for certain fields _values.erase(_values.begin() + index); for (std::size_t i = index; i < _values.size(); ++i) { MarkChanged(i); // also mark all fields of value as changed if constexpr (std::is_base_of_v) _values[i]._changesMask.SetAll(); } if (_values.size() % 32) _updateMask[UpdateMaskHelpers::GetBlockIndex(_values.size())] &= ~UpdateMaskHelpers::GetBlockFlag(_values.size()); else _updateMask.pop_back(); } void Clear() { _values.clear(); _updateMask.clear(); } void MarkChanged(std::size_t index) { std::size_t block = UpdateMaskHelpers::GetBlockIndex(index); if (block >= _updateMask.size()) _updateMask.resize(block + 1); _updateMask[block] |= UpdateMaskHelpers::GetBlockFlag(index); } std::vector& _values; std::vector& _updateMask; }; template struct OptionalUpdateFieldSetter { template friend void RemoveOptionalUpdateFieldValue(OptionalUpdateFieldSetter& setter); OptionalUpdateFieldSetter(OptionalUpdateFieldBase& field) : _field(field) { } private: void RemoveValue() { if (_field.has_value()) _field.DestroyValue(); } OptionalUpdateFieldBase& _field; }; template struct MutableFieldReferenceWithChangesMask { MutableFieldReferenceWithChangesMask(T& value) : _value(value) { } template std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>> ModifyValue(UpdateField(T::* field)) { if constexpr (BlockBit >= 0) _value._changesMask.Set(BlockBit); _value._changesMask.Set(Bit); return { (_value.*field)._value }; } template std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>> ModifyValue(UpdateFieldArray(T::* field), uint32 index) { _value._changesMask.Set(Bit); if constexpr (FirstElementBit >= 0) { if constexpr (!std::is_base_of_v) _value._changesMask.Set(FirstElementBit + index); else _value._changesMask.Set(FirstElementBit); } return { (_value.*field)._values[index] }; } template DynamicUpdateFieldSetter ModifyValue(DynamicUpdateField(T::* field)) { if constexpr (BlockBit >= 0) _value._changesMask.Set(BlockBit); _value._changesMask.Set(Bit); return { (_value.*field)._values, (_value.*field)._updateMask }; } template std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>> ModifyValue(DynamicUpdateField(T::* field), uint32 index) { if (index >= (_value.*field).size()) { // fill with zeros until reaching desired slot (_value.*field)._values.resize(index + 1); (_value.*field)._updateMask.resize((index + 1 + 31) / 32); } if constexpr (BlockBit >= 0) _value._changesMask.Set(BlockBit); _value._changesMask.Set(Bit); (_value.*field).MarkChanged(index); return { (_value.*field)._values[index] }; } template OptionalUpdateFieldSetter ModifyValue(OptionalUpdateField(T::* field)) { if constexpr (BlockBit >= 0) _value._changesMask.Set(BlockBit); _value._changesMask.Set(Bit); return { _value.*field }; } template std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>> ModifyValue(OptionalUpdateField(T::* field), uint32 /*dummy*/) { if (!(_value.*field).has_value()) (_value.*field).ConstructValue(); if constexpr (BlockBit >= 0) _value._changesMask.Set(BlockBit); _value._changesMask.Set(Bit); return { *((_value.*field)._value) }; } template std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>> ModifyValue(VariantUpdateField(T::* field), [[maybe_unused]] std::type_identity type) { if (!(_value.*field).template Is()) (_value.*field).template ConstructValue(); if constexpr (BlockBit >= 0) _value._changesMask.Set(BlockBit); _value._changesMask.Set(Bit); return { *((_value.*field).template Get()) }; } private: T& _value; }; template struct MutableFieldReferenceNoChangesMask { MutableFieldReferenceNoChangesMask(T& value) : _value(value) { } template UpdateFieldSetter ModifyValue(V(T::* field)) { return { _value.*field }; } template UpdateFieldSetter ModifyValue(V(T::* field)[Size], uint32 index) { return { (_value.*field)[index] }; } private: T& _value; }; template struct MutableNestedFieldReference { using value_type = typename T::value_type; MutableNestedFieldReference(T& value) : _value(value) { } template std::enable_if_t, U>, std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>>> ModifyValue() { return { _value._value }; } template std::enable_if_t, U>, std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>>> ModifyValue(uint32 index) { return { _value._values[index] }; } template std::enable_if_t, U>, DynamicUpdateFieldSetter> ModifyValue() { return { _value._values, _value._updateMask }; } template std::enable_if_t, U>, std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>>> ModifyValue(uint32 index) { if (index >= _value.size()) { // fill with zeros until reaching desired slot _value._values.resize(index + 1); _value._updateMask.resize((index + 1 + 31) / 32); } _value.MarkChanged(index); return { _value._values[index] }; } template std::enable_if_t, U>, OptionalUpdateFieldSetter> ModifyValue() { return { _value }; } template std::enable_if_t, U>, std::conditional_t, MutableFieldReference, std::conditional_t, MutableNestedFieldReference, UpdateFieldSetter>>> ModifyValue(uint32 /*dummy*/) { if (!_value.has_value()) _value.ConstructValue(); return { *(_value._value) }; } private: T& _value; }; template class HasChangesMask : public HasChangesMaskTag { template friend struct DynamicUpdateFieldSetter; template friend struct MutableFieldReferenceWithChangesMask; template friend struct MutableFieldReferenceNoChangesMask; template friend class UpdateField; template friend class UpdateFieldArray; template friend class DynamicUpdateField; public: using Base = HasChangesMask; using Mask = UpdateMask; template void MarkChanged(UpdateField(Derived::*)) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); if constexpr (BlockBit >= 0) _changesMask.Set(BlockBit); _changesMask.Set(Bit); } template void MarkChanged(UpdateFieldArray(Derived::*), uint32 index) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); _changesMask.Set(Bit); if constexpr (FirstElementBit >= 0) { if constexpr (!std::is_base_of_v) _changesMask.Set(FirstElementBit + index); else _changesMask.Set(FirstElementBit); } } template void MarkChanged(DynamicUpdateField(Derived::*), uint32) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); if constexpr (BlockBit >= 0) _changesMask.Set(BlockBit); _changesMask.Set(Bit); } template void MarkChanged(OptionalUpdateField(Derived::*)) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); if constexpr (BlockBit >= 0) _changesMask.Set(BlockBit); _changesMask.Set(Bit); } template void MarkChanged(VariantUpdateField(Derived::*)) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); if constexpr (BlockBit >= 0) _changesMask.Set(BlockBit); _changesMask.Set(Bit); } template void ClearChanged(UpdateField(Derived::*)) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); _changesMask.Reset(Bit); } template void ClearChanged(UpdateFieldArray(Derived::*), uint32 index) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); if constexpr (FirstElementBit >= 0) { if constexpr (!std::is_base_of_v) _changesMask.Reset(FirstElementBit + index); else _changesMask.Reset(FirstElementBit); } } template void ClearChanged(DynamicUpdateField(Derived::* field), uint32 index) { _changesMask.Reset(Bit); DynamicUpdateField& uf = (static_cast(this)->*field); if (index < uf.size()) uf.ClearChanged(index); } template void ClearChanged(OptionalUpdateField(Derived::*)) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); _changesMask.Reset(Bit); } template void ClearChanged(VariantUpdateField(Derived::*)) { static_assert(std::is_base_of_v, "Given field argument must belong to the same structure as this HasChangesMask"); _changesMask.Reset(Bit); } Mask const& GetChangesMask() const { return _changesMask; } protected: template static void ClearChangesMask(UpdateField& field) { if constexpr (std::is_base_of_v) field._value.ClearChangesMask(); } template static void ClearChangesMask(UpdateFieldArray& field) { if constexpr (std::disjunction_v, std::is_base_of>) for (T& value : field._values) value.ClearChangesMask(); } template static void ClearChangesMask(DynamicUpdateField& field) { if constexpr (std::is_base_of_v) for (T& value : field._values) value.ClearChangesMask(); field.ClearChangesMask(); } template static void ClearChangesMask(OptionalUpdateField& field) { if constexpr (std::is_base_of_v) if (field.has_value()) field._value->ClearChangesMask(); } template static void ClearChangesMask(VariantUpdateField& field) { if constexpr ((std::is_base_of_v || ...)) std::visit([](T& value) { if constexpr (std::is_base_of_v) value.ClearChangesMask(); }, field._value); } Mask _changesMask; }; template class UpdateFieldBase : public IsUpdateFieldHolderTag { template friend struct MutableFieldReferenceWithChangesMask; template friend struct MutableFieldReferenceNoChangesMask; template friend struct MutableNestedFieldReference; template friend class HasChangesMask; friend class UpdateFieldHolder; public: using value_type = T; operator T const& () const { return _value; } T const* operator->() const { return &_value; } T const& operator*() const { return _value; } private: T _value = {}; }; template class UpdateField : public UpdateFieldBase { }; template class UpdateFieldArrayBaseWithoutSize : public IsUpdateFieldHolderTag { }; template class UpdateFieldArrayBase : public UpdateFieldArrayBaseWithoutSize { template friend struct MutableFieldReferenceWithChangesMask; template friend struct MutableFieldReferenceNoChangesMask; template friend struct MutableNestedFieldReference; template friend class HasChangesMask; public: using value_type = T; T const* begin() const { return std::begin(_values); } T const* end() const { return std::end(_values); } static constexpr std::size_t size() { return Size; } T const& operator[](std::size_t index) const { return _values[index]; } private: T _values[Size] = {}; }; // workaround functions for internal compiler errors in msvc 19.33.31629 template constexpr std::size_t size() { return T::size(); } template constexpr std::size_t size_of_value_type() { return sizeof(typename T::value_type); } template class UpdateFieldArray : public UpdateFieldArrayBase { }; void WriteDynamicFieldUpdateMask(std::size_t size, std::vector const& updateMask, ByteBuffer& data, int32 bitsForSize = 32); void WriteCompleteDynamicFieldUpdateMask(std::size_t size, ByteBuffer& data, int32 bitsForSize = 32); template class DynamicUpdateFieldBase : public IsUpdateFieldHolderTag { template friend struct MutableFieldReferenceWithChangesMask; template friend struct MutableFieldReferenceNoChangesMask; template friend struct MutableNestedFieldReference; template friend class HasChangesMask; public: using value_type = T; T const* data() const { return _values.data(); } typename std::vector::const_iterator begin() const { return _values.begin(); } typename std::vector::const_iterator end() const { return _values.end(); } bool empty() const { return _values.empty(); } std::size_t size() const { return _values.size(); } T const& operator[](std::size_t index) const { return _values[index]; } int32 FindIndex(T const& value) const { auto itr = std::find(_values.begin(), _values.end(), value); if (itr != _values.end()) return int32(std::distance(_values.begin(), itr)); return -1; } template int32 FindIndexIf(Pred pred) const { auto itr = std::find_if(_values.begin(), _values.end(), std::ref(pred)); if (itr != _values.end()) return int32(std::distance(_values.begin(), itr)); return -1; } bool HasChanged(uint32 index) const { return (_updateMask[UpdateMaskHelpers::GetBlockIndex(index)] & UpdateMaskHelpers::GetBlockFlag(index)) != 0; } void WriteUpdateMask(ByteBuffer& data, int32 bitsForSize = 32) const { WriteDynamicFieldUpdateMask(_values.size(), _updateMask, data, bitsForSize); } private: void MarkChanged(std::size_t index) { _updateMask[UpdateMaskHelpers::GetBlockIndex(index)] |= UpdateMaskHelpers::GetBlockFlag(index); } void ClearChanged(std::size_t index) { _updateMask[UpdateMaskHelpers::GetBlockIndex(index)] &= ~UpdateMaskHelpers::GetBlockFlag(index); } void ClearChangesMask() { std::memset(_updateMask.data(), 0, _updateMask.size() * sizeof(uint32)); } std::vector _values; std::vector _updateMask; }; template class DynamicUpdateField : public DynamicUpdateFieldBase { }; template class OptionalUpdateFieldBase : public IsUpdateFieldHolderTag { template friend struct MutableFieldReferenceWithChangesMask; template friend struct MutableFieldReferenceNoChangesMask; template friend struct MutableNestedFieldReference; template friend class HasChangesMask; template friend struct OptionalUpdateFieldSetter; friend class UpdateFieldHolder; public: using value_type = T; using IsLarge = std::integral_constant; using StorageType = std::conditional_t, Optional>; bool has_value() const { return !!_value; } operator bool() const { return has_value(); } T const* operator->() const { return &(*_value); } T const& operator*() const { return *_value; } private: void ConstructValue() { if constexpr (IsLarge::value) _value = std::make_unique(); else _value.emplace(); } void DestroyValue() { _value.reset(); } StorageType _value = { }; }; template class OptionalUpdateField : public OptionalUpdateFieldBase { }; template class VariantUpdateFieldBase : public IsUpdateFieldHolderTag { template friend struct MutableFieldReferenceWithChangesMask; template friend struct MutableFieldReferenceNoChangesMask; template friend struct MutableNestedFieldReference; template friend class HasChangesMask; friend class UpdateFieldHolder; public: template bool Is() const { return std::holds_alternative(_value); } template T const* Get() const noexcept { if (std::holds_alternative(_value)) return &std::get(_value); return nullptr; } template decltype(auto) Visit(Visitor&& visitor) const noexcept { return std::visit(std::forward(visitor), _value); } private: template void ConstructValue() { _value.template emplace(); } template T* Get() noexcept { if (std::holds_alternative(_value)) return &std::get(_value); return nullptr; } std::variant _value; }; template class VariantUpdateField : public VariantUpdateFieldBase { }; template struct ViewerDependentValueTag { using value_type = T; }; } #endif // UpdateField_h__