/*
* 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