#pragma once
#include <type_traits>
namespace cpp
{
namespace marshal
{
/// <summary>
/// Templated class to hold a non GC object on the heap.
/// If T has a destructor a finaliser is added so it is called when this object is collected.
/// </summary>
template<class T>
class Boxed_obj final : public ::hx::Object
{
static void finalise(::hx::Object* obj);
void setFinaliser(std::true_type);
void setFinaliser(std::false_type);
public:
T value;
Boxed_obj();
Boxed_obj(T* ptr);
template<class... TArgs>
Boxed_obj(TArgs... args);
};
template<class T>
class ValueType final
{
static T FromReference(const ValueReference<T>& inRHS);
static T FromBoxed(const Boxed<T>& inRHS);
static T FromDynamic(const Dynamic& inRHS);
public:
T value;
// This allows 'StaticCast' to be used from arrays
using Ptr = Dynamic;
ValueType();
ValueType(const ValueReference<T>& inRHS);
ValueType(const null& inRHS);
ValueType(const Boxed<T>& inRHS);
ValueType(const Variant& inRHS);
ValueType(const Dynamic& inRHS);
template<class... TArgs>
ValueType(TArgs... args);
ValueType<T>& operator=(const ValueReference<T>& inRHS);
ValueType<T>& operator=(const null& inRHS);
};
template<class T>
class PointerType final
{
public:
using TPtr = T*;
private:
static TPtr FromReference(const PointerReference<T>& inRHS);
static TPtr FromBoxed(const Boxed<TPtr>& inRHS);
static TPtr FromDynamic(const Dynamic& inRHS);
public:
// This allows 'StaticCast' to be used from arrays
using Ptr = Dynamic;
TPtr value;
PointerType();
PointerType(TPtr inRHS);
PointerType(const PointerReference<T>& inRHS);
PointerType(const null& inRHS);
PointerType(const Boxed<TPtr>& inRHS);
PointerType(const Variant& inRHS);
PointerType(const Dynamic& inRHS);
PointerType<T>& operator=(const PointerReference<T>& inRHS);
PointerType<T>& operator=(const null& inRHS);
};
template<class T>
class ValueReference final : public ::cpp::Reference<T>
{
using Super = ::cpp::Reference<T>;
template<class O>
static O* FromDynamic(const Dynamic& inRHS);
template<class O>
static O* FromBoxed(const Boxed<O>& inRHS);
Boxed<T> ToBoxed() const;
public:
// This allows 'StaticCast' to be used from arrays
using Ptr = Dynamic;
ValueReference();
ValueReference(const null& inRHS);
ValueReference(const ValueType<T>& inRHS);
ValueReference(const Boxed<T>& inRHS);
ValueReference(const T& inRHS);
ValueReference(T& inRHS);
ValueReference(const T* inRHS);
template<class O>
ValueReference(const ValueReference<O>& inRHS);
template<class O>
ValueReference(const ValueType<O>& inRHS);
template<class O>
ValueReference(const Boxed<O>& inRHS);
ValueReference(const Variant& inRHS);
ValueReference(const Dynamic& inRHS);
operator Dynamic() const;
operator Variant() const;
operator Boxed<T>() const;
T* operator->() const;
T operator*() const;
bool operator==(const ValueReference<T>& inRHS) const;
bool operator!=(const ValueReference<T>& inRHS) const;
template<class K>
K get(int64_t index);
template<class K>
void set(int64_t index, K value);
};
template<class T>
class PointerReference final : public ::cpp::Reference<T*>
{
public:
using TPtr = T*;
private:
using Super = ::cpp::Reference<TPtr>;
template<class O>
static O* FromDynamic(const Dynamic& inRHS);
template<class O>
static O* FromBoxed(const Boxed<O>& inRHS);
Boxed<TPtr> ToBoxed() const;
public:
PointerReference(const null& inRHS);
PointerReference(const PointerType<T>& inRHS);
PointerReference(const Boxed<TPtr>& inRHS);
template<class O>
PointerReference(const PointerReference<O>& inRHS);
template<class O>
PointerReference(const PointerType<O>& inRHS);
template<class O>
PointerReference(const Boxed<O>& inRHS);
PointerReference(const TPtr& inRHS);
PointerReference(TPtr& inRHS);
PointerReference(const TPtr* inRHS);
PointerReference(const Variant& inRHS);
PointerReference(const Dynamic& inRHS);
operator Dynamic() const;
operator Variant() const;
operator Boxed<TPtr>() const;
operator Pointer<T>() const;
operator TPtr&();
operator TPtr*();
operator void*();
operator void**();
TPtr operator->() const;
template<class K>
K get(int64_t index);
template<class K>
void set(int64_t index, K value);
};
template<class T>
struct View final
{
::cpp::Pointer<T> ptr;
int64_t length;
View(::cpp::Pointer<T> _ptr, int64_t _length);
void clear() const;
void fill(T value) const;
bool isEmpty() const;
View<T> slice(int64_t index) const;
View<T> slice(int64_t index, int64_t length) const;
void copyTo(const View<T>& destination) const;
bool tryCopyTo(const View<T>& destination) const;
template<class K> View<K> reinterpret() const;
int compare(const View<T>& inRHS) const;
bool operator==(const View<T>& inRHS) const;
bool operator!=(const View<T>& inRHS) const;
T& operator[] (int64_t index) const;
};
class RootHandle
{
::hx::Object** object;
RootHandle(hx::Object** obj);
public:
static RootHandle create(Dynamic obj);
static RootHandle fromVoidPointer(::cpp::Pointer<void> ptr);
::cpp::Pointer<void> toVoidPointer();
Dynamic getObject();
void close();
};
struct Marshal final
{
#ifdef HXCPP_BIG_ENDIAN
static const bool isBigEndian = true;
#else
static const bool isBigEndian = false;
#endif
static View<char> asCharView(const ::String& string);
static View<char16_t> asWideCharView(const ::String& string);
template<class T> static T read(const View<uint8_t>& view);
template<class T> static ::cpp::Pointer<T> readPointer(const View<uint8_t>& view);
static int8_t readInt8(const View<uint8_t>& view);
static int16_t readInt16(const View<uint8_t>& view);
static int32_t readInt32(const View<uint8_t>& view);
static int64_t readInt64(const View<uint8_t>& view);
static uint8_t readUInt8(const View<uint8_t>& view);
static uint16_t readUInt16(const View<uint8_t>& view);
static uint32_t readUInt32(const View<uint8_t>& view);
static uint64_t readUInt64(const View<uint8_t>& view);
static float readFloat32(const View<uint8_t>& view);
static double readFloat64(const View<uint8_t>& view);
template<class T> static ::cpp::Pointer<T> readLittleEndianPointer(const View<uint8_t>& view);
static int16_t readLittleEndianInt16(const View<uint8_t>& view);
static int32_t readLittleEndianInt32(const View<uint8_t>& view);
static int64_t readLittleEndianInt64(const View<uint8_t>& view);
static uint16_t readLittleEndianUInt16(const View<uint8_t>& view);
static uint32_t readLittleEndianUInt32(const View<uint8_t>& view);
static uint64_t readLittleEndianUInt64(const View<uint8_t>& view);
static float readLittleEndianFloat32(const View<uint8_t>& view);
static double readLittleEndianFloat64(const View<uint8_t>& view);
template<class T> static ::cpp::Pointer<T> readBigEndianPointer(const View<uint8_t>& view);
static int16_t readBigEndianInt16(const View<uint8_t>& view);
static int32_t readBigEndianInt32(const View<uint8_t>& view);
static int64_t readBigEndianInt64(const View<uint8_t>& view);
static uint16_t readBigEndianUInt16(const View<uint8_t>& view);
static uint32_t readBigEndianUInt32(const View<uint8_t>& view);
static uint64_t readBigEndianUInt64(const View<uint8_t>& view);
static float readBigEndianFloat32(const View<uint8_t>& view);
static double readBigEndianFloat64(const View<uint8_t>& view);
template<class T> static void write(const View<uint8_t>& view, const T& value);
template<class T> static void writePointer(const View<uint8_t>& view, const Pointer<T>& value);
static void writeInt8(const View<uint8_t>& view, const int8_t& value);
static void writeInt16(const View<uint8_t>& view, const int16_t& value);
static void writeInt32(const View<uint8_t>& view, const int32_t& value);
static void writeInt64(const View<uint8_t>& view, const int64_t& value);
static void writeUInt8(const View<uint8_t>& view, const uint8_t& value);
static void writeUInt16(const View<uint8_t>& view, const uint16_t& value);
static void writeUInt32(const View<uint8_t>& view, const uint32_t& value);
static void writeUInt64(const View<uint8_t>& view, const uint64_t& value);
static void writeFloat32(const View<uint8_t>& view, const float& value);
static void writeFloat64(const View<uint8_t>& view, const double& value);
template<class T> static void writeLittleEndianPointer(const View<uint8_t>& view, const Pointer<T>& value);
static void writeLittleEndianInt16(const View<uint8_t>& view, const int16_t& value);
static void writeLittleEndianInt32(const View<uint8_t>& view, const int32_t& value);
static void writeLittleEndianInt64(const View<uint8_t>& view, const int64_t& value);
static void writeLittleEndianUInt16(const View<uint8_t>& view, const uint16_t& value);
static void writeLittleEndianUInt32(const View<uint8_t>& view, const uint32_t& value);
static void writeLittleEndianUInt64(const View<uint8_t>& view, const uint64_t& value);
static void writeLittleEndianFloat32(const View<uint8_t>& view, const float& value);
static void writeLittleEndianFloat64(const View<uint8_t>& view, const double& value);
template<class T> static void writeBigEndianPointer(const View<uint8_t>& view, const Pointer<T>& value);
static void writeBigEndianInt16(const View<uint8_t>& view, const int16_t& value);
static void writeBigEndianInt32(const View<uint8_t>& view, const int32_t& value);
static void writeBigEndianInt64(const View<uint8_t>& view, const int64_t& value);
static void writeBigEndianUInt16(const View<uint8_t>& view, const uint16_t& value);
static void writeBigEndianUInt32(const View<uint8_t>& view, const uint32_t& value);
static void writeBigEndianUInt64(const View<uint8_t>& view, const uint64_t& value);
static void writeBigEndianFloat32(const View<uint8_t>& view, const float& value);
static void writeBigEndianFloat64(const View<uint8_t>& view, const double& value);
};
}
}
// Implement some pointer helpers here
template<typename T>
inline cpp::Pointer<T> cpp::Pointer_obj::addressOf(const ::cpp::marshal::ValueReference<T>& ref)
{
return Pointer<T>(ref.ptr);
}
template<typename T>
inline cpp::Pointer<T*> cpp::Pointer_obj::addressOf(const ::cpp::marshal::PointerReference<T>& ref)
{
return Pointer<T*>(ref.ptr);
}
// I'm not sure why I need this pointer ctor overload, I'm sure it was working without it at some point
template<typename T>
inline cpp::Pointer<T>::Pointer(const ::cpp::marshal::PointerReference<T> ref)
{
ptr = *ref.ptr;
}