Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Rewrite AMF and property behavior logic to use smart pointers, references, and string_views over raw pointers and std::string& #1452

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fca5623
Rewrite AMF and behavior logic to use smart pointers, references, and…
jadebenn Feb 11, 2024
acd601f
fix m_BehaviorID initialization
jadebenn Feb 11, 2024
c75cef2
Fix BlockDefinition member naming
jadebenn Feb 11, 2024
07b5135
remove redundant reset()s
jadebenn Feb 11, 2024
7e036a3
Replace UB forward template declarations with header include
jadebenn Feb 11, 2024
08608c7
Merge remote-tracking branch 'upstream/main' into AMFUniquePtrs
jadebenn Feb 11, 2024
b8498c3
remove unneeded comment
jadebenn Feb 11, 2024
1bb82b8
remove non-const ref getters
jadebenn Feb 11, 2024
b89488b
simplify default behavior id initialization
jadebenn Feb 11, 2024
0f1922a
Fix invalidated use of Getter to set a value
jadebenn Feb 11, 2024
ab5ed7d
Update AddStripMessage.cpp - change push_back to emplace_back
jadebenn Feb 12, 2024
188462e
fix pointer to ref conversion mistake (should not have directly grabb…
jadebenn Feb 12, 2024
797eeb5
deref
jadebenn Feb 14, 2024
e381ef7
VERY experimental testing of forward declaration of templates - proba…
jadebenn Feb 18, 2024
b2b21a8
Revert changes (as expected)
jadebenn Feb 18, 2024
2798ee2
Merge remote-tracking branch 'upstream/main' into AMFUniquePtrs
jadebenn Feb 19, 2024
cee38f5
Update BlockDefinition.h - remove extraneous semicolons
jadebenn Feb 19, 2024
c9f2b31
Update BlockDefinition.h - remove linebreak
jadebenn Feb 19, 2024
f5e9bd8
Merge remote-tracking branch 'upstream/main' into AMFUniquePtrs
jadebenn Feb 25, 2024
2d7165a
Update Amf3.h member naming scheme
jadebenn Feb 25, 2024
9bb5089
Merge remote-tracking branch 'upstream/AMFClassNaming' into AMFUnique…
jadebenn Feb 25, 2024
7cfc10c
Merge remote-tracking branch 'upstream/main' into AMFUniquePtrs
jadebenn Feb 25, 2024
da613ad
fix duplicated code
jadebenn Feb 25, 2024
939eb61
const iterators
jadebenn Feb 25, 2024
9f8cff8
const pointers
jadebenn Feb 25, 2024
cf569f7
Merge remote-tracking branch 'upstream/main' into AMFUniquePtrs
jadebenn Feb 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions dCommon/AMFDeserialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@
* AMF3 Deserializer written by EmosewaMC
*/

AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) {
AMFBaseValue* returnValue = nullptr;
std::unique_ptr<AMFBaseValue> AMFDeserialize::Read(RakNet::BitStream& inStream) {
std::unique_ptr<AMFBaseValue> returnValue = nullptr;
// Read in the value type from the bitStream
eAmf marker;
inStream.Read(marker);
// Based on the typing, create the value associated with that and return the base value class
switch (marker) {
case eAmf::Undefined: {
returnValue = new AMFBaseValue();
returnValue = std::make_unique<AMFBaseValue>();
break;
}

case eAmf::Null: {
returnValue = new AMFNullValue();
returnValue = std::make_unique<AMFNullValue>();
break;
}

case eAmf::False: {
returnValue = new AMFBoolValue(false);
returnValue = std::make_unique<AMFBoolValue>(false);
break;
}

case eAmf::True: {
returnValue = new AMFBoolValue(true);
returnValue = std::make_unique<AMFBoolValue>(true);
break;
}

Expand Down Expand Up @@ -118,14 +118,14 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
}
}

AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
std::unique_ptr<AMFDoubleValue> AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
double value;
inStream.Read<double>(value);
return new AMFDoubleValue(value);
return std::make_unique<AMFDoubleValue>(value);
}

AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
auto arrayValue = new AMFArrayValue();
std::unique_ptr<AMFArrayValue> AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
auto arrayValue = std::make_unique<AMFArrayValue>();

// Read size of dense array
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
Expand All @@ -143,10 +143,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
return arrayValue;
}

AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
return new AMFStringValue(ReadString(inStream));
std::unique_ptr<AMFStringValue> AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
return std::make_unique<AMFStringValue>(ReadString(inStream));
}

AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
return new AMFIntValue(ReadU29(inStream));
std::unique_ptr<AMFIntValue> AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
return std::make_unique<AMFIntValue>(ReadU29(inStream)); // NOTE: NARROWING CONVERSION FROM UINT TO INT. IS THIS INTENDED?
}
14 changes: 7 additions & 7 deletions dCommon/AMFDeserialize.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#pragma once

#include "Amf3.h"
#include "BitStream.h"

#include <memory>
#include <vector>
#include <string>

class AMFBaseValue;

class AMFDeserialize {
public:
/**
Expand All @@ -15,7 +15,7 @@ class AMFDeserialize {
* @param inStream inStream to read value from.
* @return Returns an AMFValue with all the information from the bitStream in it.
*/
AMFBaseValue* Read(RakNet::BitStream& inStream);
std::unique_ptr<AMFBaseValue> Read(RakNet::BitStream& inStream);
private:
/**
* @brief Private method to read a U29 integer from a bitstream
Expand All @@ -39,31 +39,31 @@ class AMFDeserialize {
* @param inStream bitStream to read data from
* @return Double value represented as an AMFValue
*/
AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream);
static std::unique_ptr<AMFDoubleValue> ReadAmfDouble(RakNet::BitStream& inStream);

/**
* @brief Read an AMFArray from a bitStream
*
* @param inStream bitStream to read data from
* @return Array value represented as an AMFValue
*/
AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream);
std::unique_ptr<AMFArrayValue> ReadAmfArray(RakNet::BitStream& inStream);

/**
* @brief Read an AMFString from a bitStream
*
* @param inStream bitStream to read data from
* @return String value represented as an AMFValue
*/
AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream);
std::unique_ptr<AMFStringValue> ReadAmfString(RakNet::BitStream& inStream);

/**
* @brief Read an AMFInteger from a bitStream
*
* @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue
*/
AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream);
static std::unique_ptr<AMFIntValue> ReadAmfInteger(RakNet::BitStream& inStream);

/**
* List of strings read so far saved to be read by reference.
Expand Down
91 changes: 35 additions & 56 deletions dCommon/Amf3.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,14 @@ using AMFDoubleValue = AMFValue<double>;
* and are not to be deleted by a caller.
*/
class AMFArrayValue : public AMFBaseValue {
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
using AMFDense = std::vector<AMFBaseValue*>;
using AMFAssociative =
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<>>;

using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;

public:
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }

~AMFArrayValue() override {
for (const auto* valueToDelete : GetDense()) {
if (valueToDelete) {
delete valueToDelete;
valueToDelete = nullptr;
}
}
for (auto valueToDelete : GetAssociative()) {
if (valueToDelete.second) {
delete valueToDelete.second;
valueToDelete.second = nullptr;
}
}
}

/**
* Returns the Associative portion of the object
*/
Expand All @@ -151,46 +138,46 @@ class AMFArrayValue : public AMFBaseValue {
* or nullptr if a key existed and was not the same type
*/
template <typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) {
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string_view key, const ValueType value) {
const auto element = m_Associative.find(key);
AMFValue<ValueType>* val = nullptr;
bool found = true;
if (element == m_Associative.cend()) {
val = new AMFValue<ValueType>(value);
m_Associative.emplace(key, val);
auto newVal = std::make_unique<AMFValue<ValueType>>(value);
val = newVal.get();
m_Associative.emplace(key, std::move(newVal));
} else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
val = dynamic_cast<AMFValue<ValueType>*>(element->second.get());
found = false;
}
return std::make_pair(val, found);
}

// Associates an array with a string key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string_view key) {
const auto element = m_Associative.find(key);
AMFArrayValue* val = nullptr;
bool found = true;
if (element == m_Associative.cend()) {
val = new AMFArrayValue();
m_Associative.emplace(key, val);
auto newVal = std::make_unique<AMFArrayValue>();
val = newVal.get();
m_Associative.emplace(key, std::move(newVal));
} else {
val = dynamic_cast<AMFArrayValue*>(element->second);
val = dynamic_cast<AMFArrayValue*>(element->second.get());
found = false;
}
return std::make_pair(val, found);
}

// Associates an array with an integer key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
AMFArrayValue* val = nullptr;
bool inserted = false;
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
val = new AMFArrayValue();
m_Dense.at(index) = val;
m_Dense.at(index) = std::make_unique<AMFArrayValue>();
inserted = true;
}
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index)), inserted);
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()), inserted);
}

/**
Expand All @@ -205,15 +192,13 @@ class AMFArrayValue : public AMFBaseValue {
*/
template <typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
AMFValue<ValueType>* val = nullptr;
bool inserted = false;
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
val = new AMFValue<ValueType>(value);
m_Dense.at(index) = val;
m_Dense.at(index) = std::make_unique<AMFValue<ValueType>>(value);
inserted = true;
}
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index)), inserted);
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index).get()), inserted);
}

/**
Expand All @@ -225,13 +210,12 @@ class AMFArrayValue : public AMFBaseValue {
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const std::string& key, AMFBaseValue* const value) {
void Insert(const std::string_view key, std::unique_ptr<AMFBaseValue> value) {
const auto element = m_Associative.find(key);
if (element != m_Associative.cend() && element->second) {
delete element->second;
element->second = value;
element->second = std::move(value);
} else {
m_Associative.emplace(key, value);
m_Associative.emplace(key, std::move(value));
}
}

Expand All @@ -244,14 +228,11 @@ class AMFArrayValue : public AMFBaseValue {
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const size_t index, AMFBaseValue* const value) {
if (index < m_Dense.size()) {
const AMFDense::const_iterator itr = m_Dense.cbegin() + index;
if (*itr) delete m_Dense.at(index);
} else {
void Insert(const size_t index, std::unique_ptr<AMFBaseValue> value) {
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
}
m_Dense.at(index) = value;
m_Dense.at(index) = std::move(value);
}

/**
Expand Down Expand Up @@ -279,8 +260,7 @@ class AMFArrayValue : public AMFBaseValue {
void Remove(const std::string& key, const bool deleteValue = true) {
const AMFAssociative::const_iterator it = m_Associative.find(key);
if (it != m_Associative.cend()) {
if (deleteValue) delete it->second;
m_Associative.erase(it);
if (deleteValue) m_Associative.erase(it);
}
}

Expand All @@ -290,7 +270,6 @@ class AMFArrayValue : public AMFBaseValue {
void Remove(const size_t index) {
if (!m_Dense.empty() && index < m_Dense.size()) {
const auto itr = m_Dense.cbegin() + index;
if (*itr) delete (*itr);
m_Dense.erase(itr);
}
}
Expand All @@ -299,16 +278,16 @@ class AMFArrayValue : public AMFBaseValue {
if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
}

[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const {
[[nodiscard]] AMFArrayValue* GetArray(const std::string_view key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second) : nullptr;
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second.get()) : nullptr;
}

[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index)) : nullptr;
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()) : nullptr;
}

[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) {
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string_view key) {
return static_cast<AMFArrayValue*>(Insert(key).first);
}

Expand All @@ -330,17 +309,17 @@ class AMFArrayValue : public AMFBaseValue {
* @return The AMFValue
*/
template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const {
[[nodiscard]] AMFValue<AmfType>* Get(const std::string_view key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != m_Associative.cend() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) :
dynamic_cast<AMFValue<AmfType>*>(it->second.get()) :
nullptr;
}

// Get from the array but dont cast it
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const {
[[nodiscard]] AMFBaseValue* Get(const std::string_view key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != m_Associative.cend() ? it->second : nullptr;
return it != m_Associative.cend() ? it->second.get() : nullptr;
}

/**
Expand All @@ -355,13 +334,13 @@ class AMFArrayValue : public AMFBaseValue {
template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
return index < m_Dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index)) :
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index).get()) :
nullptr;
}

// Get from the dense but dont cast it
[[nodiscard]] AMFBaseValue* Get(const size_t index) const {
return index < m_Dense.size() ? m_Dense.at(index) : nullptr;
return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
}

private:
Expand Down
23 changes: 23 additions & 0 deletions dCommon/GeneralUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,29 @@ namespace GeneralUtils {

std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);

/**
* Transparent string hasher - used to allow string_view key lookups for maps storing std::string keys
* https://www.reddit.com/r/cpp_questions/comments/12xw3sn/find_stdstring_view_in_unordered_map_with/jhki225/
* https://godbolt.org/z/789xv8Eeq
*/
template <typename... Bases>
struct overload : Bases... {
using is_transparent = void;
using Bases::operator() ... ;
};

struct char_pointer_hash {
auto operator()(const char* const ptr) const noexcept {
return std::hash<std::string_view>{}(ptr);
}
};

using transparent_string_hash = overload<
std::hash<std::string>,
std::hash<std::string_view>,
char_pointer_hash
>;

// Concept constraining to enum types
template <typename T>
concept Enum = std::is_enum_v<T>;
Expand Down
4 changes: 2 additions & 2 deletions dGame/dComponents/ModelComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ class ModelComponent final : public Component {
template<typename Msg>
void HandleControlBehaviorsMsg(const AMFArrayValue& args) {
static_assert(std::is_base_of_v<BehaviorMessageBase, Msg>, "Msg must be a BehaviorMessageBase");
Msg msg(args);
for (auto& behavior : m_Behaviors) {
Msg msg{ args };
for (auto&& behavior : m_Behaviors) {
if (behavior.GetBehaviorId() == msg.GetBehaviorId()) {
behavior.HandleMsg(msg);
return;
Expand Down
Loading
Loading