diff --git a/include/fxn/context.hpp b/include/fxn/context.hpp new file mode 100644 index 0000000..677c9c5 --- /dev/null +++ b/include/fxn/context.hpp @@ -0,0 +1,186 @@ +#pragma once +#include +#include +#include + +namespace fxn +{ + struct Vector2 + { + float x; + float y; + }; + + struct Vector3 + { + float x; + float y; + float z; + }; + + struct Vector4 + { + float x; + float y; + float z; + float w; + }; + + struct NativeContext + { + private: + struct scrVector3 + { + alignas(8) float x; + alignas(8) float y; + alignas(8) float z; + }; + + struct alignas(16) scrVector3N + { + float x; + float y; + float z; + }; + + private: + void* m_ReturnBuffer; + std::uint32_t m_ArgumentCount; + void* m_Arguments; + std::uint32_t m_DataCount; + + struct VectorSpace + { + scrVector3 *outVectors[4]; + scrVector3N inVectors[4]; + } m_VectorSpace; + + scrVector3 m_Vectors[4]; + + private: + enum + { + MAX_ARGUMENTS = 32, + ARGUMENT_SIZE = 8 + }; + + std::uint8_t m_Stack[MAX_ARGUMENTS * ARGUMENT_SIZE]; + std::uint64_t m_NativeHash; + std::atomic_bool m_Executed; + + public: + inline NativeContext() + : m_ReturnBuffer(nullptr), m_ArgumentCount(0), m_Arguments(nullptr), m_DataCount(0), m_NativeHash(0), m_VectorSpace{}, m_Vectors{}, m_Stack{}, m_Executed(false) + { + for (std::size_t i = 0; i < sizeof(m_Stack); i++) + { + m_Stack[i] = 0; + } + + m_Arguments = &m_Stack; + m_ReturnBuffer = &m_Stack; + + m_ArgumentCount = 0; + m_DataCount = 0; + } + + inline NativeContext(std::uint64_t hash) + : NativeContext() + { + m_NativeHash = hash; + } + + public: + template + inline void PushArgument(const T& arg) + { + if (m_ArgumentCount >= MAX_ARGUMENTS) + { + throw std::runtime_error("Exceeded maximum number of arguments."); + } + + if constexpr (sizeof(T) < ARGUMENT_SIZE) + { + // Zero out the memory to avoid garbage values + *reinterpret_cast(m_Stack + (m_ArgumentCount * ARGUMENT_SIZE)) = 0; + } + + *reinterpret_cast(m_Stack + (m_ArgumentCount * ARGUMENT_SIZE)) = arg; + m_ArgumentCount++; + } + + template<> + inline void PushArgument(const Vector3& arg) + { + PushArgument(arg.x); + PushArgument(arg.y); + PushArgument(arg.z); + } + + public: + template + inline R GetResult() + { + return *reinterpret_cast(m_ReturnBuffer); + } + + template<> + inline Vector3 GetResult() + { + scrVector3* vec = reinterpret_cast(m_ReturnBuffer); + return Vector3{ vec->x, vec->y, vec->z }; + } + + public: + inline std::uint64_t GetNativeHash() const + { + return m_NativeHash; + } + + inline std::uint32_t GetArgumentCount() const + { + return m_ArgumentCount; + } + + inline void* GetArguments() const + { + return m_Arguments; + } + + inline bool IsExecuted() const + { + return m_Executed.load(); + } + + inline void SetExecuted(bool executed) + { + m_Executed.store(executed, std::memory_order_release); + } + + public: + inline void SetVectorResults() + { + for (size_t i = 0; i < m_DataCount; i++) + { + auto outVector = m_VectorSpace.outVectors[i]; + const auto& inVector = m_VectorSpace.inVectors[i]; + + outVector->x = inVector.x; + outVector->y = inVector.y; + outVector->z = inVector.z; + } + } + + template + inline const T& GetArgument(std::size_t index) const + { + if (index >= m_ArgumentCount) + { + throw std::out_of_range("Argument index out of range."); + } + + auto functionData = reinterpret_cast(m_Arguments); + return *reinterpret_cast(&functionData[index]); + } + }; +} \ No newline at end of file diff --git a/include/fxn/utility.hpp b/include/fxn/utility.hpp new file mode 100644 index 0000000..a5d5ffb --- /dev/null +++ b/include/fxn/utility.hpp @@ -0,0 +1,29 @@ +#pragma once +#include +#include + +namespace fxn +{ + inline constexpr char ToLower(const char c) noexcept + { + return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; + } + + inline constexpr unsigned int HashString(std::string_view str) noexcept + { + std::uint32_t hash = 0; + + for (char ch : str) + { + hash += ToLower(ch); + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; + } +} \ No newline at end of file