From 5dfa55abd4c5224cde701a752ba2ff63d04333bb Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 15 Dec 2024 12:21:53 +0000 Subject: [PATCH 01/89] Add marshal header for value type interop --- include/cpp/Marshal.h | 151 ++++++++++++++++++++++++++++++++++++++ include/cpp/Pointer.h | 5 +- include/hxcpp.h | 1 + toolchain/haxe-target.xml | 1 + 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 include/cpp/Marshal.h diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h new file mode 100644 index 000000000..0fc77773f --- /dev/null +++ b/include/cpp/Marshal.h @@ -0,0 +1,151 @@ +#pragma once + +namespace cpp +{ + namespace marshal + { + // Boxed class is used to promote a value type to the GC heap. + + template + struct Boxed_obj final : public ::hx::Object + { + T value; + + Boxed_obj(T* ptr) : value(*ptr) {} + + template + Boxed_obj(TArgs... args) : value(std::forward(args)...) {} + }; + + template + using Boxed = ::hx::ObjectPtr>; + + // + + template + struct ValueTypeStructHandler + { + static inline const char* getName() { return "cpp.ValueType"; } + static inline ::String toString(const void* inValue) { return HX_CSTRING("cpp.ValueType"); } + static inline void handler(DynamicHandlerOp op, void* inValue, int inSize, void* outResult) + { + switch (op) + { + case dhoToString: + { + *static_cast<::String*>(outResult) = toString(inValue); + break; + } + + case dhoGetClassName: + { + *static_cast(outResult) = getName(); + break; + } + + case dhoToDynamic: + { + auto ptr = static_cast(inValue); + auto boxed = new Boxed_obj(ptr); + + outResult = boxed; + break; + } + + case dhoFromDynamic: + { + auto params = static_cast(outResult); + auto ptr = static_cast(inValue); + auto wrapped = Boxed(reinterpret_cast*>(params->inData)); + + params->outProcessed = true; + + *ptr = wrapped->value; + break; + } + + case dhoIs: + break; + } + } + }; + + template + class Reference; + + template + class ValueType; + + template + class Reference final : public ::cpp::Reference + { + using Super = ::cpp::Reference; + + static T* FromDynamic(const Dynamic& inRHS) + { + auto boxed = inRHS.Cast>(); // Boxed(reinterpret_cast*>()); + auto ptr = &boxed->value; + + return ptr; + } + + public: + Reference(const T* inRHS) : Super(inRHS) {} + Reference(const ValueType& inRHS) : Super(inRHS) { } + Reference(const Boxed& inRHS) : Super(&inRHS->value) {} + Reference(const Variant& inRHS) : Super(FromDynamic(inRHS.asDynamic())) {} + Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} + + operator Dynamic () const + { + return Boxed(new Boxed_obj(Super::ptr)); + } + + operator Variant() const + { + return Boxed(new Boxed_obj(Super::ptr)); + } + }; + + template + class ValueType final : public Struct + { + static T* FromDynamic(const Dynamic& inRHS) + { + auto boxed = inRHS.Cast>(); + auto ptr = &boxed.mPtr->value; + + return ptr; + } + + public: + using ::cpp::Struct::value; + + ValueType() : Struct() {} + ValueType(const Reference& inRHS) : Struct(inRHS) {} + ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} + ValueType(const Variant& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS.asDynamic()))) {} + ValueType(const Dynamic& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS))) {} + + template + ValueType(TArgs... args) : Struct(std::forward(args)...) {} + + ValueType& operator=(const Reference& inRHS) + { + value = *inRHS.ptr; + + return *this; + } + + operator Dynamic () const + { + return Boxed(new Boxed_obj(&value)); + } + + operator Variant() const + { + return Boxed(new Boxed_obj(&value)); + } + }; + } +} \ No newline at end of file diff --git a/include/cpp/Pointer.h b/include/cpp/Pointer.h index 25c28b451..b78e58c3d 100644 --- a/include/cpp/Pointer.h +++ b/include/cpp/Pointer.h @@ -131,12 +131,15 @@ class Struct // This allows 'StaticCast' to be used from arrays typedef Dynamic Ptr; - inline Struct( ) { } + inline Struct( ) : value() { } inline Struct( const T &inRHS ) : value(inRHS) { } inline Struct( const null &) { value = T(); } inline Struct( const Reference &); inline Struct( const Dynamic &inRHS) { fromDynamic(inRHS.mPtr); } + template + Struct(TArgs... args) : value(std::forward(args)...) {} + inline Struct &operator=( const T &inRHS ) { value = inRHS; return *this; } inline Struct &operator=( const null & ) { value = T(); return *this; } inline Struct &operator=( const Dynamic &inRHS ) { return *this = Struct(inRHS); } diff --git a/include/hxcpp.h b/include/hxcpp.h index faa1b4db2..3db2f680a 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -349,6 +349,7 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include +#include #include #include #include diff --git a/toolchain/haxe-target.xml b/toolchain/haxe-target.xml index a795596ab..833bf6b8e 100644 --- a/toolchain/haxe-target.xml +++ b/toolchain/haxe-target.xml @@ -57,6 +57,7 @@ + From ec75e42120f8448b279193cc0c709d8066120e01 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 15 Dec 2024 13:28:22 +0000 Subject: [PATCH 02/89] finalise boxed objects if the type has a destructor --- include/cpp/Marshal.h | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 0fc77773f..72cbf1969 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace cpp { namespace marshal @@ -7,14 +9,34 @@ namespace cpp // Boxed class is used to promote a value type to the GC heap. template - struct Boxed_obj final : public ::hx::Object + class Boxed_obj final : public ::hx::Object { + static void finalise(::hx::Object* obj) + { + auto ptr = reinterpret_cast*>(obj); + + ptr->value.~T(); + } + + public: T value; - Boxed_obj(T* ptr) : value(*ptr) {} + Boxed_obj(T* ptr) : value(*ptr) + { + if constexpr (std::is_destructible::value) + { + ::hx::GCSetFinalizer(this, finalise); + } + } - template - Boxed_obj(TArgs... args) : value(std::forward(args)...) {} + template + Boxed_obj(TArgs... args) : value(std::forward(args)...) + { + if constexpr (std::is_destructible::value) + { + ::hx::GCSetFinalizer(this, finalise); + } + } }; template From b22a024eaa6b56264efda29f8fdb6bd8d0f86d28 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 16 Dec 2024 13:34:30 +0000 Subject: [PATCH 03/89] works with static cast --- include/cpp/Marshal.h | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 72cbf1969..0ba51112e 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -21,6 +21,14 @@ namespace cpp public: T value; + Boxed_obj() : value() + { + if constexpr (std::is_destructible::value) + { + ::hx::GCSetFinalizer(this, finalise); + } + } + Boxed_obj(T* ptr) : value(*ptr) { if constexpr (std::is_destructible::value) @@ -105,16 +113,30 @@ namespace cpp static T* FromDynamic(const Dynamic& inRHS) { - auto boxed = inRHS.Cast>(); // Boxed(reinterpret_cast*>()); - auto ptr = &boxed->value; + return FromBoxed(inRHS.Cast>()); + //auto boxed = inRHS.Cast>(); // Boxed(reinterpret_cast*>()); + //auto ptr = &boxed->value; - return ptr; + //return ptr; + } + + static T* FromBoxed(const Boxed& inRHS) + { + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return const_cast(&inRHS->value); } public: + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + Reference(const T* inRHS) : Super(inRHS) {} Reference(const ValueType& inRHS) : Super(inRHS) { } - Reference(const Boxed& inRHS) : Super(&inRHS->value) {} + Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} Reference(const Variant& inRHS) : Super(FromDynamic(inRHS.asDynamic())) {} Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} @@ -127,6 +149,16 @@ namespace cpp { return Boxed(new Boxed_obj(Super::ptr)); } + + T* operator->() const + { + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return Super::ptr; + } }; template @@ -143,6 +175,9 @@ namespace cpp public: using ::cpp::Struct::value; + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + ValueType() : Struct() {} ValueType(const Reference& inRHS) : Struct(inRHS) {} ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} From 4bc2bcc395bc92451c59b629e99aa73e89eb9888 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 16 Dec 2024 13:35:23 +0000 Subject: [PATCH 04/89] add value type tests --- test/native/tests/TestValueType.hx | 250 +++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 test/native/tests/TestValueType.hx diff --git a/test/native/tests/TestValueType.hx b/test/native/tests/TestValueType.hx new file mode 100644 index 000000000..e456c1ca0 --- /dev/null +++ b/test/native/tests/TestValueType.hx @@ -0,0 +1,250 @@ +package tests; + +import utest.Assert; +import utest.Test; +import cpp.Reference; + +@:include('vector') +@:cpp.ValueType({ type : 'vector', namespace : [ 'std' ], flags : [ ImplicitConstruction ] }) +private extern class StdVector implements ArrayAccess> { + @:overload(function ():Void {}) + function new(s:Int):Void; + + function size():Int; + + function resize(s:Int):Void; +} + +private extern class Helpers { + @:native('vec_by_val') + static function vec_by_val(v:StdVector):Void; + + @:native('vec_by_ref') + static function vec_by_ref(v:StdVector):Void; + + @:native('vec_by_ptr') + static function vec_by_ptr(v:StdVector):Void; +} + +@:cppNamespaceCode(' + +void vec_by_val(std::vector v) +{ + v.resize(v.size() * 2); +} + +void vec_by_ref(std::vector& v) +{ + v.resize(v.size() * 2); +} + +void vec_by_ptr(std::vector* v) +{ + v->resize(v->size() * 2); +} + +') +class TestValueType extends Test { + + /** + * Declaring a new variable of a value type will copy the right hand side value. + */ + function test_var_copying() { + final v1 = new StdVector(); + final v2 = v1; + + v1.resize(10); + + Assert.equals(10, v1.size()); + Assert.equals( 0, v2.size()); + } + + function test_var_asignment() { + var v = new StdVector(50); + + v = new StdVector(); + + Assert.equals(0, v.size()); + } + + /** + * Passing a value type into a function will pass it by value. + */ + function test_function_copying() { + final v = new StdVector(); + + by_value(v); + + Assert.equals( 0, v.size()); + } + + function by_value(v:StdVector) { + v.resize(10); + } + + /** + * Variables captured by closures will be wrapped in a type which moves them to the GC heap. + */ + function test_heap_promotion() { + final v = new StdVector(); + final f = () -> { + v.resize(10); + } + + f(); + + Assert.equals(10, v.size()); + } + + function test_nullable() { + var v : Null> = null; + + var thrown = false; + + try { + var _ = v.size(); + } + catch (exn) { + thrown = true; + } + + Assert.isTrue(thrown); + + v = new StdVector(5); + + Assert.equals(5, v.size()); + } + + /** + * Value type variables passed into a function of type dynamic will also be passed a copy. + */ + function test_dynamic() { + final v = new StdVector(5); + + by_value_dynamic(v); + + Assert.equals(5, v.size()); + } + + /** + * Value type variables which have been promoted to the heap will be copied to dynamic functions argumens. + */ + function test_promoted_dynamic() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + by_value_dynamic(v); + + Assert.equals(5, v.size()); + } + + /** + * Value type variables passed put into and accessed via an anonymous object will be promoted to the heap. + */ + function test_anon() { + final v = new StdVector(5); + + by_value_anon({ v : v }); + + Assert.equals(5, v.size()); + } + + + function test_extern_by_val() { + final v = new StdVector(5); + + Helpers.vec_by_val(v); + + Assert.equals(5, v.size()); + } + + function test_extern_by_ref() { + final v = new StdVector(5); + + Helpers.vec_by_ref(v); + + Assert.equals(10, v.size()); + } + + function test_extern_by_ptr() { + final v = new StdVector(5); + + Helpers.vec_by_ptr(v); + + Assert.equals(10, v.size()); + } + + function test_promoted_extern_by_val() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + Helpers.vec_by_val(v); + + Assert.equals(5, v.size()); + } + + function test_promoted_extern_by_ref() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + Helpers.vec_by_ref(v); + + Assert.equals(10, v.size()); + } + + function test_promoted_extern_by_ptr() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + Helpers.vec_by_ptr(v); + + Assert.equals(10, v.size()); + } + + function test_asigning_promoted_variable() { + var v = new StdVector(5); + final f = () -> { + v.resize(10); + } + + f(); + + v = new StdVector(2); + + Assert.equals(2, v.size()); + } + + // + + function by_value_anon(a:{ v : StdVector }) { + Assert.equals(5, a.v.size()); + + a.v.resize(10); + + Assert.equals(10, a.v.size()); + } + + function by_value_dynamic(v:Dynamic) { + Assert.equals(5, (v:StdVector).size()); + + (v:StdVector).resize(10); + + Assert.equals(10, (v:StdVector).size()); + } +} \ No newline at end of file From 44d5a28a7cef4279ef0ec841794265188d8b468d Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 27 Dec 2024 13:20:12 +0000 Subject: [PATCH 05/89] move more conversion functions to reference class --- include/cpp/Marshal.h | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 0ba51112e..46720d341 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -114,10 +114,6 @@ namespace cpp static T* FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.Cast>()); - //auto boxed = inRHS.Cast>(); // Boxed(reinterpret_cast*>()); - //auto ptr = &boxed->value; - - //return ptr; } static T* FromBoxed(const Boxed& inRHS) @@ -140,7 +136,7 @@ namespace cpp Reference(const Variant& inRHS) : Super(FromDynamic(inRHS.asDynamic())) {} Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} - operator Dynamic () const + operator Dynamic() const { return Boxed(new Boxed_obj(Super::ptr)); } @@ -150,6 +146,11 @@ namespace cpp return Boxed(new Boxed_obj(Super::ptr)); } + operator Boxed() const + { + return Boxed(new Boxed_obj(Super::ptr)); + } + T* operator->() const { if (nullptr == Super::ptr) @@ -178,8 +179,11 @@ namespace cpp // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; + ValueType(const null& inRHS) = delete; + ValueType() : Struct() {} ValueType(const Reference& inRHS) : Struct(inRHS) {} + ValueType(const ValueType& inRHS) : Struct(inRHS->value->value) {} ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} ValueType(const Variant& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS.asDynamic()))) {} ValueType(const Dynamic& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS))) {} @@ -194,15 +198,7 @@ namespace cpp return *this; } - operator Dynamic () const - { - return Boxed(new Boxed_obj(&value)); - } - - operator Variant() const - { - return Boxed(new Boxed_obj(&value)); - } + ValueType& operator=(const null& inRHS) = delete; }; } } \ No newline at end of file From 04579588d99612f08d91d1c270eff1232cea2cd5 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 27 Dec 2024 16:48:52 +0000 Subject: [PATCH 06/89] forward declare everything to avoid order issues --- include/cpp/Marshal.h | 350 ++++++++++++++++++++++++++---------------- 1 file changed, 216 insertions(+), 134 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 46720d341..986fe1b8b 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -6,58 +6,241 @@ namespace cpp { namespace marshal { - // Boxed class is used to promote a value type to the GC heap. + template + class Reference; - template - class Boxed_obj final : public ::hx::Object - { - static void finalise(::hx::Object* obj) - { - auto ptr = reinterpret_cast*>(obj); + template + class ValueType; - ptr->value.~T(); - } + template + class Boxed_obj; + + template + using Boxed = ::hx::ObjectPtr>; + + template + class Boxed_obj final : public ::hx::Object + { + static void finalise(::hx::Object* obj); public: - T value; + T value; + + Boxed_obj(); + + Boxed_obj(T* ptr); + + template + Boxed_obj(TArgs... args); + + operator ValueType() const; + }; + + template + class Reference final : public ::cpp::Reference + { + using Super = ::cpp::Reference; + + static T* FromDynamic(const Dynamic& inRHS); + + static T* FromBoxed(const Boxed& inRHS); + + public: + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + + Reference(const T* inRHS); + Reference(const ValueType& inRHS); + Reference(const Boxed& inRHS); + Reference(const Variant& inRHS); + Reference(const Dynamic& inRHS); + + operator Dynamic() const; + operator Variant() const; + operator Boxed() const; + + T* operator->() const; + }; + + template + class ValueType final : public Struct + { + static T* FromDynamic(const Dynamic& inRHS); + + public: + using ::cpp::Struct::value; + + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + + ValueType(const null& inRHS) = delete; + + ValueType(); + ValueType(const Reference& inRHS); + ValueType(const Boxed& inRHS); + ValueType(const Variant& inRHS); + ValueType(const Dynamic& inRHS); + + template + ValueType(TArgs... args); - Boxed_obj() : value() + ValueType& operator=(const Reference& inRHS); + ValueType& operator=(const null& inRHS) = delete; + }; + + // Boxed implementation + + template + void Boxed_obj::finalise(::hx::Object* obj) + { + auto ptr = reinterpret_cast*>(obj); + + ptr->value.~T(); + } + + template + Boxed_obj::Boxed_obj() : value() + { + if constexpr (std::is_destructible::value) { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } + ::hx::GCSetFinalizer(this, finalise); } + } - Boxed_obj(T* ptr) : value(*ptr) + template + Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) + { + if constexpr (std::is_destructible::value) { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } + ::hx::GCSetFinalizer(this, finalise); } + } - template - Boxed_obj(TArgs... args) : value(std::forward(args)...) + template + template + Boxed_obj::Boxed_obj(TArgs... args) : value(std::forward(args)...) + { + if constexpr (std::is_destructible::value) { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } + ::hx::GCSetFinalizer(this, finalise); } - }; + } - template - using Boxed = ::hx::ObjectPtr>; + template + Boxed_obj::operator ValueType() const + { + return ValueType(Boxed(this)); + } + + // Reference implementation + + template + T* Reference::FromDynamic(const Dynamic& inRHS) + { + return FromBoxed(inRHS.Cast>()); + } + + template + T* Reference::FromBoxed(const Boxed& inRHS) + { + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return const_cast(&inRHS->value); + } + + template + Reference::Reference(const T* inRHS) : Super(inRHS) {} + + template + Reference::Reference(const ValueType& inRHS) : Super(inRHS) {} + + template + Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} + + template + Reference::Reference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} + + template + Reference::Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} + + template + Reference::operator Dynamic() const + { + return Boxed(new Boxed_obj(Super::ptr)); + } + + template + Reference::operator Variant() const + { + return Boxed(new Boxed_obj(Super::ptr)); + } - // + template + Reference::operator Boxed() const + { + return Boxed(new Boxed_obj(Super::ptr)); + } + + template + T* Reference::operator ->() const + { + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return Super::ptr; + } + + // ValueType implementation + + template + T* ValueType::FromDynamic(const Dynamic& inRHS) + { + auto boxed = inRHS.Cast>(); + auto ptr = &boxed.mPtr->value; + + return ptr; + } + + template + ValueType::ValueType() : Struct() {} + + template + ValueType::ValueType(const Reference& inRHS) : Struct(inRHS) {} + + template + ValueType::ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} + + template + ValueType::ValueType(const Variant& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS.asDynamic()))) {} + + template + ValueType::ValueType(const Dynamic& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS))) {} + + template + template + ValueType::ValueType(TArgs ...args) : Struct(std::forward(args)...) {} + + template + ValueType& ValueType::operator=(const Reference& inRHS) + { + value = *inRHS.ptr; + + return *this; + } + + // Value type struct handler template struct ValueTypeStructHandler { - static inline const char* getName() { return "cpp.ValueType"; } - static inline ::String toString(const void* inValue) { return HX_CSTRING("cpp.ValueType"); } - static inline void handler(DynamicHandlerOp op, void* inValue, int inSize, void* outResult) + static const char* getName() { return "cpp.ValueType"; } + static ::String toString(const void* inValue) { return HX_CSTRING("cpp.ValueType"); } + static void handler(DynamicHandlerOp op, void* inValue, int inSize, void* outResult) { switch (op) { @@ -99,106 +282,5 @@ namespace cpp } } }; - - template - class Reference; - - template - class ValueType; - - template - class Reference final : public ::cpp::Reference - { - using Super = ::cpp::Reference; - - static T* FromDynamic(const Dynamic& inRHS) - { - return FromBoxed(inRHS.Cast>()); - } - - static T* FromBoxed(const Boxed& inRHS) - { - if (nullptr == inRHS.mPtr) - { - return nullptr; - } - - return const_cast(&inRHS->value); - } - - public: - // This allows 'StaticCast' to be used from arrays - using Ptr = Dynamic; - - Reference(const T* inRHS) : Super(inRHS) {} - Reference(const ValueType& inRHS) : Super(inRHS) { } - Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} - Reference(const Variant& inRHS) : Super(FromDynamic(inRHS.asDynamic())) {} - Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} - - operator Dynamic() const - { - return Boxed(new Boxed_obj(Super::ptr)); - } - - operator Variant() const - { - return Boxed(new Boxed_obj(Super::ptr)); - } - - operator Boxed() const - { - return Boxed(new Boxed_obj(Super::ptr)); - } - - T* operator->() const - { - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return Super::ptr; - } - }; - - template - class ValueType final : public Struct - { - static T* FromDynamic(const Dynamic& inRHS) - { - auto boxed = inRHS.Cast>(); - auto ptr = &boxed.mPtr->value; - - return ptr; - } - - public: - using ::cpp::Struct::value; - - // This allows 'StaticCast' to be used from arrays - using Ptr = Dynamic; - - ValueType(const null& inRHS) = delete; - - ValueType() : Struct() {} - ValueType(const Reference& inRHS) : Struct(inRHS) {} - ValueType(const ValueType& inRHS) : Struct(inRHS->value->value) {} - ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} - ValueType(const Variant& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS.asDynamic()))) {} - ValueType(const Dynamic& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS))) {} - - template - ValueType(TArgs... args) : Struct(std::forward(args)...) {} - - ValueType& operator=(const Reference& inRHS) - { - value = *inRHS.ptr; - - return *this; - } - - ValueType& operator=(const null& inRHS) = delete; - }; } } \ No newline at end of file From d718eca10412c3f613054b0761d3d494d06c7fe8 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 27 Dec 2024 18:58:35 +0000 Subject: [PATCH 07/89] ValueType construction from boxed pointer --- include/cpp/Marshal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 986fe1b8b..0a9e9f5a6 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -78,6 +78,7 @@ namespace cpp ValueType(); ValueType(const Reference& inRHS); ValueType(const Boxed& inRHS); + ValueType(Boxed_obj* inRHS); ValueType(const Variant& inRHS); ValueType(const Dynamic& inRHS); @@ -215,6 +216,9 @@ namespace cpp template ValueType::ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} + template + ValueType::ValueType(Boxed_obj* inRHS) : Struct(inRHS->value) {} + template ValueType::ValueType(const Variant& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS.asDynamic()))) {} From ad7f101bce82c8187c43d2f73fde062d5c4a4d29 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 30 Dec 2024 20:14:17 +0000 Subject: [PATCH 08/89] ValueType no longer inherits from struct --- include/cpp/Marshal.h | 71 +++++++------------------------------------ 1 file changed, 11 insertions(+), 60 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 0a9e9f5a6..90b70cd2d 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -50,6 +50,7 @@ namespace cpp using Ptr = Dynamic; Reference(const T* inRHS); + //Reference(const T& inRHS); Reference(const ValueType& inRHS); Reference(const Boxed& inRHS); Reference(const Variant& inRHS); @@ -63,12 +64,12 @@ namespace cpp }; template - class ValueType final : public Struct + class ValueType final { static T* FromDynamic(const Dynamic& inRHS); public: - using ::cpp::Struct::value; + T value; // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; @@ -156,7 +157,7 @@ namespace cpp Reference::Reference(const T* inRHS) : Super(inRHS) {} template - Reference::Reference(const ValueType& inRHS) : Super(inRHS) {} + Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} template Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} @@ -208,26 +209,26 @@ namespace cpp } template - ValueType::ValueType() : Struct() {} + ValueType::ValueType() : value() {} template - ValueType::ValueType(const Reference& inRHS) : Struct(inRHS) {} + ValueType::ValueType(const Reference& inRHS) : value(*inRHS.ptr) {} template - ValueType::ValueType(const Boxed& inRHS) : Struct(inRHS->value) {} + ValueType::ValueType(const Boxed& inRHS) : value(inRHS->value) {} template - ValueType::ValueType(Boxed_obj* inRHS) : Struct(inRHS->value) {} + ValueType::ValueType(Boxed_obj* inRHS) : value(inRHS->value) {} template - ValueType::ValueType(const Variant& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS.asDynamic()))) {} + ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} template - ValueType::ValueType(const Dynamic& inRHS) : Struct(::cpp::Reference(FromDynamic(inRHS))) {} + ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS))) {} template template - ValueType::ValueType(TArgs ...args) : Struct(std::forward(args)...) {} + ValueType::ValueType(TArgs ...args) : value(std::forward(args)...) {} template ValueType& ValueType::operator=(const Reference& inRHS) @@ -236,55 +237,5 @@ namespace cpp return *this; } - - // Value type struct handler - - template - struct ValueTypeStructHandler - { - static const char* getName() { return "cpp.ValueType"; } - static ::String toString(const void* inValue) { return HX_CSTRING("cpp.ValueType"); } - static void handler(DynamicHandlerOp op, void* inValue, int inSize, void* outResult) - { - switch (op) - { - case dhoToString: - { - *static_cast<::String*>(outResult) = toString(inValue); - break; - } - - case dhoGetClassName: - { - *static_cast(outResult) = getName(); - break; - } - - case dhoToDynamic: - { - auto ptr = static_cast(inValue); - auto boxed = new Boxed_obj(ptr); - - outResult = boxed; - break; - } - - case dhoFromDynamic: - { - auto params = static_cast(outResult); - auto ptr = static_cast(inValue); - auto wrapped = Boxed(reinterpret_cast*>(params->inData)); - - params->outProcessed = true; - - *ptr = wrapped->value; - break; - } - - case dhoIs: - break; - } - } - }; } } \ No newline at end of file From 937868a293985062a0363191d79ab696f01a752e Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 1 Jan 2025 16:16:54 +0000 Subject: [PATCH 09/89] marshal reference interop with existing pointer types --- include/cpp/Marshal.h | 54 ++++++++++++++++++++++++++++++------------- include/cpp/Pointer.h | 2 ++ include/hxcpp.h | 4 ++++ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 90b70cd2d..30645dcc9 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef CPP_MARSHAL_H +#define CPP_MARSHAL_H #include @@ -6,18 +7,6 @@ namespace cpp { namespace marshal { - template - class Reference; - - template - class ValueType; - - template - class Boxed_obj; - - template - using Boxed = ::hx::ObjectPtr>; - template class Boxed_obj final : public ::hx::Object { @@ -49,8 +38,10 @@ namespace cpp // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; + Reference(const T& inRHS); + Reference(T& inRHS); + Reference(const T* inRHS); - //Reference(const T& inRHS); Reference(const ValueType& inRHS); Reference(const Boxed& inRHS); Reference(const Variant& inRHS); @@ -61,6 +52,9 @@ namespace cpp operator Boxed() const; T* operator->() const; + + bool operator==(const Reference& inRHS) const; + bool operator!=(const Reference& inRHS) const; }; template @@ -153,6 +147,12 @@ namespace cpp return const_cast(&inRHS->value); } + template + Reference::Reference(const T& inRHS) : Super(inRHS) {} + + template + Reference::Reference(T& inRHS) : Super(inRHS) {} + template Reference::Reference(const T* inRHS) : Super(inRHS) {} @@ -197,13 +197,25 @@ namespace cpp return Super::ptr; } + template + inline bool Reference::operator==(const Reference& inRHS) const + { + return (*Super::ptr) == (*inRHS->ptr); + } + + template + inline bool Reference::operator!=(const Reference& inRHS) const + { + return (*Super::ptr) != (*inRHS->ptr); + } + // ValueType implementation template T* ValueType::FromDynamic(const Dynamic& inRHS) { auto boxed = inRHS.Cast>(); - auto ptr = &boxed.mPtr->value; + auto ptr = &boxed->value; return ptr; } @@ -238,4 +250,14 @@ namespace cpp return *this; } } -} \ No newline at end of file + + // Implement some pointer helpers here + + template + inline Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::Reference& ref) + { + return Pointer(ref.ptr); + } +} + +#endif \ No newline at end of file diff --git a/include/cpp/Pointer.h b/include/cpp/Pointer.h index b78e58c3d..898c8bf27 100644 --- a/include/cpp/Pointer.h +++ b/include/cpp/Pointer.h @@ -512,6 +512,8 @@ class Pointer_obj } + template + inline static Pointer addressOf(const ::cpp::marshal::Reference&); template inline static Pointer addressOf(T &value) { return Pointer(&value); } diff --git a/include/hxcpp.h b/include/hxcpp.h index 3db2f680a..2e8a7da90 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -260,6 +260,10 @@ namespace hx { template class ObjectPtr; } namespace cpp { template class Struct; } namespace cpp { template class Pointer; } namespace cpp { template class Function; } +namespace cpp { namespace marshal { template class ValueType; } } +namespace cpp { namespace marshal { template class Boxed_obj; } } +namespace cpp { namespace marshal { template using Boxed =::hx::ObjectPtr>; } } +namespace cpp { namespace marshal { template class Reference; } } template class Array_obj; template class Array; namespace hx { From 5b00db840f162e3047f60f1d66f849b4a6ad10a9 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 1 Jan 2025 20:55:27 +0000 Subject: [PATCH 10/89] Fix trying to dereference a null pointer when creating a boxed object from a reference --- include/cpp/Marshal.h | 313 +++++++++++++++++++++++------------------- include/hxcpp.h | 2 +- 2 files changed, 169 insertions(+), 146 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 30645dcc9..dc887084a 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -5,8 +5,8 @@ namespace cpp { - namespace marshal - { + namespace marshal + { template class Boxed_obj final : public ::hx::Object { @@ -21,8 +21,6 @@ namespace cpp template Boxed_obj(TArgs... args); - - operator ValueType() const; }; template @@ -34,18 +32,19 @@ namespace cpp static T* FromBoxed(const Boxed& inRHS); + Boxed ToBoxed() const; + public: // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; - Reference(const T& inRHS); - Reference(T& inRHS); - - Reference(const T* inRHS); Reference(const ValueType& inRHS); Reference(const Boxed& inRHS); Reference(const Variant& inRHS); Reference(const Dynamic& inRHS); + Reference(const T& inRHS); + Reference(T& inRHS); + Reference(const T* inRHS); operator Dynamic() const; operator Variant() const; @@ -83,181 +82,205 @@ namespace cpp ValueType& operator=(const Reference& inRHS); ValueType& operator=(const null& inRHS) = delete; }; + } +} - // Boxed implementation - - template - void Boxed_obj::finalise(::hx::Object* obj) - { - auto ptr = reinterpret_cast*>(obj); +//namespace hx +//{ +// template +// struct CompareTraits< cpp::marshal::Reference > +// { +// enum { type = (int)CompareAsDynamic }; +// +// inline static int toInt(Dynamic inValue) { return inValue; } +// inline static double toDouble(Dynamic inValue) { return inValue; } +// inline static cpp::Int64 toInt64(Dynamic inValue) { return inValue; } +// inline static String toString(Dynamic inValue) { return inValue; } +// inline static hx::Object* toObject(Dynamic inValue) { return inValue.mPtr; } +// inline static int getDynamicCompareType(const ::Dynamic&) { return type; } +// inline static bool isNull(const ::cpp::marshal::Reference& ref) { return nullptr == ref.ptr; } +// }; +//} + +// Boxed implementation + +template +void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) +{ + auto ptr = reinterpret_cast*>(obj); - ptr->value.~T(); - } + ptr->value.~T(); +} - template - Boxed_obj::Boxed_obj() : value() - { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } - } +template +cpp::marshal::Boxed_obj::Boxed_obj() : value() +{ + if constexpr (std::is_destructible::value) + { + ::hx::GCSetFinalizer(this, finalise); + } +} - template - Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) - { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } - } +template +cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) +{ + if constexpr (std::is_destructible::value) + { + ::hx::GCSetFinalizer(this, finalise); + } +} - template - template - Boxed_obj::Boxed_obj(TArgs... args) : value(std::forward(args)...) - { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } - } +template +template +cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value(std::forward(args)...) +{ + if constexpr (std::is_destructible::value) + { + ::hx::GCSetFinalizer(this, finalise); + } +} - template - Boxed_obj::operator ValueType() const - { - return ValueType(Boxed(this)); - } +// Reference implementation - // Reference implementation +template +T* cpp::marshal::Reference::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); +} - template - T* Reference::FromDynamic(const Dynamic& inRHS) - { - return FromBoxed(inRHS.Cast>()); - } +template +T* cpp::marshal::Reference::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } - template - T* Reference::FromBoxed(const Boxed& inRHS) - { - if (nullptr == inRHS.mPtr) - { - return nullptr; - } + return const_cast(&inRHS->value); +} - return const_cast(&inRHS->value); - } +template +cpp::marshal::Reference::Reference(const T& inRHS) : Super(inRHS) {} - template - Reference::Reference(const T& inRHS) : Super(inRHS) {} +template +cpp::marshal::Reference::Reference(T& inRHS) : Super(inRHS) {} - template - Reference::Reference(T& inRHS) : Super(inRHS) {} +template +cpp::marshal::Reference::Reference(const T* inRHS) : Super(inRHS) {} - template - Reference::Reference(const T* inRHS) : Super(inRHS) {} +template +cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} - template - Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} +template +cpp::marshal::Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} - template - Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} +template +cpp::marshal::Reference::Reference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} - template - Reference::Reference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} +template +cpp::marshal::Reference::Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} - template - Reference::Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} +template +cpp::marshal::Boxed cpp::marshal::Reference::ToBoxed() const +{ + if (Super::ptr) + { + return Boxed(new Boxed_obj(Super::ptr)); + } + else + { + return Boxed(); + } +} - template - Reference::operator Dynamic() const - { - return Boxed(new Boxed_obj(Super::ptr)); - } +template +cpp::marshal::Reference::operator ::Dynamic() const +{ + return ToBoxed(); +} - template - Reference::operator Variant() const - { - return Boxed(new Boxed_obj(Super::ptr)); - } +template +cpp::marshal::Reference::operator ::cpp::Variant() const +{ + return ToBoxed(); +} - template - Reference::operator Boxed() const - { - return Boxed(new Boxed_obj(Super::ptr)); - } +template +cpp::marshal::Reference::operator ::cpp::marshal::Boxed() const +{ + return ToBoxed(); +} - template - T* Reference::operator ->() const - { - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } +template +T* cpp::marshal::Reference::operator ->() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } - return Super::ptr; - } + return Super::ptr; +} - template - inline bool Reference::operator==(const Reference& inRHS) const - { - return (*Super::ptr) == (*inRHS->ptr); - } +template +inline bool cpp::marshal::Reference::operator==(const Reference& inRHS) const +{ + return (*Super::ptr) == (*inRHS->ptr); +} - template - inline bool Reference::operator!=(const Reference& inRHS) const - { - return (*Super::ptr) != (*inRHS->ptr); - } +template +inline bool cpp::marshal::Reference::operator!=(const Reference& inRHS) const +{ + return (*Super::ptr) != (*inRHS->ptr); +} - // ValueType implementation +// ValueType implementation - template - T* ValueType::FromDynamic(const Dynamic& inRHS) - { - auto boxed = inRHS.Cast>(); - auto ptr = &boxed->value; +template +T* cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) +{ + auto boxed = inRHS.Cast>(); + auto ptr = &boxed->value; - return ptr; - } + return ptr; +} - template - ValueType::ValueType() : value() {} +template +cpp::marshal::ValueType::ValueType() : value() {} - template - ValueType::ValueType(const Reference& inRHS) : value(*inRHS.ptr) {} +template +cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(*inRHS.ptr) {} - template - ValueType::ValueType(const Boxed& inRHS) : value(inRHS->value) {} +template +cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : value(inRHS->value) {} - template - ValueType::ValueType(Boxed_obj* inRHS) : value(inRHS->value) {} +template +cpp::marshal::ValueType::ValueType(Boxed_obj* inRHS) : value(inRHS->value) {} - template - ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} +template +cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} - template - ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS))) {} +template +cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS))) {} - template - template - ValueType::ValueType(TArgs ...args) : value(std::forward(args)...) {} +template +template +cpp::marshal::ValueType::ValueType(TArgs ...args) : value(std::forward(args)...) {} - template - ValueType& ValueType::operator=(const Reference& inRHS) - { - value = *inRHS.ptr; +template +cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const Reference& inRHS) +{ + value = *inRHS.ptr; - return *this; - } - } + return *this; +} - // Implement some pointer helpers here +// Implement some pointer helpers here - template - inline Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::Reference& ref) - { - return Pointer(ref.ptr); - } +template +inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::Reference& ref) +{ + return Pointer(ref.ptr); } #endif \ No newline at end of file diff --git a/include/hxcpp.h b/include/hxcpp.h index 2e8a7da90..1ccd5fdce 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -353,7 +353,6 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include -#include #include #include #include @@ -363,6 +362,7 @@ typedef PropertyAccessMode PropertyAccess; #include #include #include +#include #endif From 73d18dc54f5f5bf250b3d305340c222d7935fb76 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 1 Jan 2025 20:58:58 +0000 Subject: [PATCH 11/89] add compare traits specialisation for reference null check --- include/cpp/Marshal.h | 17 ----------------- include/hx/LessThanEq.h | 13 +++++++++++++ include/hxcpp.h | 2 +- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index dc887084a..92905d0c8 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -85,23 +85,6 @@ namespace cpp } } -//namespace hx -//{ -// template -// struct CompareTraits< cpp::marshal::Reference > -// { -// enum { type = (int)CompareAsDynamic }; -// -// inline static int toInt(Dynamic inValue) { return inValue; } -// inline static double toDouble(Dynamic inValue) { return inValue; } -// inline static cpp::Int64 toInt64(Dynamic inValue) { return inValue; } -// inline static String toString(Dynamic inValue) { return inValue; } -// inline static hx::Object* toObject(Dynamic inValue) { return inValue.mPtr; } -// inline static int getDynamicCompareType(const ::Dynamic&) { return type; } -// inline static bool isNull(const ::cpp::marshal::Reference& ref) { return nullptr == ref.ptr; } -// }; -//} - // Boxed implementation template diff --git a/include/hx/LessThanEq.h b/include/hx/LessThanEq.h index e87ebb06c..eaa3def46 100644 --- a/include/hx/LessThanEq.h +++ b/include/hx/LessThanEq.h @@ -246,6 +246,19 @@ struct CompareTraits< T * > inline static bool isNull(T *inValue) { return !inValue; } }; +template +struct CompareTraits< cpp::marshal::Reference > +{ + enum { type = (int)CompareAsDynamic }; + + inline static int toInt(Dynamic inValue) { return inValue; } + inline static double toDouble(Dynamic inValue) { return inValue; } + inline static cpp::Int64 toInt64(Dynamic inValue) { return inValue; } + inline static String toString(Dynamic inValue) { return inValue; } + inline static hx::Object* toObject(Dynamic inValue) { return inValue.mPtr; } + inline static int getDynamicCompareType(const ::Dynamic&) { return type; } + inline static bool isNull(const ::cpp::marshal::Reference& ref) { return nullptr == ref.ptr; } +}; template hx::Object *GetExistingObject(const T1 &v1) diff --git a/include/hxcpp.h b/include/hxcpp.h index 1ccd5fdce..2e8a7da90 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -353,6 +353,7 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include +#include #include #include #include @@ -362,7 +363,6 @@ typedef PropertyAccessMode PropertyAccess; #include #include #include -#include #endif From d4e7dfef68d6b1fe561bb51cf1286de4deeb13c3 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 1 Jan 2025 21:45:49 +0000 Subject: [PATCH 12/89] consistent null checking and throwing --- include/cpp/Marshal.h | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 92905d0c8..815f3c7f2 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -52,6 +52,7 @@ namespace cpp T* operator->() const; + bool operator==(const Reference& inRHS) const; bool operator!=(const Reference& inRHS) const; }; @@ -59,7 +60,9 @@ namespace cpp template class ValueType final { + static T* FromReference(const Reference& inRHS); static T* FromDynamic(const Dynamic& inRHS); + static T* FromBoxed(const Boxed& inRHS); public: T value; @@ -222,23 +225,42 @@ inline bool cpp::marshal::Reference::operator!=(const Reference& inRHS) co template T* cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) { - auto boxed = inRHS.Cast>(); - auto ptr = &boxed->value; + return FromBoxed(inRHS.StaticCast>()); +} + +template +T* cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + ::hx::NullReference("ValueType", true); + } + + return const_cast(&inRHS->value); +} + +template +T* cpp::marshal::ValueType::FromReference(const Reference& inRHS) +{ + if (nullptr == inRHS.ptr) + { + ::hx::NullReference("ValueType", true); + } - return ptr; + return inRHS.ptr; } template cpp::marshal::ValueType::ValueType() : value() {} template -cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(*inRHS.ptr) {} +cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(*FromReference(inRHS.ptr)) {} template -cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : value(inRHS->value) {} +cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS))) {} template -cpp::marshal::ValueType::ValueType(Boxed_obj* inRHS) : value(inRHS->value) {} +cpp::marshal::ValueType::ValueType(Boxed_obj* inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS))) {} template cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} From 46e0cd31be51ec68b49eb29fec39c993b8d08723 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Wed, 1 Jan 2025 21:58:56 +0000 Subject: [PATCH 13/89] raise exceptions when value types are assigned null --- include/cpp/Marshal.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 815f3c7f2..39d90d1bf 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -70,10 +70,9 @@ namespace cpp // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; - ValueType(const null& inRHS) = delete; - ValueType(); ValueType(const Reference& inRHS); + ValueType(const null& inRHS); ValueType(const Boxed& inRHS); ValueType(Boxed_obj* inRHS); ValueType(const Variant& inRHS); @@ -83,7 +82,7 @@ namespace cpp ValueType(TArgs... args); ValueType& operator=(const Reference& inRHS); - ValueType& operator=(const null& inRHS) = delete; + [[noreturn]] ValueType& operator=(const null& inRHS); }; } } @@ -256,6 +255,9 @@ cpp::marshal::ValueType::ValueType() : value() {} template cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(*FromReference(inRHS.ptr)) {} +template +inline cpp::marshal::ValueType::ValueType(const null&) : ValueType(::cpp::marshal::Reference(nullptr)) {} + template cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS))) {} @@ -280,6 +282,12 @@ cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const Referenc return *this; } +template +cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& inRHS) +{ + ::hx::NullReference("ValueType", true); +} + // Implement some pointer helpers here template From e7195b4b467348557d698d72115241b09c1cc594 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 4 Jan 2025 00:18:11 +0000 Subject: [PATCH 14/89] reference equality operations --- include/cpp/Marshal.h | 77 +++++++++++++++++++++++------------------ include/hx/LessThanEq.h | 6 ++++ 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 39d90d1bf..747d62209 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -23,6 +23,34 @@ namespace cpp Boxed_obj(TArgs... args); }; + template + class ValueType final + { + static T* FromReference(const Reference& inRHS); + static T* FromDynamic(const Dynamic& inRHS); + static T* FromBoxed(const Boxed& inRHS); + + public: + T value; + + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + + ValueType(); + ValueType(const Reference& inRHS); + ValueType(const null& inRHS); + ValueType(const Boxed& inRHS); + ValueType(Boxed_obj* inRHS); + ValueType(const Variant& inRHS); + ValueType(const Dynamic& inRHS); + + template + ValueType(TArgs... args); + + ValueType& operator=(const Reference& inRHS); + [[noreturn]] ValueType& operator=(const null& inRHS); + }; + template class Reference final : public ::cpp::Reference { @@ -51,39 +79,11 @@ namespace cpp operator Boxed() const; T* operator->() const; - + T operator*() const; bool operator==(const Reference& inRHS) const; bool operator!=(const Reference& inRHS) const; }; - - template - class ValueType final - { - static T* FromReference(const Reference& inRHS); - static T* FromDynamic(const Dynamic& inRHS); - static T* FromBoxed(const Boxed& inRHS); - - public: - T value; - - // This allows 'StaticCast' to be used from arrays - using Ptr = Dynamic; - - ValueType(); - ValueType(const Reference& inRHS); - ValueType(const null& inRHS); - ValueType(const Boxed& inRHS); - ValueType(Boxed_obj* inRHS); - ValueType(const Variant& inRHS); - ValueType(const Dynamic& inRHS); - - template - ValueType(TArgs... args); - - ValueType& operator=(const Reference& inRHS); - [[noreturn]] ValueType& operator=(const null& inRHS); - }; } } @@ -117,7 +117,7 @@ cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) template template -cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value(std::forward(args)...) +cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward(args)... ) { if constexpr (std::is_destructible::value) { @@ -210,13 +210,24 @@ T* cpp::marshal::Reference::operator ->() const template inline bool cpp::marshal::Reference::operator==(const Reference& inRHS) const { - return (*Super::ptr) == (*inRHS->ptr); + return (*Super::ptr) == (*inRHS.ptr); } template inline bool cpp::marshal::Reference::operator!=(const Reference& inRHS) const { - return (*Super::ptr) != (*inRHS->ptr); + return (*Super::ptr) != (*inRHS.ptr); +} + +template +inline T cpp::marshal::Reference::operator*() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *Super::ptr; } // ValueType implementation @@ -272,7 +283,7 @@ cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp template template -cpp::marshal::ValueType::ValueType(TArgs ...args) : value(std::forward(args)...) {} +cpp::marshal::ValueType::ValueType(TArgs... args) : value( std::forward(args)... ) {} template cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const Reference& inRHS) diff --git a/include/hx/LessThanEq.h b/include/hx/LessThanEq.h index eaa3def46..1567c2592 100644 --- a/include/hx/LessThanEq.h +++ b/include/hx/LessThanEq.h @@ -423,9 +423,15 @@ inline bool TestLessEq(const T1 &v1, const T2 &v2) template bool IsEq(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } +template +bool IsEq(const ::cpp::marshal::Reference& v1, const ::cpp::marshal::Reference& v2) { return v1 == v2; } + template bool IsNotEq(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } +template +bool IsNotEq(const ::cpp::marshal::Reference& v1, const ::cpp::marshal::Reference& v2) { return v1 != v2; } + template bool IsLess(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } From f92c9a32845bbbf1325c24e4f75e0f999a3066dd Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 4 Jan 2025 00:44:09 +0000 Subject: [PATCH 15/89] remove no return --- include/cpp/Marshal.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 747d62209..3d69f4fd7 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -48,7 +48,7 @@ namespace cpp ValueType(TArgs... args); ValueType& operator=(const Reference& inRHS); - [[noreturn]] ValueType& operator=(const null& inRHS); + ValueType& operator=(const null& inRHS); }; template @@ -297,6 +297,8 @@ template cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& inRHS) { ::hx::NullReference("ValueType", true); + + return *this; } // Implement some pointer helpers here From b49440f785092aad832b254a79bdd832c8acaef0 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 5 Jan 2025 13:48:12 +0000 Subject: [PATCH 16/89] remove some un-needed constructors --- include/cpp/Marshal.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 3d69f4fd7..d98973253 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -40,7 +40,6 @@ namespace cpp ValueType(const Reference& inRHS); ValueType(const null& inRHS); ValueType(const Boxed& inRHS); - ValueType(Boxed_obj* inRHS); ValueType(const Variant& inRHS); ValueType(const Dynamic& inRHS); @@ -57,9 +56,7 @@ namespace cpp using Super = ::cpp::Reference; static T* FromDynamic(const Dynamic& inRHS); - static T* FromBoxed(const Boxed& inRHS); - Boxed ToBoxed() const; public: @@ -272,9 +269,6 @@ inline cpp::marshal::ValueType::ValueType(const null&) : ValueType(::cpp:: template cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS))) {} -template -cpp::marshal::ValueType::ValueType(Boxed_obj* inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS))) {} - template cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} From 7f133d3b33edb429071553082d22f81cbd1d0b93 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 7 Jan 2025 19:24:50 +0000 Subject: [PATCH 17/89] Make constructors use more templates and use reinterpret cast --- include/cpp/Marshal.h | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index d98973253..bbcbe5250 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -55,8 +55,10 @@ namespace cpp { using Super = ::cpp::Reference; - static T* FromDynamic(const Dynamic& inRHS); - static T* FromBoxed(const Boxed& inRHS); + template + static O* FromDynamic(const Dynamic& inRHS); + template + static O* FromBoxed(const Boxed& inRHS); Boxed ToBoxed() const; public: @@ -65,12 +67,18 @@ namespace cpp Reference(const ValueType& inRHS); Reference(const Boxed& inRHS); - Reference(const Variant& inRHS); - Reference(const Dynamic& inRHS); Reference(const T& inRHS); Reference(T& inRHS); Reference(const T* inRHS); + template + Reference(const ValueType& inRHS); + template + Reference(const Boxed& inRHS); + + Reference(const Variant& inRHS); + Reference(const Dynamic& inRHS); + operator Dynamic() const; operator Variant() const; operator Boxed() const; @@ -125,22 +133,30 @@ cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward -T* cpp::marshal::Reference::FromDynamic(const Dynamic& inRHS) +template +O* cpp::marshal::Reference::FromDynamic(const Dynamic& inRHS) { - return FromBoxed(inRHS.StaticCast>()); + return FromBoxed(inRHS.StaticCast>()); } template -T* cpp::marshal::Reference::FromBoxed(const Boxed& inRHS) +template +O* cpp::marshal::Reference::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { return nullptr; } - return const_cast(&inRHS->value); + return const_cast(&inRHS->value); } +template +cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} + +template +cpp::marshal::Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} + template cpp::marshal::Reference::Reference(const T& inRHS) : Super(inRHS) {} @@ -151,16 +167,18 @@ template cpp::marshal::Reference::Reference(const T* inRHS) : Super(inRHS) {} template -cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} +template +cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} template -cpp::marshal::Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} +template +cpp::marshal::Reference::Reference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} template -cpp::marshal::Reference::Reference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} +cpp::marshal::Reference::Reference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::Reference::Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} +cpp::marshal::Reference::Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} template cpp::marshal::Boxed cpp::marshal::Reference::ToBoxed() const From d86f57caa84161175186f430c645bb647f5de889 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 7 Jan 2025 21:27:08 +0000 Subject: [PATCH 18/89] use tagged dispatch --- include/cpp/Marshal.h | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index bbcbe5250..433627622 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -12,6 +12,9 @@ namespace cpp { static void finalise(::hx::Object* obj); + void setFinaliser(std::true_type); + void setFinaliser(std::false_type); + public: T value; @@ -102,32 +105,32 @@ void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) ptr->value.~T(); } +template +void cpp::marshal::Boxed_obj::setFinaliser(std::true_type) +{ + ::hx::GCSetFinalizer(this, finalise); +} + +template +void cpp::marshal::Boxed_obj::setFinaliser(std::false_type) {} + template cpp::marshal::Boxed_obj::Boxed_obj() : value() { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } + setFinaliser(std::is_destructible{}); } template cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } + setFinaliser(std::is_destructible{}); } template template cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward(args)... ) { - if constexpr (std::is_destructible::value) - { - ::hx::GCSetFinalizer(this, finalise); - } + setFinaliser(std::is_destructible{}); } // Reference implementation From 9f8ab7715febe5a977e5426bed0405da6272442b Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 10 Jan 2025 20:52:47 +0000 Subject: [PATCH 19/89] support pointer types being held in value type helper --- include/cpp/Marshal.h | 62 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 433627622..9be1452b8 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -29,9 +29,17 @@ namespace cpp template class ValueType final { - static T* FromReference(const Reference& inRHS); - static T* FromDynamic(const Dynamic& inRHS); - static T* FromBoxed(const Boxed& inRHS); + // These true and false variants are called based on if T is a pointer + // If T is not a pointer trying to assign a value type to null results in a null pointer exception being thrown. + // But if T is a pointer then the value type holds a null pointer value. + + static T FromReference(const Reference& inRHS, std::true_type); + static T FromReference(const Reference& inRHS, std::false_type); + + static T FromBoxed(const Boxed& inRHS, std::true_type); + static T FromBoxed(const Boxed& inRHS, std::false_type); + + static T FromDynamic(const Dynamic& inRHS); public: T value; @@ -68,6 +76,7 @@ namespace cpp // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; + Reference(const null& inRHS); Reference(const ValueType& inRHS); Reference(const Boxed& inRHS); Reference(const T& inRHS); @@ -154,6 +163,9 @@ O* cpp::marshal::Reference::FromBoxed(const Boxed& inRHS) return const_cast(&inRHS->value); } +template +cpp::marshal::Reference::Reference(const null& inRHS) : Super(inRHS) {} + template cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} @@ -251,44 +263,70 @@ inline T cpp::marshal::Reference::operator*() const // ValueType implementation template -T* cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) +T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) { - return FromBoxed(inRHS.StaticCast>()); + return FromBoxed(inRHS.StaticCast>(), std::is_pointer{}); } template -T* cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) +T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS, std::true_type) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + else + { + return inRHS->value; + } +} + +template +T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS, std::false_type) { if (nullptr == inRHS.mPtr) { ::hx::NullReference("ValueType", true); } - return const_cast(&inRHS->value); + return inRHS->value; +} + +template +T cpp::marshal::ValueType::FromReference(const Reference& inRHS, std::true_type) +{ + if (nullptr == inRHS.ptr) + { + return nullptr; + } + else + { + return *inRHS.ptr; + } } template -T* cpp::marshal::ValueType::FromReference(const Reference& inRHS) +T cpp::marshal::ValueType::FromReference(const Reference& inRHS, std::false_type) { if (nullptr == inRHS.ptr) { ::hx::NullReference("ValueType", true); } - return inRHS.ptr; + return *inRHS.ptr; } template cpp::marshal::ValueType::ValueType() : value() {} template -cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(*FromReference(inRHS.ptr)) {} +cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(FromReference(inRHS.ptr, std::is_pointer{})) {} template -inline cpp::marshal::ValueType::ValueType(const null&) : ValueType(::cpp::marshal::Reference(nullptr)) {} +inline cpp::marshal::ValueType::ValueType(const null& inRHS) : ValueType(::cpp::marshal::Reference(inRHS)) {} template -cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS))) {} +cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS), std::is_pointer{})) {} template cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} From cfb6feedc59b786c446cc8980fbc051d1623077c Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 11 Jan 2025 13:46:14 +0000 Subject: [PATCH 20/89] Add new marshal pointer type --- include/cpp/Marshal.h | 89 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 9be1452b8..7ccab87d0 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -101,6 +101,29 @@ namespace cpp bool operator==(const Reference& inRHS) const; bool operator!=(const Reference& inRHS) const; }; + + template + class Pointer final : public ::cpp::Pointer + { + using Super = ::cpp::Pointer; + + static T* FromDynamic(const Dynamic& inRHS); + static T* FromBoxed(const Boxed& inRHS); + + Boxed ToBoxed() const; + + public: + Pointer(const Boxed& inRHS); + + operator Dynamic() const; + operator Variant() const; + operator Boxed() const; + + operator void* (); + operator void** (); + + T operator->() const; + }; } } @@ -260,6 +283,72 @@ inline T cpp::marshal::Reference::operator*() const return *Super::ptr; } +// Pointer implementation + +template +cpp::marshal::Boxed cpp::marshal::Pointer::ToBoxed() const +{ + return new Boxed_obj(ptr); +} + +template +T* cpp::marshal::Pointer::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return const_cast(&inRHS->value); +} + +template +T* cpp::marshal::Pointer::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); +} + +template +cpp::marshal::Pointer::Pointer(const Boxed& inRHS) : Super(FromBoxed(inRHS)) +{ +} + +template +cpp::marshal::Pointer::operator ::Dynamic() const +{ + return ToBoxed(); +} + +template +cpp::marshal::Pointer::operator ::cpp::Variant() const +{ + return ToBoxed(); +} + +template +cpp::marshal::Pointer::operator ::cpp::marshal::Boxed() const +{ + return ToBoxed(); +} + +template +inline cpp::marshal::Pointer::operator void* () +{ + return reinterpret_cast(*Super::ptr); +} + +template +inline cpp::marshal::Pointer::operator void** () +{ + return reinterpret_cast(Super::ptr); +} + +template +inline T cpp::marshal::Pointer::operator->() const +{ + return *Super::ptr; +} + // ValueType implementation template From 23da6f1c09d0647dca1c90e3bb7461189c274cae Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 11 Jan 2025 18:21:30 +0000 Subject: [PATCH 21/89] rename marshal types in prep for more pointer stuff --- include/cpp/Marshal.h | 190 ++++++++++++++++++++++------------------ include/cpp/Pointer.h | 2 +- include/hx/LessThanEq.h | 28 +++++- include/hxcpp.h | 6 +- 4 files changed, 132 insertions(+), 94 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 7ccab87d0..1781d0273 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -7,6 +7,10 @@ namespace cpp { namespace marshal { + /// + /// 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. + /// template class Boxed_obj final : public ::hx::Object { @@ -33,12 +37,8 @@ namespace cpp // If T is not a pointer trying to assign a value type to null results in a null pointer exception being thrown. // But if T is a pointer then the value type holds a null pointer value. - static T FromReference(const Reference& inRHS, std::true_type); - static T FromReference(const Reference& inRHS, std::false_type); - - static T FromBoxed(const Boxed& inRHS, std::true_type); - static T FromBoxed(const Boxed& inRHS, std::false_type); - + static T FromReference(const ValueReference& inRHS); + static T FromBoxed(const Boxed& inRHS); static T FromDynamic(const Dynamic& inRHS); public: @@ -48,7 +48,7 @@ namespace cpp using Ptr = Dynamic; ValueType(); - ValueType(const Reference& inRHS); + ValueType(const ValueReference& inRHS); ValueType(const null& inRHS); ValueType(const Boxed& inRHS); ValueType(const Variant& inRHS); @@ -57,12 +57,26 @@ namespace cpp template ValueType(TArgs... args); - ValueType& operator=(const Reference& inRHS); + ValueType& operator=(const ValueReference& inRHS); ValueType& operator=(const null& inRHS); }; template - class Reference final : public ::cpp::Reference + class PointerType final + { + public: + T value; + + PointerType(); + PointerType(const null&); + PointerType(T inRHS); + // PointerType(const Boxed& inRHS); + // PointerType(const Variant& inRHS); + // PointerType(const Dynamic& inRHS); + }; + + template + class ValueReference final : public ::cpp::Reference { using Super = ::cpp::Reference; @@ -76,20 +90,20 @@ namespace cpp // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; - Reference(const null& inRHS); - Reference(const ValueType& inRHS); - Reference(const Boxed& inRHS); - Reference(const T& inRHS); - Reference(T& inRHS); - Reference(const T* inRHS); + ValueReference(const null& inRHS); + ValueReference(const ValueType& inRHS); + ValueReference(const Boxed& inRHS); + ValueReference(const T& inRHS); + ValueReference(T& inRHS); + ValueReference(const T* inRHS); template - Reference(const ValueType& inRHS); + ValueReference(const ValueType& inRHS); template - Reference(const Boxed& inRHS); + ValueReference(const Boxed& inRHS); - Reference(const Variant& inRHS); - Reference(const Dynamic& inRHS); + ValueReference(const Variant& inRHS); + ValueReference(const Dynamic& inRHS); operator Dynamic() const; operator Variant() const; @@ -98,12 +112,12 @@ namespace cpp T* operator->() const; T operator*() const; - bool operator==(const Reference& inRHS) const; - bool operator!=(const Reference& inRHS) const; + bool operator==(const ValueReference& inRHS) const; + bool operator!=(const ValueReference& inRHS) const; }; template - class Pointer final : public ::cpp::Pointer + class PointerReference final : public ::cpp::Pointer { using Super = ::cpp::Pointer; @@ -113,7 +127,8 @@ namespace cpp Boxed ToBoxed() const; public: - Pointer(const Boxed& inRHS); + PointerReference(const Boxed& inRHS); + PointerReference(const PointerType& inRHS); operator Dynamic() const; operator Variant() const; @@ -169,14 +184,14 @@ cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward template -O* cpp::marshal::Reference::FromDynamic(const Dynamic& inRHS) +O* cpp::marshal::ValueReference::FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.StaticCast>()); } template template -O* cpp::marshal::Reference::FromBoxed(const Boxed& inRHS) +O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { @@ -187,39 +202,39 @@ O* cpp::marshal::Reference::FromBoxed(const Boxed& inRHS) } template -cpp::marshal::Reference::Reference(const null& inRHS) : Super(inRHS) {} +cpp::marshal::ValueReference::ValueReference(const null& inRHS) : Super(inRHS) {} template -cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(inRHS.value) {} +cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(inRHS.value) {} template -cpp::marshal::Reference::Reference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} +cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} template -cpp::marshal::Reference::Reference(const T& inRHS) : Super(inRHS) {} +cpp::marshal::ValueReference::ValueReference(const T& inRHS) : Super(inRHS) {} template -cpp::marshal::Reference::Reference(T& inRHS) : Super(inRHS) {} +cpp::marshal::ValueReference::ValueReference(T& inRHS) : Super(inRHS) {} template -cpp::marshal::Reference::Reference(const T* inRHS) : Super(inRHS) {} +cpp::marshal::ValueReference::ValueReference(const T* inRHS) : Super(inRHS) {} template template -cpp::marshal::Reference::Reference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} +cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} template template -cpp::marshal::Reference::Reference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} +cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} template -cpp::marshal::Reference::Reference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} +cpp::marshal::ValueReference::ValueReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::Reference::Reference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} +cpp::marshal::ValueReference::ValueReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::Boxed cpp::marshal::Reference::ToBoxed() const +cpp::marshal::Boxed cpp::marshal::ValueReference::ToBoxed() const { if (Super::ptr) { @@ -232,25 +247,25 @@ cpp::marshal::Boxed cpp::marshal::Reference::ToBoxed() const } template -cpp::marshal::Reference::operator ::Dynamic() const +cpp::marshal::ValueReference::operator ::Dynamic() const { return ToBoxed(); } template -cpp::marshal::Reference::operator ::cpp::Variant() const +cpp::marshal::ValueReference::operator ::cpp::Variant() const { return ToBoxed(); } template -cpp::marshal::Reference::operator ::cpp::marshal::Boxed() const +cpp::marshal::ValueReference::operator ::cpp::marshal::Boxed() const { return ToBoxed(); } template -T* cpp::marshal::Reference::operator ->() const +T* cpp::marshal::ValueReference::operator ->() const { if (nullptr == Super::ptr) { @@ -261,19 +276,19 @@ T* cpp::marshal::Reference::operator ->() const } template -inline bool cpp::marshal::Reference::operator==(const Reference& inRHS) const +inline bool cpp::marshal::ValueReference::operator==(const ValueReference& inRHS) const { return (*Super::ptr) == (*inRHS.ptr); } template -inline bool cpp::marshal::Reference::operator!=(const Reference& inRHS) const +inline bool cpp::marshal::ValueReference::operator!=(const ValueReference& inRHS) const { return (*Super::ptr) != (*inRHS.ptr); } template -inline T cpp::marshal::Reference::operator*() const +inline T cpp::marshal::ValueReference::operator*() const { if (nullptr == Super::ptr) { @@ -286,13 +301,13 @@ inline T cpp::marshal::Reference::operator*() const // Pointer implementation template -cpp::marshal::Boxed cpp::marshal::Pointer::ToBoxed() const +cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const { - return new Boxed_obj(ptr); + return new Boxed_obj(Super::ptr); } template -T* cpp::marshal::Pointer::FromBoxed(const Boxed& inRHS) +T* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { @@ -303,99 +318,95 @@ T* cpp::marshal::Pointer::FromBoxed(const Boxed& inRHS) } template -T* cpp::marshal::Pointer::FromDynamic(const Dynamic& inRHS) +T* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.StaticCast>()); } template -cpp::marshal::Pointer::Pointer(const Boxed& inRHS) : Super(FromBoxed(inRHS)) +cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) +{ +} + +template +inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(&inRHS.value) { } template -cpp::marshal::Pointer::operator ::Dynamic() const +cpp::marshal::PointerReference::operator ::Dynamic() const { return ToBoxed(); } template -cpp::marshal::Pointer::operator ::cpp::Variant() const +cpp::marshal::PointerReference::operator ::cpp::Variant() const { return ToBoxed(); } template -cpp::marshal::Pointer::operator ::cpp::marshal::Boxed() const +cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const { return ToBoxed(); } template -inline cpp::marshal::Pointer::operator void* () +inline cpp::marshal::PointerReference::operator void* () { return reinterpret_cast(*Super::ptr); } template -inline cpp::marshal::Pointer::operator void** () +inline cpp::marshal::PointerReference::operator void** () { return reinterpret_cast(Super::ptr); } template -inline T cpp::marshal::Pointer::operator->() const +inline T cpp::marshal::PointerReference::operator->() const { return *Super::ptr; } -// ValueType implementation +// template -T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) +inline cpp::marshal::PointerType::PointerType() : value(nullptr) { - return FromBoxed(inRHS.StaticCast>(), std::is_pointer{}); } template -T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS, std::true_type) +inline cpp::marshal::PointerType::PointerType(const null&) : value(nullptr) { - if (nullptr == inRHS.mPtr) - { - return nullptr; - } - else - { - return inRHS->value; - } } template -T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS, std::false_type) +inline cpp::marshal::PointerType::PointerType(T inRHS) : value(inRHS) { - if (nullptr == inRHS.mPtr) - { - ::hx::NullReference("ValueType", true); - } +} - return inRHS->value; +// ValueType implementation + +template +T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); } template -T cpp::marshal::ValueType::FromReference(const Reference& inRHS, std::true_type) +T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) { - if (nullptr == inRHS.ptr) - { - return nullptr; - } - else + if (nullptr == inRHS.mPtr) { - return *inRHS.ptr; + ::hx::NullReference("ValueType", true); } + + return inRHS->value; } template -T cpp::marshal::ValueType::FromReference(const Reference& inRHS, std::false_type) +T cpp::marshal::ValueType::FromReference(const ValueReference& inRHS) { if (nullptr == inRHS.ptr) { @@ -409,27 +420,32 @@ template cpp::marshal::ValueType::ValueType() : value() {} template -cpp::marshal::ValueType::ValueType(const Reference& inRHS) : value(FromReference(inRHS.ptr, std::is_pointer{})) {} +cpp::marshal::ValueType::ValueType(const ValueReference& inRHS) : value(FromReference(inRHS.ptr)) {} template -inline cpp::marshal::ValueType::ValueType(const null& inRHS) : ValueType(::cpp::marshal::Reference(inRHS)) {} +inline cpp::marshal::ValueType::ValueType(const null& inRHS) : ValueType(::cpp::marshal::ValueReference(inRHS)) {} template -cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::Reference(FromBoxed(inRHS), std::is_pointer{})) {} +cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::ValueReference(FromBoxed(inRHS))) {} template -cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS.asDynamic()))) {} +cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS.asDynamic()))) {} template -cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::Reference(FromDynamic(inRHS))) {} +cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS))) {} template template cpp::marshal::ValueType::ValueType(TArgs... args) : value( std::forward(args)... ) {} template -cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const Reference& inRHS) +cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const ValueReference& inRHS) { + if (nullptr == inRHS.ptr) + { + ::hx::NullReference("ValueType", true); + } + value = *inRHS.ptr; return *this; @@ -446,7 +462,7 @@ cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& in // Implement some pointer helpers here template -inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::Reference& ref) +inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::ValueReference& ref) { return Pointer(ref.ptr); } diff --git a/include/cpp/Pointer.h b/include/cpp/Pointer.h index 898c8bf27..55db33a03 100644 --- a/include/cpp/Pointer.h +++ b/include/cpp/Pointer.h @@ -513,7 +513,7 @@ class Pointer_obj template - inline static Pointer addressOf(const ::cpp::marshal::Reference&); + inline static Pointer addressOf(const ::cpp::marshal::ValueReference&); template inline static Pointer addressOf(T &value) { return Pointer(&value); } diff --git a/include/hx/LessThanEq.h b/include/hx/LessThanEq.h index 1567c2592..77b59ffa4 100644 --- a/include/hx/LessThanEq.h +++ b/include/hx/LessThanEq.h @@ -247,7 +247,7 @@ struct CompareTraits< T * > }; template -struct CompareTraits< cpp::marshal::Reference > +struct CompareTraits< cpp::marshal::ValueReference > { enum { type = (int)CompareAsDynamic }; @@ -257,7 +257,21 @@ struct CompareTraits< cpp::marshal::Reference > inline static String toString(Dynamic inValue) { return inValue; } inline static hx::Object* toObject(Dynamic inValue) { return inValue.mPtr; } inline static int getDynamicCompareType(const ::Dynamic&) { return type; } - inline static bool isNull(const ::cpp::marshal::Reference& ref) { return nullptr == ref.ptr; } + inline static bool isNull(const ::cpp::marshal::ValueReference& ref) { return nullptr == ref.ptr; } +}; + +template +struct CompareTraits< cpp::marshal::PointerReference > +{ + enum { type = (int)CompareAsDynamic }; + + inline static int toInt(Dynamic inValue) { return inValue; } + inline static double toDouble(Dynamic inValue) { return inValue; } + inline static cpp::Int64 toInt64(Dynamic inValue) { return inValue; } + inline static String toString(Dynamic inValue) { return inValue; } + inline static hx::Object* toObject(Dynamic inValue) { return inValue.mPtr; } + inline static int getDynamicCompareType(const ::Dynamic&) { return type; } + inline static bool isNull(const ::cpp::marshal::PointerReference& ref) { return nullptr == *ref.ptr; } }; template @@ -424,13 +438,19 @@ template bool IsEq(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } template -bool IsEq(const ::cpp::marshal::Reference& v1, const ::cpp::marshal::Reference& v2) { return v1 == v2; } +bool IsEq(const ::cpp::marshal::ValueReference& v1, const ::cpp::marshal::ValueReference& v2) { return v1 == v2; } + +template +bool IsEq(const ::cpp::marshal::PointerReference& v1, const ::cpp::marshal::PointerReference& v2) { return *v1.ptr == *v2.ptr; } template bool IsNotEq(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } template -bool IsNotEq(const ::cpp::marshal::Reference& v1, const ::cpp::marshal::Reference& v2) { return v1 != v2; } +bool IsNotEq(const ::cpp::marshal::ValueReference& v1, const ::cpp::marshal::ValueReference& v2) { return v1 != v2; } + +template +bool IsNotEq(const ::cpp::marshal::PointerReference& v1, const ::cpp::marshal::PointerReference& v2) { return *v1.ptr != *v2.ptr; } template bool IsLess(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } diff --git a/include/hxcpp.h b/include/hxcpp.h index 2e8a7da90..eb72dc9ff 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -260,10 +260,12 @@ namespace hx { template class ObjectPtr; } namespace cpp { template class Struct; } namespace cpp { template class Pointer; } namespace cpp { template class Function; } -namespace cpp { namespace marshal { template class ValueType; } } namespace cpp { namespace marshal { template class Boxed_obj; } } namespace cpp { namespace marshal { template using Boxed =::hx::ObjectPtr>; } } -namespace cpp { namespace marshal { template class Reference; } } +namespace cpp { namespace marshal { template class ValueType; } } +namespace cpp { namespace marshal { template class ValueReference; } } +namespace cpp { namespace marshal { template class PointerType; } } +namespace cpp { namespace marshal { template class PointerReference; } } template class Array_obj; template class Array; namespace hx { From de4c7ec0fc1bab4eed10921ed538a5e0abc10d27 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 12 Jan 2025 20:19:37 +0000 Subject: [PATCH 22/89] support reinterpreting value type references --- include/cpp/Marshal.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 1781d0273..8171478f3 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -97,6 +97,8 @@ namespace cpp ValueReference(T& inRHS); ValueReference(const T* inRHS); + template + ValueReference(const ValueReference& inRHS); template ValueReference(const ValueType& inRHS); template @@ -133,6 +135,7 @@ namespace cpp operator Dynamic() const; operator Variant() const; operator Boxed() const; + operator PointerType(); operator void* (); operator void** (); @@ -219,6 +222,10 @@ cpp::marshal::ValueReference::ValueReference(T& inRHS) : Super(inRHS) {} template cpp::marshal::ValueReference::ValueReference(const T* inRHS) : Super(inRHS) {} +template +template +inline cpp::marshal::ValueReference::ValueReference(const ValueReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} + template template cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} @@ -351,6 +358,19 @@ cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const return ToBoxed(); } +template +cpp::marshal::PointerReference::operator ::cpp::marshal::PointerType() +{ + if (Super::ptr) + { + return ::cpp::marshal::PointerType(*Super::ptr); + } + else + { + return ::cpp::marshal::PointerType(nullptr); + } +} + template inline cpp::marshal::PointerReference::operator void* () { From 800410001c34bef0943999f4baca815bd7c4e13f Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Thu, 16 Jan 2025 22:46:23 +0000 Subject: [PATCH 23/89] seemingly working pointer marshalling types --- include/cpp/Marshal.h | 144 +++++++++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 36 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 8171478f3..6da07f042 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -64,15 +64,26 @@ namespace cpp template class PointerType final { + static T FromReference(const PointerReference& inRHS); + static T FromBoxed(const Boxed& inRHS); + static T FromDynamic(const Dynamic& inRHS); + public: + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + T value; PointerType(); - PointerType(const null&); PointerType(T inRHS); - // PointerType(const Boxed& inRHS); - // PointerType(const Variant& inRHS); - // PointerType(const Dynamic& inRHS); + PointerType(const PointerReference& inRHS); + PointerType(const null& inRHS); + PointerType(const Boxed& inRHS); + PointerType(const Variant& inRHS); + PointerType(const Dynamic& inRHS); + + PointerType& operator=(const PointerReference& inRHS); + PointerType& operator=(const null& inRHS); }; template @@ -119,23 +130,31 @@ namespace cpp }; template - class PointerReference final : public ::cpp::Pointer + class PointerReference final : public ::cpp::Reference { - using Super = ::cpp::Pointer; + using Super = ::cpp::Reference; - static T* FromDynamic(const Dynamic& inRHS); - static T* FromBoxed(const Boxed& inRHS); + template + static O* FromDynamic(const Dynamic& inRHS); + + template + static O* FromBoxed(const Boxed& inRHS); Boxed ToBoxed() const; public: - PointerReference(const Boxed& inRHS); + PointerReference(const null& inRHS); PointerReference(const PointerType& inRHS); + PointerReference(const Boxed& inRHS); + PointerReference(const T& inRHS); + PointerReference(T& inRHS); + PointerReference(const T* inRHS); + PointerReference(const Variant& inRHS); + PointerReference(const Dynamic& inRHS); operator Dynamic() const; operator Variant() const; operator Boxed() const; - operator PointerType(); operator void* (); operator void** (); @@ -314,31 +333,47 @@ cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const } template -T* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) +template +O* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { return nullptr; } - return const_cast(&inRHS->value); + return const_cast(&inRHS->value); } template -T* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) +template +O* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) { - return FromBoxed(inRHS.StaticCast>()); + return FromBoxed(inRHS.StaticCast>()); } template -cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) -{ -} +cpp::marshal::PointerReference::PointerReference(const null& inRHS) : Super(inRHS) {} template -inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(&inRHS.value) -{ -} +cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(inRHS.value) {} + +template +cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} + +template +cpp::marshal::PointerReference::PointerReference(const T& inRHS) : Super(inRHS) {} + +template +cpp::marshal::PointerReference::PointerReference(T& inRHS) : Super(inRHS) {} + +template +cpp::marshal::PointerReference::PointerReference(const T* inRHS) : Super(inRHS) {} + +template +cpp::marshal::PointerReference::PointerReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} + +template +cpp::marshal::PointerReference::PointerReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} template cpp::marshal::PointerReference::operator ::Dynamic() const @@ -358,19 +393,6 @@ cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const return ToBoxed(); } -template -cpp::marshal::PointerReference::operator ::cpp::marshal::PointerType() -{ - if (Super::ptr) - { - return ::cpp::marshal::PointerType(*Super::ptr); - } - else - { - return ::cpp::marshal::PointerType(nullptr); - } -} - template inline cpp::marshal::PointerReference::operator void* () { @@ -392,18 +414,68 @@ inline T cpp::marshal::PointerReference::operator->() const // template -inline cpp::marshal::PointerType::PointerType() : value(nullptr) +T cpp::marshal::PointerType::FromDynamic(const Dynamic& inRHS) { + return FromBoxed(inRHS.StaticCast>()); +} + +template +T cpp::marshal::PointerType::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return inRHS->value; +} + +template +T cpp::marshal::PointerType::FromReference(const PointerReference& inRHS) +{ + if (nullptr == inRHS.ptr) + { + return nullptr; + } + + return *inRHS.ptr; } template -inline cpp::marshal::PointerType::PointerType(const null&) : value(nullptr) +inline cpp::marshal::PointerType::PointerType() : value(nullptr) {} + +template +inline cpp::marshal::PointerType::PointerType(T inRHS) : value(inRHS) {} + +template +inline cpp::marshal::PointerType::PointerType(const PointerReference& inRHS) : value(FromReference(inRHS.ptr)) {} + +template +inline cpp::marshal::PointerType::PointerType(const null&) : value(nullptr) {} + +template +inline cpp::marshal::PointerType::PointerType(const Boxed& inRHS) : value(FromBoxed(inRHS)) {} + +template +inline cpp::marshal::PointerType::PointerType(const Variant& inRHS) : value(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::PointerType::PointerType(const Dynamic& inRHS) : value(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(const PointerReference& inRHS) { + value = *inRHS.ptr; + + return *this; } template -inline cpp::marshal::PointerType::PointerType(T inRHS) : value(inRHS) +inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(const null& inRHS) { + value = nullptr; + + return *this; } // ValueType implementation From 55723642b0c8f797e5932c26e0d4a3b848120759 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 19 Jan 2025 20:28:31 +0000 Subject: [PATCH 24/89] better null checking with pointer references --- include/cpp/Marshal.h | 47 +++++++++++++++++++++++++++++++++++++++-- include/hx/LessThanEq.h | 22 ++++++++++++++++--- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 6da07f042..3441d8505 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -146,6 +146,14 @@ namespace cpp PointerReference(const null& inRHS); PointerReference(const PointerType& inRHS); PointerReference(const Boxed& inRHS); + + template + PointerReference(const PointerReference& inRHS); + template + PointerReference(const PointerType& inRHS); + template + PointerReference(const Boxed& inRHS); + PointerReference(const T& inRHS); PointerReference(T& inRHS); PointerReference(const T* inRHS); @@ -329,7 +337,14 @@ inline T cpp::marshal::ValueReference::operator*() const template cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const { - return new Boxed_obj(Super::ptr); + if (nullptr == Super::ptr) + { + return new Boxed_obj(); + } + else + { + return new Boxed_obj(Super::ptr); + } } template @@ -360,11 +375,29 @@ cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) template cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} +template +template +cpp::marshal::PointerReference::PointerReference(const PointerReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} + +template +template +cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} + +template +template +cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} + template cpp::marshal::PointerReference::PointerReference(const T& inRHS) : Super(inRHS) {} template -cpp::marshal::PointerReference::PointerReference(T& inRHS) : Super(inRHS) {} +cpp::marshal::PointerReference::PointerReference(T& inRHS) +{ + if (nullptr != inRHS) + { + Super::ptr = &inRHS; + } +} template cpp::marshal::PointerReference::PointerReference(const T* inRHS) : Super(inRHS) {} @@ -408,6 +441,16 @@ inline cpp::marshal::PointerReference::operator void** () template inline T cpp::marshal::PointerReference::operator->() const { + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + if (nullptr == *Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + return *Super::ptr; } diff --git a/include/hx/LessThanEq.h b/include/hx/LessThanEq.h index 77b59ffa4..f5762b2a7 100644 --- a/include/hx/LessThanEq.h +++ b/include/hx/LessThanEq.h @@ -271,7 +271,7 @@ struct CompareTraits< cpp::marshal::PointerReference > inline static String toString(Dynamic inValue) { return inValue; } inline static hx::Object* toObject(Dynamic inValue) { return inValue.mPtr; } inline static int getDynamicCompareType(const ::Dynamic&) { return type; } - inline static bool isNull(const ::cpp::marshal::PointerReference& ref) { return nullptr == *ref.ptr; } + inline static bool isNull(const ::cpp::marshal::PointerReference& ref) { return nullptr == ref.ptr || nullptr == *ref.ptr; } }; template @@ -441,7 +441,23 @@ template bool IsEq(const ::cpp::marshal::ValueReference& v1, const ::cpp::marshal::ValueReference& v2) { return v1 == v2; } template -bool IsEq(const ::cpp::marshal::PointerReference& v1, const ::cpp::marshal::PointerReference& v2) { return *v1.ptr == *v2.ptr; } +bool IsEq(const ::cpp::marshal::PointerReference& v1, const ::cpp::marshal::PointerReference& v2) +{ + if (nullptr == v1.ptr && nullptr == v2.ptr) + { + return true; + } + if (nullptr == v1.ptr && nullptr != v2.ptr) + { + return nullptr == *v2.ptr; + } + if (nullptr == v2.ptr && nullptr != v1.ptr) + { + return nullptr == *v1.ptr; + } + + return *v1.ptr == *v2.ptr; +} template bool IsNotEq(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } @@ -450,7 +466,7 @@ template bool IsNotEq(const ::cpp::marshal::ValueReference& v1, const ::cpp::marshal::ValueReference& v2) { return v1 != v2; } template -bool IsNotEq(const ::cpp::marshal::PointerReference& v1, const ::cpp::marshal::PointerReference& v2) { return *v1.ptr != *v2.ptr; } +bool IsNotEq(const ::cpp::marshal::PointerReference& v1, const ::cpp::marshal::PointerReference& v2) { return IsEq(v1, v2) == false; } template bool IsLess(const T1 &v1, const T2 &v2) { return TestLessEq(v1,v2); } From 2ffcf811ea14391990394a063fdc2294da1bab7a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 19 Jan 2025 20:30:06 +0000 Subject: [PATCH 25/89] add marshalling tests --- test/RunTests.hx | 10 + test/marshalling/build.hxml | 5 + test/marshalling/src/Build.xml | 35 ++ test/marshalling/src/Context.hx | 15 + test/marshalling/src/Main.hx | 24 ++ test/marshalling/src/StdVector.hx | 11 + .../src/classes/TestAbstractValueType.hx | 54 +++ .../src/classes/TestClassValueType.hx | 208 ++++++++++ .../src/classes/TestEnumValueType.hx | 80 ++++ .../src/classes/TestInheritance.hx | 86 +++++ .../src/classes/TestInterfaceValueType.hx | 113 ++++++ .../src/classes/TestLocalValueType.hx | 356 ++++++++++++++++++ .../src/classes/TestValueTypeCollections.hx | 64 ++++ .../src/classes/TestValueTypeFields.hx | 147 ++++++++ .../src/classes/TestValueTypeInterop.hx | 219 +++++++++++ .../src/enums/TestValueTypeEnumAbstract.hx | 101 +++++ .../enums/TestValueTypeEnumClassAbstract.hx | 99 +++++ test/marshalling/src/native/Base.cpp | 7 + test/marshalling/src/native/Base.hpp | 5 + test/marshalling/src/native/Child.cpp | 12 + test/marshalling/src/native/Child.hpp | 8 + test/marshalling/src/native/ctx.cpp | 15 + test/marshalling/src/native/ctx.hpp | 12 + test/marshalling/src/native/holder.cpp | 15 + test/marshalling/src/native/holder.hpp | 19 + test/marshalling/src/native/point.cpp | 4 + test/marshalling/src/native/point.hpp | 13 + .../src/pointers/TestClassPointers.hx | 200 ++++++++++ .../src/pointers/TestEnumPointers.hx | 78 ++++ .../src/pointers/TestInheritancePointers.hx | 90 +++++ .../src/pointers/TestInterfacePointers.hx | 104 +++++ .../src/pointers/TestLocalPointers.hx | 225 +++++++++++ .../src/pointers/TestPointerFields.hx | 47 +++ 33 files changed, 2481 insertions(+) create mode 100644 test/marshalling/build.hxml create mode 100644 test/marshalling/src/Build.xml create mode 100644 test/marshalling/src/Context.hx create mode 100644 test/marshalling/src/Main.hx create mode 100644 test/marshalling/src/StdVector.hx create mode 100644 test/marshalling/src/classes/TestAbstractValueType.hx create mode 100644 test/marshalling/src/classes/TestClassValueType.hx create mode 100644 test/marshalling/src/classes/TestEnumValueType.hx create mode 100644 test/marshalling/src/classes/TestInheritance.hx create mode 100644 test/marshalling/src/classes/TestInterfaceValueType.hx create mode 100644 test/marshalling/src/classes/TestLocalValueType.hx create mode 100644 test/marshalling/src/classes/TestValueTypeCollections.hx create mode 100644 test/marshalling/src/classes/TestValueTypeFields.hx create mode 100644 test/marshalling/src/classes/TestValueTypeInterop.hx create mode 100644 test/marshalling/src/enums/TestValueTypeEnumAbstract.hx create mode 100644 test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx create mode 100644 test/marshalling/src/native/Base.cpp create mode 100644 test/marshalling/src/native/Base.hpp create mode 100644 test/marshalling/src/native/Child.cpp create mode 100644 test/marshalling/src/native/Child.hpp create mode 100644 test/marshalling/src/native/ctx.cpp create mode 100644 test/marshalling/src/native/ctx.hpp create mode 100644 test/marshalling/src/native/holder.cpp create mode 100644 test/marshalling/src/native/holder.hpp create mode 100644 test/marshalling/src/native/point.cpp create mode 100644 test/marshalling/src/native/point.hpp create mode 100644 test/marshalling/src/pointers/TestClassPointers.hx create mode 100644 test/marshalling/src/pointers/TestEnumPointers.hx create mode 100644 test/marshalling/src/pointers/TestInheritancePointers.hx create mode 100644 test/marshalling/src/pointers/TestInterfacePointers.hx create mode 100644 test/marshalling/src/pointers/TestLocalPointers.hx create mode 100644 test/marshalling/src/pointers/TestPointerFields.hx diff --git a/test/RunTests.hx b/test/RunTests.hx index 06f0c79c2..7a3a88c37 100644 --- a/test/RunTests.hx +++ b/test/RunTests.hx @@ -56,6 +56,13 @@ class RunTests } + public static function marshalling() + { + setDir("marshalling"); + + command("haxe", [ "build.hxml" ]); + command("bin" + sep + "Main-debug", []); + } public static function debugger() { @@ -188,6 +195,9 @@ class RunTests //run("opMatrix", opMatrix); run("haxe", runHaxe); run("telemetry", runTelemetry); +#if (haxe_ver >= 5) + run("marshalling", marshalling); +#end run("std32", std32); run("std64", std64); run("native", native); diff --git a/test/marshalling/build.hxml b/test/marshalling/build.hxml new file mode 100644 index 000000000..4ae32f8d5 --- /dev/null +++ b/test/marshalling/build.hxml @@ -0,0 +1,5 @@ +-p src +-m Main +-L utest +--cpp bin +--debug \ No newline at end of file diff --git a/test/marshalling/src/Build.xml b/test/marshalling/src/Build.xml new file mode 100644 index 000000000..81ff1a3b3 --- /dev/null +++ b/test/marshalling/src/Build.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/marshalling/src/Context.hx b/test/marshalling/src/Context.hx new file mode 100644 index 000000000..b232dda96 --- /dev/null +++ b/test/marshalling/src/Context.hx @@ -0,0 +1,15 @@ +@:semantics(reference) +@:include('ctx.hpp') +@:cpp.PointerType({ type : 'ctx' }) +extern class Context { + @:native('create') + public static function create() : Context; + + @:native('create_null') + public static function createNull() : Context; + + var number : Int; + + @:native('Double') + function double() : Int; +} \ No newline at end of file diff --git a/test/marshalling/src/Main.hx b/test/marshalling/src/Main.hx new file mode 100644 index 000000000..f0bfb2527 --- /dev/null +++ b/test/marshalling/src/Main.hx @@ -0,0 +1,24 @@ +@:buildXml("") +class Main { + static function main() { + utest.UTest.run([ + new classes.TestLocalValueType(), + new classes.TestClassValueType(), + new classes.TestInterfaceValueType(), + new classes.TestEnumValueType(), + new classes.TestAbstractValueType(), + new classes.TestValueTypeInterop(), + new classes.TestValueTypeCollections(), + new classes.TestValueTypeFields(), + new classes.TestInheritance(), + new enums.TestValueTypeEnumAbstract(), + new enums.TestValueTypeEnumClassAbstract(), + new pointers.TestLocalPointers(), + new pointers.TestClassPointers(), + new pointers.TestInterfacePointers(), + new pointers.TestInheritancePointers(), + new pointers.TestEnumPointers(), + new pointers.TestPointerFields() + ]); + } +} \ No newline at end of file diff --git a/test/marshalling/src/StdVector.hx b/test/marshalling/src/StdVector.hx new file mode 100644 index 000000000..adc073c5a --- /dev/null +++ b/test/marshalling/src/StdVector.hx @@ -0,0 +1,11 @@ +@:include('vector') +@:semantics(reference) +@:cpp.ValueType({ type : 'vector', namespace : [ 'std' ] }) +extern class StdVector implements ArrayAccess { + @:overload(function ():Void {}) + function new(s:Int):Void; + + function size():Int; + + function resize(s:Int):Void; +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestAbstractValueType.hx b/test/marshalling/src/classes/TestAbstractValueType.hx new file mode 100644 index 000000000..5073bb6dc --- /dev/null +++ b/test/marshalling/src/classes/TestAbstractValueType.hx @@ -0,0 +1,54 @@ +package classes; + +import StdVector; +import utest.Assert; +import utest.Test; + +abstract MyVector(StdVector) { + public var size (get, never) : Int; + + function get_size() { + return this.size(); + } + + public function new() { + this = new StdVector(50); + } + + public function resize(_size:Int) { + this.resize(_size); + } +} + +class TestAbstractValueType extends Test { + function test_cast_to_underlying() { + final v = new MyVector(); + + Assert.equals(50, (cast v : StdVector).size()); + } + + function test_property_access() { + final v = new MyVector(); + + Assert.equals(50, v.size); + } + + function test_mutating_abstract() { + final v = new MyVector(); + + v.resize(100); + + Assert.equals(100, v.size); + Assert.equals(100, (cast v : StdVector).size()); + } + + function test_casting_copy() { + final v = new MyVector(); + final i = (cast v : StdVector); + + v.resize(100); + + Assert.equals(100, v.size); + Assert.equals( 50, i.size()); + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestClassValueType.hx b/test/marshalling/src/classes/TestClassValueType.hx new file mode 100644 index 000000000..54e01ed18 --- /dev/null +++ b/test/marshalling/src/classes/TestClassValueType.hx @@ -0,0 +1,208 @@ +package classes; + +import utest.Assert; +import utest.Test; + +class Foo { + public static var v_static = new StdVector(50); + + public var v : StdVector; + + public function new() { + v = new StdVector(7); + } + + public function get() { + return v; + } + + public function multiply(v:StdVector) { + v.resize(v.size() * 2); + + return v.size(); + } + + public dynamic function pass_through(v:StdVector) { + return v; + } + + public static function get_random(max:Int) { + return new StdVector(max + Std.random(max)); + } +} + +class WithConstruction { + public final v : StdVector; + + public function new(v) { + this.v = v; + } +} + +class TestClassValueType extends Test { + + // Member Variables + + function test_class_field_access() { + final f = new Foo(); + + Assert.equals(7, f.v.size()); + } + + function test_mutating_class_field() { + final f = new Foo(); + + f.v.resize(100); + + Assert.equals(100, f.v.size()); + } + + function test_class_field_copy() { + final f = new Foo(); + final v = f.v; + + v.resize(100); + + Assert.equals(100, v.size()); + Assert.equals(7, f.v.size()); + } + + function test_class_field_assignment() { + final f = new Foo(); + + f.v = new StdVector(100); + + Assert.equals(100, f.v.size()); + } + + function test_class_reflect_variable() { + final f = new Foo(); + final s = (Reflect.field(f, 'v') : StdVector).size(); + + Assert.equals(7, s); + } + + function test_class_reflect_variable_mutation() { + final f = new Foo(); + + (Reflect.field(f, 'v') : StdVector).resize(100); + + Assert.equals(100, f.v.size()); + } + + function test_class_reflect_variable_assignment() { + final f = new Foo(); + + Reflect.setField(f, 'v', new StdVector(100)); + + Assert.equals(100, f.v.size()); + } + + // Static Variables + + function test_static_variable_mutation() { + Foo.v_static.resize(100); + + Assert.equals(100, Foo.v_static.size()); + } + + function test_static_variable_assignment() { + Foo.v_static = new StdVector(25); + + Assert.equals(25, Foo.v_static.size()); + } + + function test_static_variable_copy() { + final v = Foo.v_static; + + v.resize(75); + + Assert.equals(75, v.size()); + Assert.notEquals(75, Foo.v_static.size()); + } + + function test_static_class_reflect_variable() { + Foo.v_static.resize(11); + + final s = (Reflect.field(Foo, 'v_static') : StdVector).size(); + + Assert.equals(11, s); + } + + function test_static_class_reflect_variable_mutation() { + (Reflect.field(Foo, 'v_static') : StdVector).resize(12); + + Assert.equals(12, Foo.v_static.size()); + } + + function test_static_class_reflect_variable_assignment() { + Reflect.setField(Foo, 'v_static', new StdVector(13)); + + Assert.equals(13, Foo.v_static.size()); + } + + // Member Functions + + function test_class_function_copy() { + final f = new Foo(); + final v = f.get(); + + v.resize(100); + + Assert.equals(100, v.size()); + Assert.equals(7, f.v.size()); + } + + function test_class_function_pass() { + final f = new Foo(); + final v = new StdVector(7); + final s = f.multiply(v); + + Assert.equals(7, v.size()); + Assert.equals(14, s); + } + + function test_class_function_call() { + final f = new Foo(); + final s = f.get().size(); + + Assert.equals(7, s); + } + + function test_member_dynamic_function() { + final f = new Foo(); + final v = f.pass_through(new StdVector(10)); + + Assert.equals(10, v.size()); + } + + // Static Functions + + function test_static_function() { + Assert.equals(true, Foo.get_random(100).size() >= 100); + } + + // Construction + + function test_constructor() { + final v = new StdVector(7); + final o = new WithConstruction(v); + + o.v.resize(100); + + Assert.equals(100, o.v.size()); + Assert.equals(7, v.size()); + } + + function test_reflection_create_empty() { + final f : WithConstruction = Type.createEmptyInstance(WithConstruction); + + Assert.isNull(f.v); + } + + function test_reflection_create() { + final f : WithConstruction = Type.createInstance(WithConstruction, [ new StdVector(7) ]); + + Assert.equals(7, f.v.size()); + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestEnumValueType.hx b/test/marshalling/src/classes/TestEnumValueType.hx new file mode 100644 index 000000000..f0cf7807a --- /dev/null +++ b/test/marshalling/src/classes/TestEnumValueType.hx @@ -0,0 +1,80 @@ +package classes; + +import haxe.EnumTools; +import utest.Assert; +import utest.Test; + +enum FooEnum { + Bar(v:StdVector); +} + +class TestEnumValueType extends Test { + function test_copy_into_enum() { + final v = new StdVector(50); + final e = FooEnum.Bar(v); + + switch e { + case Bar(v_copy): + v.resize(100); + + Assert.equals(100, v.size()); + Assert.equals( 50, v_copy.size()); + } + } + + function test_mutating_enum() { + final e = FooEnum.Bar(new StdVector(50)); + + switch e { + case Bar(v1): + v1.resize(100); + + Assert.equals(100, v1.size()); + + switch e { + case Bar(v2): + Assert.equals(100, v2.size()); + } + } + } + + function test_copy_from_enum() { + final e = FooEnum.Bar(new StdVector(50)); + + switch e { + case Bar(v): + final v_copy = v; + + v_copy.resize(100); + + Assert.equals(100, v_copy.size()); + Assert.equals( 50, v.size()); + } + } + + function test_create_by_index() { + final v1 = new StdVector(50); + final e = EnumTools.createByIndex(FooEnum, 0, [ v1 ]); + + switch e { + case Bar(v2): + v1.resize(100); + + Assert.equals(100, v1.size()); + Assert.equals( 50, v2.size()); + } + } + + function test_create_by_name() { + final v1 = new StdVector(50); + final e = EnumTools.createByName(FooEnum, 'Bar', [ v1 ]); + + switch e { + case Bar(v2): + v1.resize(100); + + Assert.equals(100, v1.size()); + Assert.equals( 50, v2.size()); + } + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestInheritance.hx b/test/marshalling/src/classes/TestInheritance.hx new file mode 100644 index 000000000..1202c856a --- /dev/null +++ b/test/marshalling/src/classes/TestInheritance.hx @@ -0,0 +1,86 @@ +package classes; + +import utest.Assert; +import utest.Test; + +@:semantics(reference) +@:include('Base.hpp') +@:cpp.ValueType +private extern class Base { + function foo():Int; +} + +@:semantics(reference) +@:include('Child.hpp') +@:cpp.ValueType +private extern class Child extends Base { + function new():Void; + + function bar():Int; +} + +class TestInheritance extends Test { + function test_copying_to_a_more_specific_type() { + final o = create_child(); + final c : Child = cast o; + + Assert.equals(10, c.foo()); + Assert.equals(20, c.bar()); + } + + function test_copying_to_a_more_specific_type_promoted() { + final o = create_child(); + final c : Child = cast o; + final f = () -> { + return c.bar(); + } + + f(); + + Assert.equals(10, c.foo()); + Assert.equals(20, c.bar()); + } + + function test_casting_var_to_base() { + final o = create_child(); + final v = (cast o : Child).bar(); + + Assert.equals(20, v); + } + + function test_passing_child_to_child_function() { + final o = new Child(); + final v = pass_child(o); + + Assert.equals(10, v); + } + + function test_passing_child_to_base_function() { + final o = new Child(); + final v = pass_base(o); + + Assert.equals(7, v); + } + + function test_reassigning() { + var o : Base = new Child(); + + Assert.equals(7, o.foo()); + + o = new Child(); + + Assert.equals(7, o.foo()); + } + + function create_child() : Base { + return new Child(); + } + + function pass_child(c : Child) { + return c.foo(); + } + + function pass_base(b : Base) { + return b.foo(); + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestInterfaceValueType.hx b/test/marshalling/src/classes/TestInterfaceValueType.hx new file mode 100644 index 000000000..54a72722e --- /dev/null +++ b/test/marshalling/src/classes/TestInterfaceValueType.hx @@ -0,0 +1,113 @@ +package classes; + +import utest.Assert; +import utest.Test; + +interface IBar { + var v : StdVector; + + function get() : StdVector; + + function multiply(v : StdVector) : Int; +} + +class Bar implements IBar { + public var v : StdVector; + + public function new() { + v = new StdVector(7); + } + + public function get() { + return v; + } + + public function multiply(v:StdVector) { + v.resize(v.size() * 2); + + return v.size(); + } +} + +class TestInterfaceValueType extends Test { + function test_interface_field_access() { + final f : IBar = new Bar(); + + Assert.equals(7, f.v.size()); + } + + function test_mutating_interface_field() { + final f : IBar = new Bar(); + + f.v.resize(100); + + Assert.equals(100, f.v.size()); + } + + function test_interface_field_copy() { + final f : IBar = new Bar(); + final v = f.v; + + v.resize(100); + + Assert.equals(100, v.size()); + Assert.equals(7, f.v.size()); + } + + function test_interface_function_copy() { + final f : IBar = new Bar(); + final v = f.get(); + + v.resize(100); + + Assert.equals(100, v.size()); + Assert.equals(7, f.v.size()); + } + + function test_interface_field_assignment() { + final f : IBar = new Bar(); + + f.v = new StdVector(100); + + Assert.equals(100, f.v.size()); + } + + function test_interface_function_pass() { + final f : IBar = new Bar(); + final v = new StdVector(7); + final s = f.multiply(v); + + Assert.equals(7, v.size()); + Assert.equals(14, s); + } + + function test_interface_function_call() { + final f : IBar = new Bar(); + final s = f.get().size(); + + Assert.equals(7, s); + } + + function test_interface_reflect_variable() { + final f : IBar = new Bar(); + final s = (Reflect.field(f, 'v') : StdVector).size(); + + Assert.equals(7, s); + } + + function test_interface_reflect_variable_mutation() { + final f : IBar = new Bar(); + + (Reflect.field(f, 'v') : StdVector).resize(100); + + Assert.equals(100, f.v.size()); + } + + function test_interface_reflect_variable_assignment() { + final f : IBar = new Bar(); + + Reflect.setField(f, 'v', new StdVector(100)); + + Assert.equals(100, f.v.size()); + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestLocalValueType.hx b/test/marshalling/src/classes/TestLocalValueType.hx new file mode 100644 index 000000000..a7f4ad276 --- /dev/null +++ b/test/marshalling/src/classes/TestLocalValueType.hx @@ -0,0 +1,356 @@ +package classes; + +import utest.Assert; +import utest.Test; + +private class StdVectorIterator { + final max : Int; + var current : Int; + + public function new() { + max = 10 + Std.random(10); + current = 0; + } + + public function hasNext() { + return current < max; + } + + public function next() { + return new StdVector(current++); + } +} + +class TestLocalValueType extends Test { + /** + * Declaring a new variable of a value type will copy the right hand side value. + */ + function test_var_copying() { + final v1 = new StdVector(); + final v2 = v1; + + v1.resize(10); + + Assert.equals(10, v1.size()); + Assert.equals( 0, v2.size()); + } + + /** + * Value type variables can be re-assigned and the internal reference is still correct. + */ + function test_var_assignment() { + var v = new StdVector(50); + + v = new StdVector(); + + Assert.equals(0, v.size()); + } + + function test_nullable_var_null() { + final v : Null> = null; + + Assert.isNull(v); + } + + function test_nullable_var_not_null() { + final v : Null> = new StdVector(); + + Assert.notNull(v); + } + + function test_nullable_var_null_copy() { + final v1 : Null> = null; + final v2 = v1; + + Assert.isNull(v1); + Assert.isNull(v2); + } + + function test_nullable_var_to_non_null() { + final v1 : Null> = new StdVector(); + final v2 : StdVector = v1; + + Assert.notNull(v1); + Assert.notNull(v2); + } + + @:analyzer(no_local_dce) + function test_nullable_var_null_to_non_null() { + final v1 : Null> = null; + + Assert.raises(() -> { + final _ : StdVector = v1; + }); + } + + function test_assigning_null_to_non_null_var() { + Assert.raises(() -> { + var v = new StdVector(50); + + v = null; + }); + } + + @:analyzer(no_local_dce) + function test_initialising_non_null_var_to_null() { + Assert.raises(() -> { + var _ : StdVector = null; + }); + } + + @:analyzer(no_local_dce) + function test_initialising_non_null_var_to_dynamic_null() { + function get_null() : Any { + return null; + } + + Assert.raises(() -> { + var _ : StdVector = get_null(); + }); + } + + /** + * Value type function arguments can be re-assigned and the internal reference is still correct. + */ + function test_argument_assignment() { + final v = new StdVector(); + + Assert.equals(10, argument_assign(v)); + Assert.equals(0, v.size()); + } + + function argument_assign(arg) { + arg = new StdVector(10); + + return arg.size(); + } + + /** + * Lamba functions which accept value types as arguments can be correctly re-assigned. + */ + function test_lambda_argument_assignment() { + final v = new StdVector(); + final f = arg -> { + arg = new StdVector(10); + + return arg.size(); + } + + Assert.equals(10, f(v)); + Assert.equals(0, v.size()); + } + + /** + * Passing a value type into a function will pass it by value. + */ + function test_function_copying() { + final v = new StdVector(); + + by_value(v); + + Assert.equals( 0, v.size()); + } + + function by_value(v:StdVector) { + v.resize(10); + } + + /** + * Variables captured by closures will be wrapped in a type which moves them to the GC heap. + */ + function test_heap_promotion() { + final v = new StdVector(); + final f = () -> { + v.resize(10); + } + + f(); + + Assert.equals(10, v.size()); + } + + /** + * Function arguments which are captured are promoted to retain consistent behaviour. + */ + function test_promoting_function_argument() { + final v = new StdVector(); + final s = promote_arg(v); + + Assert.equals(10, s.fst); + Assert.equals(10, s.snd); + } + + function promote_arg(v:StdVector) { + final f = () -> { + v.resize(10); + + return v.size(); + } + final newSize = f(); + final oldSize = v.size(); + + return { fst : oldSize, snd : newSize } + } + + /** + * Lambda arguments which are captured are promoted to retain consistent behaviour. + */ + function test_promoting_lambda_argument() { + final v = new StdVector(); + + function lambda_promote_arg(v:StdVector) { + final f = () -> { + v.resize(10); + + return v.size(); + } + + final newSize = f(); + final oldSize = v.size(); + + return { fst : oldSize, snd : newSize } + } + + final s = lambda_promote_arg(v); + + Assert.equals(10, s.fst); + Assert.equals(10, s.snd); + } + + /** + * Value type variables passed into a function of type dynamic will also be passed a copy. + */ + function test_dynamic() { + final v = new StdVector(5); + + by_value_dynamic(v); + + Assert.equals(5, v.size()); + } + + /** + * Value type variables which have been promoted to the heap will be copied to dynamic functions argumens. + */ + function test_promoted_dynamic() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + by_value_dynamic(v); + + Assert.equals(5, v.size()); + } + + /** + * Value type variables passed put into and accessed via an anonymous object will be promoted to the heap. + */ + function test_anon() { + final v = new StdVector(5); + + by_value_anon({ v : v }); + + Assert.equals(5, v.size()); + } + + function by_value_anon(a:{ v : StdVector }) { + Assert.equals(5, a.v.size()); + + a.v.resize(10); + + Assert.equals(10, a.v.size()); + } + + /** + * Value types which have been promoted can be re-assigned and the internal reference will remain valid. + */ + function test_assigning_promoted_variable() { + var v = new StdVector(5); + final f = () -> { + v.resize(10); + } + + f(); + + v = new StdVector(2); + + Assert.equals(2, v.size()); + } + + function test_lamba_returns() { + final v1 = new StdVector(100); + final f = () -> { + return v1; + } + + final v2 = f(); + + v2.resize(50); + + Assert.equals( 50, v2.size()); + Assert.equals(100, v1.size()); + } + + function test_iterator() { + final iter = new StdVectorIterator(); + + var count = 0; + for (vec in iter) { + Assert.equals(count++, vec.size()); + } + } + + function test_to_string() { + final v = new StdVector(); + final s = Std.string(v); + + Assert.notNull(s); + } + + function test_equality() { + final v1 = new StdVector(); + final v2 = new StdVector(); + final eq = v1 == v2; + + Assert.isTrue(eq); + } + + function test_inequality() { + final v1 = new StdVector(); + final v2 = new StdVector(); + final eq = v1 != v2; + + Assert.isFalse(eq); + } + + function test_just_creation() { + new StdVector(10); + + Assert.pass(); + } + + /** + * Array reading is allowed on value types implementing ArrayAccess. + */ + // function test_array_access() { + // final v = new StdVector(5); + + // // v[1] = 7; + + // final i = v[1]; + + // Assert.equals(0, i); + // } + + // Various helper functions + + function by_value_dynamic(v:Dynamic) { + Assert.equals(5, (v:StdVector).size()); + + (v:StdVector).resize(10); + + Assert.equals(10, (v:StdVector).size()); + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestValueTypeCollections.hx b/test/marshalling/src/classes/TestValueTypeCollections.hx new file mode 100644 index 000000000..cced66c8a --- /dev/null +++ b/test/marshalling/src/classes/TestValueTypeCollections.hx @@ -0,0 +1,64 @@ +package classes; + +import utest.Assert; +import utest.Test; + +class TestValueTypeCollections extends Test { + public function test_push_copy_to_array() { + final a = []; + + // prevent haxe optimising the array away + a.resize(10); + a.resize(0); + + a.push(new StdVector()); + + Assert.equals(0, a[0].size()); + } + + public function test_mutate_array_element() { + final a = [ new StdVector() ]; + final s = 100; + + // prevent haxe optimising the array away + a.resize(10); + a.resize(1); + + a[0].resize(s); + + Assert.equals(s, a[0].size()); + } + + public function test_copy_array_element() { + final a = [ new StdVector() ]; + final s = 100; + final c = a[0]; + + c.resize(s); + + // prevent haxe optimising the array away + a.resize(10); + a.resize(1); + + Assert.equals(0, a[0].size()); + Assert.equals(s, c.size()); + } + + public function test_switch_on_array() { + final a = [ new StdVector() ]; + final s = 100; + + // prevent haxe optimising the array away + a.resize(10); + a.resize(1); + + switch a { + case [ elem ]: + elem.resize(s); + + Assert.equals(s, a[0].size()); + default: + Assert.fail('expected array to have one element'); + } + } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestValueTypeFields.hx b/test/marshalling/src/classes/TestValueTypeFields.hx new file mode 100644 index 000000000..29a213b0d --- /dev/null +++ b/test/marshalling/src/classes/TestValueTypeFields.hx @@ -0,0 +1,147 @@ +package classes; + +import utest.Assert; +import utest.Test; + +@:semantics(reference) +@:include('point.hpp') +@:cpp.ValueType({ type : 'point', namespace : [ 'hx', 'maths' ] }) +private extern class Point { + var x : Float; + var y : Float; + + @:overload(function(_x : Float, _y : Float) : Void {}) + function new(); +} + +@:semantics(reference) +@:include('holder.hpp') +@:cpp.ValueType({ type : 'holder', namespace : [] }) +private extern class Holder { + var p1 : Point; + var p2 : Point; + var pPtr : Point; + + @:overload(function(_p1 : Point, _p2 : Point) : Void {}) + function new(); + + function create() : Point; + + function get_static() : Point; +} + +class TestValueTypeFields extends Test { + function test_struct_with_default_construction() { + final v = new Point(); + Assert.equals(7f64, v.x); + Assert.equals(26f64, v.y); + } + + function test_promoted_struct_with_default_construction() { + final v = new Point(); + final f = () -> { + return v.x; + } + + f(); + + Assert.equals(7f64, v.x); + Assert.equals(26f64, v.y); + } + + function test_accessing_inner_value_types() { + final v = new Holder(); + Assert.equals(7f64, v.p1.x); + Assert.equals(26f64, v.p1.y); + } + + function test_accessing_inner_value_types_promoted() { + final v = new Holder(); + final f = () -> { + return v.p1.x; + } + + f(); + + Assert.equals(7f64, v.p1.x); + Assert.equals(26f64, v.p1.y); + } + + function test_copying_struct_inner_type() { + final v = new Holder(); + final p = v.p1; + + p.x = 33f64; + + Assert.equals(7f64, v.p1.x); + Assert.equals(33f64, p.x); + } + + function test_copying_struct_inner_type_promoted() { + final v = new Holder(); + final p = v.p1; + final f = () -> { + p.x = 33f64; + } + + f(); + + Assert.equals(7f64, v.p1.x); + Assert.equals(33f64, p.x); + } + + function test_assigning_struct_inner_type() { + final p = new Point(33, 66); + final v = new Holder(); + + v.p1 = p; + + Assert.equals(33f64, v.p1.x); + Assert.equals(66f64, v.p1.y); + } + + function test_assigning_struct_inner_promoted() { + final p = new Point(); + final v = new Holder(); + final f = () -> { + p.x = 33; + p.y = 66; + } + + f(); + + v.p1 = p; + + Assert.equals(33f64, v.p1.x); + Assert.equals(66f64, v.p1.y); + } + + function test_extern_function_returning_value() { + final h = new Holder(); + final p = h.create(); + + Assert.equals(h.p1.x + h.p2.x, p.x); + Assert.equals(h.p1.y + h.p2.y, p.y); + } + + // function test_extern_function_returning_pointer() { + // final h = new Holder(); + // final p1 = h.get_static(); + + // Assert.equals( 7f64, p1.x); + // Assert.equals(26f64, p1.y); + + // final p2 = h.get_static(); + + // Assert.equals( 7f64, p2.x); + // Assert.equals(26f64, p2.y); + + // h.get_static().x = 33; + // h.get_static().y = 66; + + // final p3 = h.get_static(); + + // Assert.equals(33f64, p3.x); + // Assert.equals(66f64, p3.y); + // } +} \ No newline at end of file diff --git a/test/marshalling/src/classes/TestValueTypeInterop.hx b/test/marshalling/src/classes/TestValueTypeInterop.hx new file mode 100644 index 000000000..3838f3905 --- /dev/null +++ b/test/marshalling/src/classes/TestValueTypeInterop.hx @@ -0,0 +1,219 @@ +package classes; + +import cpp.Native; +import cpp.Star; +import cpp.Pointer; +import cpp.Reference; +import cpp.RawPointer; +import utest.Assert; +import utest.Test; + +private extern class NativeFunctions { + @:native('vec_by_val') + static function vec_by_val(v:StdVector):Void; + + @:native('vec_by_ref') + static function vec_by_ref(v:StdVector):Void; + + @:native('vec_by_ptr') + static function vec_by_ptr(v:StdVector):Void; +} + +private class HaxeFunctions { + @:unreflective @:generic public static function get_size_doubled(v : StdVector) { + return v.size() * 2; + } + + @:unreflective @:generic public static function resize_vec_by_ref(v : Reference>, size : Int) { + v.resize(size); + } + + @:unreflective @:generic public static function resize_vec_by_ptr(v : Pointer>, size : Int) { + v[0].resize(size); + } + + @:unreflective @:generic public static function resize_vec_by_raw_ptr(v : RawPointer>, size : Int) { + v[0].resize(size); + } + + @:unreflective @:generic public static function resize_vec_by_star(v : Star>, size : Int) { + v.resize(size); + } +} + +@:cppNamespaceCode(' +void vec_by_val(std::vector v) +{ + v.resize(v.size() * 2); +} + +void vec_by_ref(std::vector& v) +{ + v.resize(v.size() * 2); +} + +void vec_by_ptr(std::vector* v) +{ + v->resize(v->size() * 2); +} + +int* create_int() { + return new int { 7 }; +} + +void int_ptr_ptr(int** ptr) { + *ptr = new int { 14 }; +} +') +class TestValueTypeInterop extends Test { + function test_pass_straight_in() { + Assert.equals(10, HaxeFunctions.get_size_doubled(new StdVector(5))); + } + + /** + * Extern functions which expect a type will be given a copy of the value type. + */ + function test_extern_by_val() { + final v = new StdVector(5); + + NativeFunctions.vec_by_val(v); + + Assert.equals(5, v.size()); + } + + /** + * Extern functions which expect a reference to a type will be given a reference to the value type. + */ + function test_extern_by_ref() { + final v = new StdVector(5); + + NativeFunctions.vec_by_ref(v); + + Assert.equals(10, v.size()); + } + + /** + * Extern functions which expect a pointer to a type will be given a pointer to the value type. + */ + function test_extern_by_ptr() { + final v = new StdVector(5); + + NativeFunctions.vec_by_ptr(v); + + Assert.equals(10, v.size()); + } + + /** + * Extern functions which expect a type will be given a copy of the promoted value type. + */ + function test_promoted_extern_by_val() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + NativeFunctions.vec_by_val(v); + + Assert.equals(5, v.size()); + } + + /** + * Extern functions which expect a reference to a type will be given a reference to the promoted value type. + */ + function test_promoted_extern_by_ref() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + NativeFunctions.vec_by_ref(v); + + Assert.equals(10, v.size()); + } + + /** + * Extern functions which expect a pointer to a type will be given a pointer to the promoted value type. + */ + function test_promoted_extern_by_ptr() { + final v = new StdVector(); + final f = () -> { + v.resize(5); + } + + f(); + + NativeFunctions.vec_by_ptr(v); + + Assert.equals(10, v.size()); + } + + function test_resize_vec_by_ref() { + final v = new StdVector(); + final size = 100; + + HaxeFunctions.resize_vec_by_ref(v, size); + + Assert.equals(size, v.size()); + } + + function test_resize_vec_by_ptr() { + final v = new StdVector(); + final size = 100; + + HaxeFunctions.resize_vec_by_ptr(Pointer.addressOf(v), size); + + Assert.equals(size, v.size()); + } + + function test_resize_vec_by_raw_ptr() { + final v = new StdVector(); + final size = 100; + + HaxeFunctions.resize_vec_by_raw_ptr(Pointer.addressOf(v).raw, size); + + Assert.equals(size, v.size()); + } + + function test_resize_vec_by_star() { + final v = new StdVector(); + final size = 100; + + HaxeFunctions.resize_vec_by_star(Pointer.addressOf(v).ptr, size); + + Assert.equals(size, v.size()); + } + + function test_copying_from_pointer() { + final src = new StdVector(10); + final ptr = Pointer.addressOf(src); + final copy = ptr.value; + + copy.resize(100); + + Assert.equals( 10, src.size()); + Assert.equals(100, copy.size()); + } + + function test_native_star() { + final v = new StdVector(); + final ptr = Native.addressOf(v); + + ptr.resize(10); + + Assert.equals(10, v.size()); + } + + function test_native_dereference() { + final v = new StdVector(); + final ptr = Pointer.addressOf(v); + final ref = Native.star(ptr.ptr); + + ref.resize(10); + + Assert.equals(10, v.size()); + } +} \ No newline at end of file diff --git a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx b/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx new file mode 100644 index 000000000..568736e74 --- /dev/null +++ b/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx @@ -0,0 +1,101 @@ +package enums; + +import utest.Assert; +import utest.Test; + +@:semantics(reference) +@:cpp.ValueType({ type : 'colour', namespace : [] }) +private extern enum abstract Colour(Int) { + @:native('red') + var Red; + + @:native('green') + var Green; + + @:native('blue') + var Blue; +} + +@:cppFileCode(' +enum colour { + red, + green, + blue +}; +') +class TestValueTypeEnumAbstract extends Test { + function test_switching_on_uncaptured_enum() { + final e = Colour.Green; + + switch e { + case Green: + Assert.pass(); + default: + Assert.fail('Expected "green"'); + } + } + + function test_switching_on_captured_enum() { + final e = Colour.Green; + final f = () -> { + return e; + } + + f(); + + switch e { + case Red, Blue: + Assert.fail('Expected "green"'); + case Green: + Assert.pass(); + } + } + + function test_uncaptured_equals() { + final e = Colour.Green; + + Assert.isTrue(e == Colour.Green); + } + + function test_uncaptured_not_equals() { + final e = Colour.Green; + + Assert.isFalse(e != Colour.Green); + } + + function test_promoted_equals() { + final e = Colour.Green; + final f = () -> { + return e; + } + + f(); + + Assert.isTrue(e == Colour.Green); + } + + function test_promoted_not_equals() { + final e = Colour.Green; + final f = () -> { + return e; + } + + f(); + + Assert.isFalse(e != Colour.Green); + } + + function test_from_underlying_type() { + final i = 1; + final e : Colour = cast i; + + Assert.isTrue(e == Colour.Green); + } + + function test_to_underlying_type() { + final e = Colour.Green; + final i : Int = cast e; + + Assert.equals(1, i); + } +} \ No newline at end of file diff --git a/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx b/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx new file mode 100644 index 000000000..86ea0fc20 --- /dev/null +++ b/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx @@ -0,0 +1,99 @@ +package enums; + +import utest.Assert; +import utest.Test; + +@:semantics(reference) +@:cpp.ValueType({ namespace : [ 'foo' ] }) +private extern enum abstract Numbers(Int) { + var One; + var Two; + var Three; +} + +@:cppFileCode(' +namespace foo +{ + enum class Numbers : char { + One, + Two = 5, + Three + }; +} +') +class TestValueTypeEnumClassAbstract extends Test { + function test_switching_on_uncaptured_enum() { + final e = Numbers.Two; + + switch e { + case Two: + Assert.pass(); + default: + Assert.fail('Expected "Two"'); + } + } + + function test_switching_on_captured_enum() { + final e = Numbers.Two; + final f = () -> { + return e; + } + + f(); + + switch e { + case One, Three: + Assert.fail('Expected "green"'); + case Two: + Assert.pass(); + } + } + + function test_uncaptured_equals() { + final e = Numbers.Two; + + Assert.isTrue(e == Numbers.Two); + } + + function test_uncaptured_not_equals() { + final e = Numbers.Two; + + Assert.isFalse(e != Numbers.Two); + } + + function test_promoted_equals() { + final e = Numbers.Two; + final f = () -> { + return e; + } + + f(); + + Assert.isTrue(e == Numbers.Two); + } + + function test_promoted_not_equals() { + final e = Numbers.Two; + final f = () -> { + return e; + } + + f(); + + Assert.isFalse(e != Numbers.Two); + } + + function test_from_underlying_type() { + final i = 5; + final e : Numbers = cast i; + + Assert.isTrue(e == Numbers.Two); + } + + function test_to_underlying_type() { + final e = Numbers.Two; + final i : Int = cast e; + + Assert.equals(5, i); + } +} \ No newline at end of file diff --git a/test/marshalling/src/native/Base.cpp b/test/marshalling/src/native/Base.cpp new file mode 100644 index 000000000..a964a889d --- /dev/null +++ b/test/marshalling/src/native/Base.cpp @@ -0,0 +1,7 @@ +#include +#include + +int Base::foo() +{ + return 7; +} \ No newline at end of file diff --git a/test/marshalling/src/native/Base.hpp b/test/marshalling/src/native/Base.hpp new file mode 100644 index 000000000..6aaa091dc --- /dev/null +++ b/test/marshalling/src/native/Base.hpp @@ -0,0 +1,5 @@ +#pragma once + +struct Base { + virtual int foo(); +}; \ No newline at end of file diff --git a/test/marshalling/src/native/Child.cpp b/test/marshalling/src/native/Child.cpp new file mode 100644 index 000000000..4b947ecb6 --- /dev/null +++ b/test/marshalling/src/native/Child.cpp @@ -0,0 +1,12 @@ +#include +#include + +int Child::foo() +{ + return 10; +} + +int Child::bar() +{ + return 20; +} \ No newline at end of file diff --git a/test/marshalling/src/native/Child.hpp b/test/marshalling/src/native/Child.hpp new file mode 100644 index 000000000..8142518b3 --- /dev/null +++ b/test/marshalling/src/native/Child.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +struct Child : public Base { + int foo() override; + int bar(); +}; \ No newline at end of file diff --git a/test/marshalling/src/native/ctx.cpp b/test/marshalling/src/native/ctx.cpp new file mode 100644 index 000000000..aa198e761 --- /dev/null +++ b/test/marshalling/src/native/ctx.cpp @@ -0,0 +1,15 @@ +#include + +ctx::ctx() : number(7) {} + +int ctx::Double() { + return number * 2; +} + +ctx* create() { + return new ctx(); +} + +ctx* create_null() { + return nullptr; +} \ No newline at end of file diff --git a/test/marshalling/src/native/ctx.hpp b/test/marshalling/src/native/ctx.hpp new file mode 100644 index 000000000..83c2d5c1c --- /dev/null +++ b/test/marshalling/src/native/ctx.hpp @@ -0,0 +1,12 @@ +#pragma once + +struct ctx { + int number; + + ctx(); + + int Double(); +}; + +ctx* create(); +ctx* create_null(); \ No newline at end of file diff --git a/test/marshalling/src/native/holder.cpp b/test/marshalling/src/native/holder.cpp new file mode 100644 index 000000000..9b4fdef6b --- /dev/null +++ b/test/marshalling/src/native/holder.cpp @@ -0,0 +1,15 @@ +#include +#include + +::hx::maths::point holder::p_static; + +holder::holder(const ::hx::maths::point& _p1, const ::hx::maths::point& _p2) : p1(_p1), p2(_p2), pPtr(new ::hx::maths::point(45, 67)) {} + +::hx::maths::point holder::create() +{ + return ::hx::maths::point(p1.x + p2.x, p1.y + p2.y); +} + +::hx::maths::point* holder::get_static() { + return &p_static; +} \ No newline at end of file diff --git a/test/marshalling/src/native/holder.hpp b/test/marshalling/src/native/holder.hpp new file mode 100644 index 000000000..60123b757 --- /dev/null +++ b/test/marshalling/src/native/holder.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +class holder { + static ::hx::maths::point p_static; + +public: + ::hx::maths::point p1; + ::hx::maths::point p2; + + ::hx::maths::point* pPtr; + + holder() = default; + holder(const ::hx::maths::point& _p1, const ::hx::maths::point& _p2); + + ::hx::maths::point create(); + ::hx::maths::point* get_static(); +}; \ No newline at end of file diff --git a/test/marshalling/src/native/point.cpp b/test/marshalling/src/native/point.cpp new file mode 100644 index 000000000..702186786 --- /dev/null +++ b/test/marshalling/src/native/point.cpp @@ -0,0 +1,4 @@ +#include +#include + +hx::maths::point::point(double _x, double _y) : x(_x), y(_y) {} \ No newline at end of file diff --git a/test/marshalling/src/native/point.hpp b/test/marshalling/src/native/point.hpp new file mode 100644 index 000000000..f7d0e5c82 --- /dev/null +++ b/test/marshalling/src/native/point.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace hx { + namespace maths { + struct point { + double x = 7; + double y = 26; + + point() = default; + point(double _x, double _y); + }; + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestClassPointers.hx b/test/marshalling/src/pointers/TestClassPointers.hx new file mode 100644 index 000000000..7991d3249 --- /dev/null +++ b/test/marshalling/src/pointers/TestClassPointers.hx @@ -0,0 +1,200 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +class Foo { + public static var ptr_static = Context.create(); + + public var v : Context; + + public function new() { + v = Context.create(); + } + + public function get() { + return v; + } + + public function mutate(size : Int) { + return v.number = size; + } + + public dynamic function pass_through(ctx : Context) { + return ctx; + } +} + +class WithConstruction { + public final v : Context; + + public function new(v) { + this.v = v; + } +} + +class TestClassPointers extends Test { + + // Member Variables + + function test_class_field_access() { + final f = new Foo(); + + Assert.equals(7, f.v.number); + } + + function test_mutating_class_field() { + final f = new Foo(); + + f.v.number = 20; + + Assert.equals(20, f.v.number); + } + + function test_class_field_copy() { + final f = new Foo(); + final p = f.v; + + p.number = 20; + + Assert.equals(20, f.v.number); + Assert.equals(20, p.number); + } + + function test_class_field_assignment() { + final f = new Foo(); + final p = Context.create(); + + p.number = 20; + + f.v = p; + + Assert.isTrue(p == f.v); + Assert.equals(20, f.v.number); + } + + function test_class_reflect_variable() { + final f = new Foo(); + final n = (Reflect.field(f, 'v') : Context).number; + + Assert.equals(7, n); + } + + function test_class_reflect_variable_mutation() { + final f = new Foo(); + + (Reflect.field(f, 'v') : Context).number = 20; + + Assert.equals(20, f.v.number); + } + + function test_class_reflect_variable_assignment() { + final f = new Foo(); + final p = Context.create(); + + p.number = 20; + + Reflect.setField(f, 'v', p); + + Assert.isTrue(p == f.v); + Assert.equals(20, f.v.number); + } + + // Static Variables + + function test_static_variable_mutation() { + Foo.ptr_static.number = 20; + + Assert.equals(20, Foo.ptr_static.number); + } + + function test_static_variable_assignment() { + final ptr = Context.create(); + final old = Foo.ptr_static; + + Foo.ptr_static = ptr; + + Assert.isTrue(Foo.ptr_static == ptr); + Assert.isTrue(Foo.ptr_static != old); + } + + function test_static_variable_copy() { + final c = Foo.ptr_static; + + c.number = 75; + + Assert.equals(75, c.number); + Assert.equals(75, Foo.ptr_static.number); + } + + function test_static_class_reflect_variable() { + Foo.ptr_static.number = 11; + + final s = (Reflect.field(Foo, 'ptr_static') : Context).number; + + Assert.equals(11, s); + } + + function test_static_class_reflect_variable_mutation() { + (Reflect.field(Foo, 'ptr_static') : Context).number = 12; + + Assert.equals(12, Foo.ptr_static.number); + } + + function test_static_class_reflect_variable_assignment() { + final ptr = Context.create(); + final old = Foo.ptr_static; + + Reflect.setField(Foo, 'ptr_static', ptr); + + Assert.isTrue(Foo.ptr_static == ptr); + Assert.isTrue(Foo.ptr_static != old); + } + + // Member Functions + + function test_class_function_call() { + final f = new Foo(); + + Assert.equals(14, f.v.double()); + } + + function test_class_function_pass() { + final f = new Foo(); + final s = f.mutate(20); + + Assert.equals(20, f.v.number); + } + + function test_member_dynamic_function() { + final f = new Foo(); + final p = Context.create(); + final v = f.pass_through(p); + + Assert.isTrue(p == v); + } + + // Construction + + function test_constructor() { + final v = Context.create(); + final o = new WithConstruction(v); + + o.v.number = 20; + + Assert.equals(20, o.v.number); + Assert.equals(20, v.number); + } + + function test_reflection_create_empty() { + final f : WithConstruction = Type.createEmptyInstance(WithConstruction); + + Assert.isTrue(f.v == null); + } + + function test_reflection_create() { + final f : WithConstruction = Type.createInstance(WithConstruction, [ Context.create() ]); + + Assert.equals(7, f.v.number); + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestEnumPointers.hx b/test/marshalling/src/pointers/TestEnumPointers.hx new file mode 100644 index 000000000..ebf06cca1 --- /dev/null +++ b/test/marshalling/src/pointers/TestEnumPointers.hx @@ -0,0 +1,78 @@ +package pointers; + +import haxe.EnumTools; +import utest.Assert; +import utest.Test; + +enum FooEnum { + Bar(c:Context); +} + +class TestEnumPointers extends Test { + function test_into_enum() { + final c = Context.create(); + final e = FooEnum.Bar(c); + + c.number = 20; + + switch e { + case Bar(v): + + Assert.equals(20, c.number); + Assert.equals(20, v.number); + } + } + + function test_mutating_enum() { + final c = Context.create(); + final e = FooEnum.Bar(c); + + switch e { + case Bar(v1): + v1.number = 20; + + Assert.equals(20, v1.number); + Assert.equals(20, c.number); + + switch e { + case Bar(v2): + Assert.equals(20, v2.number); + } + } + } + + function test_copy_from_enum() { + final e = FooEnum.Bar(Context.create()); + + switch e { + case Bar(v): + final v_copy = v; + + v_copy.number = 20; + + Assert.equals(20, v_copy.number); + Assert.equals(20, v.number); + } + } + + function test_create_by_index() { + final c = Context.create(); + final e = EnumTools.createByIndex(FooEnum, 0, [ c ]); + + switch e { + case Bar(v): + Assert.equals(7, v.number); + } + } + + function test_create_by_name() { + final c = Context.create(); + final e = EnumTools.createByName(FooEnum, 'Bar', [ c ]); + + switch e { + case Bar(v): + + Assert.equals(7, v.number); + } + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestInheritancePointers.hx b/test/marshalling/src/pointers/TestInheritancePointers.hx new file mode 100644 index 000000000..876dcaa9c --- /dev/null +++ b/test/marshalling/src/pointers/TestInheritancePointers.hx @@ -0,0 +1,90 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +@:semantics(reference) +@:include('Base.hpp') +@:cpp.PointerType +private extern class Base { + function foo():Int; +} + +@:semantics(reference) +@:include('Child.hpp') +@:cpp.PointerType +private extern class Child extends Base { + function new():Void; + + function bar():Int; +} + +class TestInheritancePointers extends Test { + function test_assigning_to_a_more_specific_type() { + final o = create_child(); + final c : Child = cast o; + + Assert.equals(10, c.foo()); + Assert.equals(20, c.bar()); + } + + function test_assigning_to_a_more_specific_promoted() { + final o = create_child(); + final c : Child = cast o; + final f = () -> { + return c.bar(); + } + + f(); + + Assert.equals(10, c.foo()); + Assert.equals(20, c.bar()); + } + + function test_casting_var_to_base() { + final o = create_child(); + final v = (cast o : Child).bar(); + + Assert.equals(20, v); + } + + function test_passing_child_to_child_function() { + final o = create_child(); + final v = pass_child(cast o); + + Assert.equals(10, v); + } + + function test_passing_child_to_base_function() { + final o = create_child(); + final v = pass_base(o); + + Assert.equals(10, v); + } + + function test_reassigning() { + var o : Base = create_child(); + + Assert.equals(10, o.foo()); + + o = create_child_as_child(); + + Assert.equals(10, o.foo()); + } + + function create_child() : Base { + return untyped __cpp__('new Child()'); + } + + function create_child_as_child() : Child { + return untyped __cpp__('new Child()'); + } + + function pass_child(c : Child) { + return c.foo(); + } + + function pass_base(b : Base) { + return b.foo(); + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestInterfacePointers.hx b/test/marshalling/src/pointers/TestInterfacePointers.hx new file mode 100644 index 000000000..16ecc6154 --- /dev/null +++ b/test/marshalling/src/pointers/TestInterfacePointers.hx @@ -0,0 +1,104 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +interface IBar { + var c : Context; + + function get() : Context; + + function assign(c : Context) : Void; +} + +class Bar implements IBar { + public var c : Context; + + public function new() { + c = Context.create(); + } + + public function assign(c:Context) { + c.number = 20; + } + + public function get():Context { + return c; + } +} + +class TestInterfacePointers extends Test { + function test_interface_field_access() { + final f : IBar = new Bar(); + + Assert.equals(7, f.c.number); + } + + function test_mutating_interface_field() { + final f : IBar = new Bar(); + + f.c.number = 20; + + Assert.equals(20, f.c.number); + } + + function test_interface_field_copy() { + final f : IBar = new Bar(); + final c = f.c; + + c.number = 20; + + Assert.isTrue(c == f.c); + Assert.equals(20, c.number); + Assert.equals(20, f.c.number); + } + + function test_interface_field_assignment() { + final f : IBar = new Bar(); + final old = f.c; + + f.c = Context.create(); + + Assert.isTrue(old != f.c); + } + + function test_interface_function_return() { + final f : IBar = new Bar(); + final c = f.get(); + + Assert.isTrue(f.c == c); + } + + function test_interface_function_call() { + final f : IBar = new Bar(); + final c = Context.create(); + + f.assign(c); + + Assert.equals(20, c.number); + } + + function test_interface_reflect_variable() { + final f : IBar = new Bar(); + final s = (Reflect.field(f, 'c') : Context).number; + + Assert.equals(7, s); + } + + function test_interface_reflect_variable_mutation() { + final f : IBar = new Bar(); + + (Reflect.field(f, 'c') : Context).number = 20; + + Assert.equals(20, f.c.number); + } + + function test_interface_reflect_variable_assignment() { + final f : IBar = new Bar(); + final old = f.c; + + Reflect.setField(f, 'c', Context.create()); + + Assert.isTrue(old != f.c); + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestLocalPointers.hx b/test/marshalling/src/pointers/TestLocalPointers.hx new file mode 100644 index 000000000..d5a178fa9 --- /dev/null +++ b/test/marshalling/src/pointers/TestLocalPointers.hx @@ -0,0 +1,225 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +class TestLocalPointers extends Test { + function test_null_ptr() { + final ptr : Context = null; + + Assert.isTrue(ptr == null); + } + + function test_null_captured_ptr() { + final ptr : Context = null; + final f = () -> { + return ptr; + } + + f(); + + Assert.isTrue(ptr == null); + } + + function test_non_null_ptr() { + final ptr = Context.create(); + + Assert.isTrue(ptr != null); + } + + function test_non_null_captured_ptr() { + final ptr = Context.create(); + final f = () -> { + return ptr; + } + + f(); + + Assert.isTrue(ptr != null); + } + + function test_assinging_ptr() { + var ptr : Context = null; + + Assert.isTrue(ptr == null); + + ptr = Context.create(); + + Assert.isTrue(ptr != null); + } + + function test_assinging_captured_ptr() { + var ptr : Context = null; + final f = () -> { + return ptr; + } + + f(); + + Assert.isTrue(ptr == null); + + ptr = Context.create(); + + Assert.isTrue(ptr != null); + } + + function test_assinging_captured_ptr_in_closure() { + var ptr : Context = null; + final f = () -> { + ptr = Context.create(); + } + + f(); + + Assert.isTrue(ptr != null); + } + + function test_pointer_equality() { + final ptr = Context.create(); + final copy = ptr; + + Assert.isTrue(ptr == copy); + } + + function test_captured_pointer_equality() { + final ptr = Context.create(); + final f = () -> { + return ptr; + } + final copy = f(); + + Assert.isTrue(ptr == copy); + } + + function test_captured_pointer_inequality() { + final ptr = Context.create(); + final f = () -> { + return Context.create(); + } + final copy = f(); + + Assert.isTrue(ptr != copy); + } + + function test_pointer_field_access() { + final ptr = Context.create(); + + Assert.equals(7, ptr.number); + } + + function test_captured_pointer_field_access() { + final ptr = Context.create(); + final f = () -> { + return ptr.number; + } + + Assert.equals(7, f()); + } + + function test_pointer_field_mutation() { + final ptr = Context.create(); + + ptr.number = 14; + + Assert.equals(14, ptr.number); + } + + function test_capturd_pointer_field_mutation() { + final ptr = Context.create(); + final f = () -> { + ptr.number = 14; + } + + f(); + + Assert.equals(14, ptr.number); + } + + function test_pointer_function_call() { + final ptr = Context.create(); + + Assert.equals(14, ptr.double()); + } + + function test_captured_pointer_function_call() { + final ptr = Context.create(); + final f = () -> { + return ptr.double(); + } + + Assert.equals(14, f()); + } + + function test_dynamic() { + final ptr = Context.create(); + + by_dynamic(ptr); + + Assert.equals(20, ptr.number); + } + + function test_promoted_dynamic() { + var ptr = null; + + final f = () -> { + ptr = Context.create(); + } + + f(); + + by_dynamic(ptr); + + Assert.equals(20, ptr.number); + } + + function test_anon() { + final ptr = Context.create(); + + by_anon({ v : ptr }); + + Assert.equals(20, ptr.number); + } + + function test_lambda_return() { + final f = () -> { + return Context.create(); + } + + final ptr = f(); + + Assert.notNull(ptr); + } + + function test_to_string() { + final ptr = Context.create(); + final str = Std.string(ptr); + + Assert.notNull(str); + } + + function test_just_creation() { + Context.create(); + + Assert.pass(); + } + + function test_reassignment() { + var ptr = Context.create(); + + ptr.number = 20; + + ptr = Context.create(); + + Assert.equals(7, ptr.number); + } + + // + + function by_anon(a : { v : Context }) { + a.v.number = 20; + } + + function by_dynamic(v:Dynamic) { + (v:Context).number = 20; + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestPointerFields.hx b/test/marshalling/src/pointers/TestPointerFields.hx new file mode 100644 index 000000000..419070b9c --- /dev/null +++ b/test/marshalling/src/pointers/TestPointerFields.hx @@ -0,0 +1,47 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +@:semantics(reference) +@:include('point.hpp') +@:cpp.PointerType({ type : 'point', namespace : [ 'hx', 'maths' ] }) +private extern class Point { + var x : Float; + var y : Float; +} + +@:semantics(reference) +@:include('holder.hpp') +@:cpp.ValueType({ type : 'holder', namespace : [] }) +private extern class Holder { + var pPtr : Point; +} + +class TestPointerFields extends Test { + + function test_field_access() { + final h = create_holder(); + + if (Assert.isTrue(h.pPtr != null)) { + Assert.equals(45f64, h.pPtr.x); + Assert.equals(67f64, h.pPtr.y); + } + } + + function test_field_null_access() { + final h = create_holder_with_null(); + + if (Assert.isTrue(h.pPtr == null)) { + Assert.exception(() -> h.pPtr.x = 7); + } + } + + function create_holder() : Holder { + return untyped __cpp__('::holder(::hx::maths::point(), ::hx::maths::point())'); + } + + function create_holder_with_null() : Holder { + return untyped __cpp__('::holder()'); + } +} \ No newline at end of file From 0978d5b575e1e28feedd3c78c55d6d9afbc149c9 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 19 Jan 2025 21:48:33 +0000 Subject: [PATCH 26/89] Add pointer collection tests --- .../src/pointers/TestPointerCollections.hx | 62 +++++++++++++++++++ .../src/pointers/TestPointerFields.hx | 40 ++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 test/marshalling/src/pointers/TestPointerCollections.hx diff --git a/test/marshalling/src/pointers/TestPointerCollections.hx b/test/marshalling/src/pointers/TestPointerCollections.hx new file mode 100644 index 000000000..edfe60632 --- /dev/null +++ b/test/marshalling/src/pointers/TestPointerCollections.hx @@ -0,0 +1,62 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +class TestPointerCollections extends Test { + function test_pushing_to_array() { + final a = []; + + a.push(Context.create()); + + Assert.equals(7, a[0].number); + } + + function test_mutate_element() { + final c = Context.create(); + final a = [ c ]; + + a[0].number = 20; + + Assert.equals(20, c.number); + Assert.equals(20, a[0].number); + } + + function test_null_default() { + final a = new Array(); + + a.resize(1); + + Assert.isTrue(a[0] == null); + } + + function test_setting_array_element() { + final c = Context.create(); + final a = [ null ]; + + a[0] = c; + + if (Assert.isTrue(a[0] != null)) { + Assert.equals(7, a[0].number); + } + } + + function test_switch_on_array() { + final c = Context.create(); + final a = [ c ]; + + // prevent haxe optimising the array away + a.resize(10); + a.resize(1); + + switch a { + case [ elem ]: + elem.number = 20; + + Assert.equals(20, c.number); + Assert.equals(20, a[0].number); + default: + Assert.fail('expected array to have one element'); + } + } +} \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestPointerFields.hx b/test/marshalling/src/pointers/TestPointerFields.hx index 419070b9c..e1dde6188 100644 --- a/test/marshalling/src/pointers/TestPointerFields.hx +++ b/test/marshalling/src/pointers/TestPointerFields.hx @@ -37,6 +37,42 @@ class TestPointerFields extends Test { } } + function test_copying_to_var() { + final h = create_holder(); + final p = h.pPtr; + + p.x = 100; + p.y = 200; + + Assert.equals(100f64, h.pPtr.x); + Assert.equals(200f64, h.pPtr.y); + } + + function test_assignment() { + final h = create_holder(); + final p = create_point(); + + h.pPtr = p; + + Assert.equals(100f64, h.pPtr.x); + Assert.equals(200f64, h.pPtr.y); + } + + function test_assignment_from_promoted() { + final h = create_holder(); + final p = create_point(); + final f = () -> { + return p.x; + } + + f(); + + h.pPtr = p; + + Assert.equals(100f64, h.pPtr.x); + Assert.equals(200f64, h.pPtr.y); + } + function create_holder() : Holder { return untyped __cpp__('::holder(::hx::maths::point(), ::hx::maths::point())'); } @@ -44,4 +80,8 @@ class TestPointerFields extends Test { function create_holder_with_null() : Holder { return untyped __cpp__('::holder()'); } + + function create_point() : Point { + return untyped __cpp__('new ::hx::maths::point(100, 200)'); + } } \ No newline at end of file From d2a9bcf9eae12343a3114d64125be3575e96d4b7 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 20 Jan 2025 19:38:38 +0000 Subject: [PATCH 27/89] Move enums into header files --- test/marshalling/src/Main.hx | 3 ++- .../src/enums/TestValueTypeEnumAbstract.hx | 9 ++------- .../src/enums/TestValueTypeEnumClassAbstract.hx | 12 ++---------- test/marshalling/src/native/Numbers.hpp | 10 ++++++++++ test/marshalling/src/native/colour.hpp | 7 +++++++ 5 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 test/marshalling/src/native/Numbers.hpp create mode 100644 test/marshalling/src/native/colour.hpp diff --git a/test/marshalling/src/Main.hx b/test/marshalling/src/Main.hx index f0bfb2527..1159a590a 100644 --- a/test/marshalling/src/Main.hx +++ b/test/marshalling/src/Main.hx @@ -18,7 +18,8 @@ class Main { new pointers.TestInterfacePointers(), new pointers.TestInheritancePointers(), new pointers.TestEnumPointers(), - new pointers.TestPointerFields() + new pointers.TestPointerFields(), + new pointers.TestPointerCollections() ]); } } \ No newline at end of file diff --git a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx b/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx index 568736e74..9819b58bb 100644 --- a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx +++ b/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx @@ -4,6 +4,7 @@ import utest.Assert; import utest.Test; @:semantics(reference) +@:include('colour.hpp') @:cpp.ValueType({ type : 'colour', namespace : [] }) private extern enum abstract Colour(Int) { @:native('red') @@ -16,13 +17,7 @@ private extern enum abstract Colour(Int) { var Blue; } -@:cppFileCode(' -enum colour { - red, - green, - blue -}; -') +@:headerInclude('colour.hpp') class TestValueTypeEnumAbstract extends Test { function test_switching_on_uncaptured_enum() { final e = Colour.Green; diff --git a/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx b/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx index 86ea0fc20..74336fdaf 100644 --- a/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx +++ b/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx @@ -4,6 +4,7 @@ import utest.Assert; import utest.Test; @:semantics(reference) +@:include('Numbers.hpp') @:cpp.ValueType({ namespace : [ 'foo' ] }) private extern enum abstract Numbers(Int) { var One; @@ -11,16 +12,7 @@ private extern enum abstract Numbers(Int) { var Three; } -@:cppFileCode(' -namespace foo -{ - enum class Numbers : char { - One, - Two = 5, - Three - }; -} -') +@:headerInclude('Numbers.hpp') class TestValueTypeEnumClassAbstract extends Test { function test_switching_on_uncaptured_enum() { final e = Numbers.Two; diff --git a/test/marshalling/src/native/Numbers.hpp b/test/marshalling/src/native/Numbers.hpp new file mode 100644 index 000000000..ec2f68d77 --- /dev/null +++ b/test/marshalling/src/native/Numbers.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace foo +{ + enum class Numbers : char { + One, + Two = 5, + Three + }; +} \ No newline at end of file diff --git a/test/marshalling/src/native/colour.hpp b/test/marshalling/src/native/colour.hpp new file mode 100644 index 000000000..36b175950 --- /dev/null +++ b/test/marshalling/src/native/colour.hpp @@ -0,0 +1,7 @@ +#pragma once + +enum colour { + red, + green, + blue +}; \ No newline at end of file From 50301d317a38d84c9f8645891c2becca5ba85f58 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 20 Jan 2025 19:40:15 +0000 Subject: [PATCH 28/89] test abstract around pointers --- test/marshalling/src/Main.hx | 3 +- .../src/pointers/TestAbstractPointer.hx | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/marshalling/src/pointers/TestAbstractPointer.hx diff --git a/test/marshalling/src/Main.hx b/test/marshalling/src/Main.hx index 1159a590a..65228fb4d 100644 --- a/test/marshalling/src/Main.hx +++ b/test/marshalling/src/Main.hx @@ -19,7 +19,8 @@ class Main { new pointers.TestInheritancePointers(), new pointers.TestEnumPointers(), new pointers.TestPointerFields(), - new pointers.TestPointerCollections() + new pointers.TestPointerCollections(), + new pointers.TestAbstractPointer() ]); } } \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestAbstractPointer.hx b/test/marshalling/src/pointers/TestAbstractPointer.hx new file mode 100644 index 000000000..b63bf0fcc --- /dev/null +++ b/test/marshalling/src/pointers/TestAbstractPointer.hx @@ -0,0 +1,43 @@ +package pointers; + +import utest.Assert; +import utest.Test; + +abstract MyContext(Context) { + public var number (get, never) : Int; + + function get_number() { + return this.number; + } + + public function new() { + this = Context.create(); + } + + public function double() { + this.number *= 2; + } +} + +class TestAbstractPointer extends Test { + function test_cast_to_underlying() { + final v = new MyContext(); + + Assert.equals(7, (cast v : Context).number); + } + + function test_property_access() { + final v = new MyContext(); + + Assert.equals(7, v.number); + } + + function test_mutating_abstract() { + final v = new MyContext(); + + v.double(); + + Assert.equals(14, v.number); + Assert.equals(14, (cast v : Context).number); + } +} From b1231af6ddc2f6c4e4f7c8b48f3603e55622eb96 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 24 Jan 2025 17:08:02 +0000 Subject: [PATCH 29/89] Pointer type changes --- include/cpp/Marshal.h | 180 +++++++++++++++++++++++++----------------- 1 file changed, 106 insertions(+), 74 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 3441d8505..8e98dde85 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -64,21 +64,25 @@ namespace cpp template class PointerType final { - static T FromReference(const PointerReference& inRHS); - static T FromBoxed(const Boxed& inRHS); - static T FromDynamic(const Dynamic& inRHS); + public: + using TPtr = T*; + + private: + static TPtr FromReference(const PointerReference& inRHS); + static TPtr FromBoxed(const Boxed& inRHS); + static TPtr FromDynamic(const Dynamic& inRHS); public: // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; - T value; + TPtr value; PointerType(); - PointerType(T inRHS); + PointerType(TPtr inRHS); PointerType(const PointerReference& inRHS); PointerType(const null& inRHS); - PointerType(const Boxed& inRHS); + PointerType(const Boxed& inRHS); PointerType(const Variant& inRHS); PointerType(const Dynamic& inRHS); @@ -130,9 +134,13 @@ namespace cpp }; template - class PointerReference final : public ::cpp::Reference + class PointerReference final : public ::cpp::Reference { - using Super = ::cpp::Reference; + public: + using TPtr = T*; + + private: + using Super = ::cpp::Reference; template static O* FromDynamic(const Dynamic& inRHS); @@ -140,12 +148,12 @@ namespace cpp template static O* FromBoxed(const Boxed& inRHS); - Boxed ToBoxed() const; + Boxed ToBoxed() const; public: PointerReference(const null& inRHS); PointerReference(const PointerType& inRHS); - PointerReference(const Boxed& inRHS); + PointerReference(const Boxed& inRHS); template PointerReference(const PointerReference& inRHS); @@ -154,20 +162,22 @@ namespace cpp template PointerReference(const Boxed& inRHS); - PointerReference(const T& inRHS); - PointerReference(T& inRHS); - PointerReference(const T* 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() const; + operator Boxed() const; + operator Pointer() const; + operator TPtr() const; operator void* (); operator void** (); - T operator->() const; + TPtr operator->() const; }; } } @@ -175,7 +185,7 @@ namespace cpp // Boxed implementation template -void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) +inline void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) { auto ptr = reinterpret_cast*>(obj); @@ -183,29 +193,29 @@ void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) } template -void cpp::marshal::Boxed_obj::setFinaliser(std::true_type) +inline void cpp::marshal::Boxed_obj::setFinaliser(std::true_type) { ::hx::GCSetFinalizer(this, finalise); } template -void cpp::marshal::Boxed_obj::setFinaliser(std::false_type) {} +inline void cpp::marshal::Boxed_obj::setFinaliser(std::false_type) {} template -cpp::marshal::Boxed_obj::Boxed_obj() : value() +inline cpp::marshal::Boxed_obj::Boxed_obj() : value() { setFinaliser(std::is_destructible{}); } template -cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) +inline cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) { setFinaliser(std::is_destructible{}); } template template -cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward(args)... ) +inline cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward(args)... ) { setFinaliser(std::is_destructible{}); } @@ -214,14 +224,14 @@ cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward template -O* cpp::marshal::ValueReference::FromDynamic(const Dynamic& inRHS) +inline O* cpp::marshal::ValueReference::FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.StaticCast>()); } template template -O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) +inline O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { @@ -232,22 +242,22 @@ O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) } template -cpp::marshal::ValueReference::ValueReference(const null& inRHS) : Super(inRHS) {} +inline cpp::marshal::ValueReference::ValueReference(const null& inRHS) : Super(inRHS) {} template -cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(inRHS.value) {} +inline cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(inRHS.value) {} template -cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} +inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} template -cpp::marshal::ValueReference::ValueReference(const T& inRHS) : Super(inRHS) {} +inline cpp::marshal::ValueReference::ValueReference(const T& inRHS) : Super(inRHS) {} template -cpp::marshal::ValueReference::ValueReference(T& inRHS) : Super(inRHS) {} +inline cpp::marshal::ValueReference::ValueReference(T& inRHS) : Super(inRHS) {} template -cpp::marshal::ValueReference::ValueReference(const T* inRHS) : Super(inRHS) {} +inline cpp::marshal::ValueReference::ValueReference(const T* inRHS) : Super(inRHS) {} template template @@ -255,20 +265,20 @@ inline cpp::marshal::ValueReference::ValueReference(const ValueReference& template template -cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} +inline cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} template template -cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} +inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} template -cpp::marshal::ValueReference::ValueReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} +inline cpp::marshal::ValueReference::ValueReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::ValueReference::ValueReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} +inline cpp::marshal::ValueReference::ValueReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::Boxed cpp::marshal::ValueReference::ToBoxed() const +inline cpp::marshal::Boxed cpp::marshal::ValueReference::ToBoxed() const { if (Super::ptr) { @@ -281,25 +291,25 @@ cpp::marshal::Boxed cpp::marshal::ValueReference::ToBoxed() const } template -cpp::marshal::ValueReference::operator ::Dynamic() const +inline cpp::marshal::ValueReference::operator ::Dynamic() const { return ToBoxed(); } template -cpp::marshal::ValueReference::operator ::cpp::Variant() const +inline cpp::marshal::ValueReference::operator ::cpp::Variant() const { return ToBoxed(); } template -cpp::marshal::ValueReference::operator ::cpp::marshal::Boxed() const +inline cpp::marshal::ValueReference::operator ::cpp::marshal::Boxed() const { return ToBoxed(); } template -T* cpp::marshal::ValueReference::operator ->() const +inline T* cpp::marshal::ValueReference::operator ->() const { if (nullptr == Super::ptr) { @@ -335,21 +345,21 @@ inline T cpp::marshal::ValueReference::operator*() const // Pointer implementation template -cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const +inline cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const { if (nullptr == Super::ptr) { - return new Boxed_obj(); + return new Boxed_obj(); } else { - return new Boxed_obj(Super::ptr); + return new Boxed_obj(Super::ptr); } } template template -O* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) +inline O* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { @@ -361,37 +371,37 @@ O* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) template template -O* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) +inline O* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.StaticCast>()); } template -cpp::marshal::PointerReference::PointerReference(const null& inRHS) : Super(inRHS) {} +inline cpp::marshal::PointerReference::PointerReference(const null& inRHS) : Super(inRHS) {} template -cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(inRHS.value) {} +inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(const_cast(&inRHS.value)) {} template -cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} +inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} template template -cpp::marshal::PointerReference::PointerReference(const PointerReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} +inline cpp::marshal::PointerReference::PointerReference(const PointerReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} template template -cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} +inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} template template -cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} +inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} template -cpp::marshal::PointerReference::PointerReference(const T& inRHS) : Super(inRHS) {} +inline cpp::marshal::PointerReference::PointerReference(const TPtr& inRHS) : Super(inRHS) {} template -cpp::marshal::PointerReference::PointerReference(T& inRHS) +inline cpp::marshal::PointerReference::PointerReference(TPtr& inRHS) { if (nullptr != inRHS) { @@ -400,32 +410,54 @@ cpp::marshal::PointerReference::PointerReference(T& inRHS) } template -cpp::marshal::PointerReference::PointerReference(const T* inRHS) : Super(inRHS) {} +inline cpp::marshal::PointerReference::PointerReference(const TPtr* inRHS) : Super(inRHS) {} template -cpp::marshal::PointerReference::PointerReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} +inline cpp::marshal::PointerReference::PointerReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::PointerReference::PointerReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} +inline cpp::marshal::PointerReference::PointerReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} template -cpp::marshal::PointerReference::operator ::Dynamic() const +inline cpp::marshal::PointerReference::operator ::Dynamic() const { return ToBoxed(); } template -cpp::marshal::PointerReference::operator ::cpp::Variant() const +inline cpp::marshal::PointerReference::operator ::cpp::Variant() const { return ToBoxed(); } template -cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const +inline cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const { return ToBoxed(); } +template +inline cpp::marshal::PointerReference::operator ::cpp::Pointer() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return ::cpp::Pointer(*Super::ptr); +} + +template +inline cpp::marshal::PointerReference::operator TPtr() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + *Super::ptr; +} + template inline cpp::marshal::PointerReference::operator void* () { @@ -439,7 +471,7 @@ inline cpp::marshal::PointerReference::operator void** () } template -inline T cpp::marshal::PointerReference::operator->() const +inline T* cpp::marshal::PointerReference::operator->() const { if (nullptr == Super::ptr) { @@ -457,13 +489,13 @@ inline T cpp::marshal::PointerReference::operator->() const // template -T cpp::marshal::PointerType::FromDynamic(const Dynamic& inRHS) +inline T* cpp::marshal::PointerType::FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.StaticCast>()); } template -T cpp::marshal::PointerType::FromBoxed(const Boxed& inRHS) +inline T* cpp::marshal::PointerType::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { @@ -474,7 +506,7 @@ T cpp::marshal::PointerType::FromBoxed(const Boxed& inRHS) } template -T cpp::marshal::PointerType::FromReference(const PointerReference& inRHS) +inline T* cpp::marshal::PointerType::FromReference(const PointerReference& inRHS) { if (nullptr == inRHS.ptr) { @@ -488,7 +520,7 @@ template inline cpp::marshal::PointerType::PointerType() : value(nullptr) {} template -inline cpp::marshal::PointerType::PointerType(T inRHS) : value(inRHS) {} +inline cpp::marshal::PointerType::PointerType(TPtr inRHS) : value(inRHS) {} template inline cpp::marshal::PointerType::PointerType(const PointerReference& inRHS) : value(FromReference(inRHS.ptr)) {} @@ -497,7 +529,7 @@ template inline cpp::marshal::PointerType::PointerType(const null&) : value(nullptr) {} template -inline cpp::marshal::PointerType::PointerType(const Boxed& inRHS) : value(FromBoxed(inRHS)) {} +inline cpp::marshal::PointerType::PointerType(const Boxed& inRHS) : value(FromBoxed(inRHS)) {} template inline cpp::marshal::PointerType::PointerType(const Variant& inRHS) : value(FromDynamic(inRHS)) {} @@ -524,13 +556,13 @@ inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(con // ValueType implementation template -T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) +inline T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) { return FromBoxed(inRHS.StaticCast>()); } template -T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) +inline T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) { if (nullptr == inRHS.mPtr) { @@ -541,7 +573,7 @@ T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) } template -T cpp::marshal::ValueType::FromReference(const ValueReference& inRHS) +inline T cpp::marshal::ValueType::FromReference(const ValueReference& inRHS) { if (nullptr == inRHS.ptr) { @@ -552,29 +584,29 @@ T cpp::marshal::ValueType::FromReference(const ValueReference& inRHS) } template -cpp::marshal::ValueType::ValueType() : value() {} +inline cpp::marshal::ValueType::ValueType() : value() {} template -cpp::marshal::ValueType::ValueType(const ValueReference& inRHS) : value(FromReference(inRHS.ptr)) {} +inline cpp::marshal::ValueType::ValueType(const ValueReference& inRHS) : value(FromReference(inRHS.ptr)) {} template inline cpp::marshal::ValueType::ValueType(const null& inRHS) : ValueType(::cpp::marshal::ValueReference(inRHS)) {} template -cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::ValueReference(FromBoxed(inRHS))) {} +inline cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::ValueReference(FromBoxed(inRHS))) {} template -cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS.asDynamic()))) {} +inline cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS.asDynamic()))) {} template -cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS))) {} +inline cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS))) {} template template -cpp::marshal::ValueType::ValueType(TArgs... args) : value( std::forward(args)... ) {} +inline cpp::marshal::ValueType::ValueType(TArgs... args) : value( std::forward(args)... ) {} template -cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const ValueReference& inRHS) +inline cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const ValueReference& inRHS) { if (nullptr == inRHS.ptr) { @@ -587,7 +619,7 @@ cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const ValueRef } template -cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& inRHS) +inline cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& inRHS) { ::hx::NullReference("ValueType", true); From 20cb53eb11a93df218831b1c9109b1e646172933 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 25 Jan 2025 11:18:47 +0000 Subject: [PATCH 30/89] add pointer reference to pointer casting --- include/cpp/Marshal.h | 24 ++- test/marshalling/src/Main.hx | 3 +- test/marshalling/src/native/ctx.cpp | 26 +++ test/marshalling/src/native/ctx.hpp | 7 +- .../src/pointers/TestPointerInterop.hx | 168 ++++++++++++++++++ 5 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 test/marshalling/src/pointers/TestPointerInterop.hx diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 8e98dde85..6f215ece7 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -172,10 +172,11 @@ namespace cpp operator Variant() const; operator Boxed() const; operator Pointer() const; - operator TPtr() const; - operator void* (); - operator void** (); + operator TPtr&(); + operator TPtr*(); + operator void*(); + operator void**(); TPtr operator->() const; }; @@ -448,20 +449,31 @@ inline cpp::marshal::PointerReference::operator ::cpp::Pointer() const } template -inline cpp::marshal::PointerReference::operator TPtr() const +inline cpp::marshal::PointerReference::operator TPtr&() { if (nullptr == Super::ptr) { ::hx::NullReference("ValueType", true); } - *Super::ptr; + return *Super::ptr; +} + +template +inline cpp::marshal::PointerReference::operator TPtr* () +{ + return Super::ptr; } template inline cpp::marshal::PointerReference::operator void* () { - return reinterpret_cast(*Super::ptr); + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *Super::ptr; } template diff --git a/test/marshalling/src/Main.hx b/test/marshalling/src/Main.hx index 65228fb4d..2395b82d6 100644 --- a/test/marshalling/src/Main.hx +++ b/test/marshalling/src/Main.hx @@ -20,7 +20,8 @@ class Main { new pointers.TestEnumPointers(), new pointers.TestPointerFields(), new pointers.TestPointerCollections(), - new pointers.TestAbstractPointer() + new pointers.TestAbstractPointer(), + new pointers.TestPointerInterop() ]); } } \ No newline at end of file diff --git a/test/marshalling/src/native/ctx.cpp b/test/marshalling/src/native/ctx.cpp index aa198e761..8898cda00 100644 --- a/test/marshalling/src/native/ctx.cpp +++ b/test/marshalling/src/native/ctx.cpp @@ -12,4 +12,30 @@ ctx* create() { ctx* create_null() { return nullptr; +} + +void ctx_ptr(ctx* pCtx) { + pCtx->number = 20; +} + +void ctx_ptr_ptr(ctx** ppCtx) { + auto replacement = new ctx(); + + replacement->number = 20; + + *ppCtx = replacement; +} + +void ctx_void_ptr(void* pCtx) { + auto casted = static_cast(pCtx); + + casted->number = 20; +} + +void ctx_void_ptr_ptr(void** ppCtx) { + auto replacement = new ctx(); + + replacement->number = 20; + + *ppCtx = replacement; } \ No newline at end of file diff --git a/test/marshalling/src/native/ctx.hpp b/test/marshalling/src/native/ctx.hpp index 83c2d5c1c..586e8f5a0 100644 --- a/test/marshalling/src/native/ctx.hpp +++ b/test/marshalling/src/native/ctx.hpp @@ -9,4 +9,9 @@ struct ctx { }; ctx* create(); -ctx* create_null(); \ No newline at end of file +ctx* create_null(); + +void ctx_ptr(ctx* pCtx); +void ctx_ptr_ptr(ctx** ppCtx); +void ctx_void_ptr(void* pCtx); +void ctx_void_ptr_ptr(void** ppCtx); \ No newline at end of file diff --git a/test/marshalling/src/pointers/TestPointerInterop.hx b/test/marshalling/src/pointers/TestPointerInterop.hx new file mode 100644 index 000000000..20d422b05 --- /dev/null +++ b/test/marshalling/src/pointers/TestPointerInterop.hx @@ -0,0 +1,168 @@ +package pointers; + +import cpp.RawPointer; +import cpp.Star; +import cpp.Pointer; +import utest.Test; +import utest.Assert; + +@:include('ctx.hpp') +private extern class NativeFunction { + @:native('ctx_ptr') + static function ctx_ptr(ctx:Context):Void; + + @:native('ctx_ptr_ptr') + static function ctx_ptr_ptr(ctx:Context):Void; + + @:native('ctx_void_ptr') + static function ctx_void_ptr(ctx:Context):Void; + + @:native('ctx_void_ptr_ptr') + static function ctx_void_ptr_ptr(ctx:Context):Void; +} + +private class HaxeFunctions { + @:unreflective public static function set_number_ptr(ctx : Pointer) { + ctx[0].number = 20; + } + + @:unreflective public static function set_number_raw_ptr(ctx : RawPointer) { + ctx[0].number = 20; + } + + @:unreflective public static function set_number_star(ctx : Star) { + ctx.number = 20; + } + + @:unreflective public static function is_ptr_null(ctx : Pointer) { + return ctx == null; + } + + @:unreflective public static function is_raw_ptr_null(ctx : RawPointer) { + return ctx == null; + } + + @:unreflective public static function is_star_null(ctx : Star) { + return ctx == null; + } +} + +class TestPointerInterop extends Test { + function test_implicit_to_ptr() { + final ctx = Context.create(); + + Assert.equals(7, ctx.number); + + NativeFunction.ctx_ptr(ctx); + + Assert.equals(20, ctx.number); + } + + function test_implicit_to_ptr_ptr() { + final ctx = Context.create(); + + Assert.equals(7, ctx.number); + + NativeFunction.ctx_ptr_ptr(ctx); + + Assert.equals(20, ctx.number); + } + + function test_implicit_to_ptr_ptr_null() { + final ctx : Context = null; + + Assert.isTrue(ctx == null); + + NativeFunction.ctx_ptr_ptr(ctx); + + if (Assert.isTrue(ctx != null)) { + Assert.equals(20, ctx.number); + } + } + + function test_implicit_to_ptr_ptr_copy() { + final ctx = Context.create(); + final copy = ctx; + + Assert.equals(7, ctx.number); + + NativeFunction.ctx_ptr_ptr(ctx); + + Assert.equals(20, ctx.number); + Assert.equals(7, copy.number); + } + + function test_implicit_to_void_ptr() { + final ctx = Context.create(); + + Assert.equals(7, ctx.number); + + NativeFunction.ctx_void_ptr(ctx); + + Assert.equals(20, ctx.number); + } + + function test_implicit_to_void_ptr_ptr() { + final ctx = Context.create(); + + Assert.equals(7, ctx.number); + + NativeFunction.ctx_void_ptr_ptr(ctx); + + Assert.equals(20, ctx.number); + } + + function test_implicit_to_void_ptr_ptr_null() { + final ctx : Context = null; + + Assert.isTrue(ctx == null); + + NativeFunction.ctx_void_ptr_ptr(ctx); + + if (Assert.isTrue(ctx != null)) { + Assert.equals(20, ctx.number); + } + } + + function test_to_cpp_pointer() { + final ctx = Context.create(); + + HaxeFunctions.set_number_ptr(cast ctx); + + Assert.equals(20, ctx.number); + } + + function test_null_to_cpp_pointer_throws() { + final ctx : Context = null; + + Assert.isTrue(HaxeFunctions.is_ptr_null(cast ctx)); + } + + function test_to_cpp_raw_pointer() { + final ctx = Context.create(); + + HaxeFunctions.set_number_raw_ptr(cast ctx); + + Assert.equals(20, ctx.number); + } + + function test_null_to_cpp_raw_pointer_throws() { + final ctx : Context = null; + + Assert.isTrue(HaxeFunctions.is_raw_ptr_null(cast ctx)); + } + + function test_to_cpp_star() { + final ctx = Context.create(); + + HaxeFunctions.set_number_star(cast ctx); + + Assert.equals(20, ctx.number); + } + + function test_null_to_cpp_star_throws() { + final ctx : Context = null; + + Assert.isTrue(HaxeFunctions.is_star_null(cast ctx)); + } +} \ No newline at end of file From 5b5cd497f3cd5507f3fd7431fd9a46c28245d33b Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 25 Jan 2025 11:32:44 +0000 Subject: [PATCH 31/89] add null test to pointer access --- .../src/pointers/TestLocalPointers.hx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/marshalling/src/pointers/TestLocalPointers.hx b/test/marshalling/src/pointers/TestLocalPointers.hx index d5a178fa9..b84105f12 100644 --- a/test/marshalling/src/pointers/TestLocalPointers.hx +++ b/test/marshalling/src/pointers/TestLocalPointers.hx @@ -213,6 +213,23 @@ class TestLocalPointers extends Test { Assert.equals(7, ptr.number); } + function test_null_access_exception() { + final ptr : Context = null; + + Assert.raises(() -> ptr.number = 7); + } + + function test_promoted_null_access_exception() { + final ptr : Context = null; + final f = () -> { + return ptr; + } + + f(); + + Assert.raises(() -> ptr.number = 7); + } + // function by_anon(a : { v : Context }) { From 335fe71825972a87f0ceeb0fbf095a001d83b27b Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 26 Jan 2025 13:37:07 +0000 Subject: [PATCH 32/89] add test for vector of value types --- test/marshalling/src/StdVector.hx | 6 +++++ .../src/classes/TestValueTypeInterop.hx | 22 +++++++++++++++++++ test/marshalling/src/native/point.cpp | 6 ++++- test/marshalling/src/native/point.hpp | 5 ++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/test/marshalling/src/StdVector.hx b/test/marshalling/src/StdVector.hx index adc073c5a..806d95af0 100644 --- a/test/marshalling/src/StdVector.hx +++ b/test/marshalling/src/StdVector.hx @@ -1,3 +1,5 @@ +import cpp.Reference; + @:include('vector') @:semantics(reference) @:cpp.ValueType({ type : 'vector', namespace : [ 'std' ] }) @@ -8,4 +10,8 @@ extern class StdVector implements ArrayAccess { function size():Int; function resize(s:Int):Void; + + function at(s:Int):Reference; + + function push_back(v:T):Void; } \ No newline at end of file diff --git a/test/marshalling/src/classes/TestValueTypeInterop.hx b/test/marshalling/src/classes/TestValueTypeInterop.hx index 3838f3905..ef41ceb04 100644 --- a/test/marshalling/src/classes/TestValueTypeInterop.hx +++ b/test/marshalling/src/classes/TestValueTypeInterop.hx @@ -8,6 +8,17 @@ import cpp.RawPointer; import utest.Assert; import utest.Test; +@:semantics(reference) +@:include('point.hpp') +@:cpp.ValueType({ type : 'point', namespace : [ 'hx', 'maths' ] }) +private extern class Point { + var x : Float; + var y : Float; + + @:overload(function(_x : Float, _y : Float) : Void {}) + function new(); +} + private extern class NativeFunctions { @:native('vec_by_val') static function vec_by_val(v:StdVector):Void; @@ -17,6 +28,9 @@ private extern class NativeFunctions { @:native('vec_by_ptr') static function vec_by_ptr(v:StdVector):Void; + + @:native('point_vec') + static function point_vec(v:StdVector):Void; } private class HaxeFunctions { @@ -216,4 +230,12 @@ class TestValueTypeInterop extends Test { Assert.equals(10, v.size()); } + + function test_vec_of_points() { + final v = new StdVector(5); + + NativeFunctions.point_vec(v); + + Assert.equals(300f64, v.at(0).x); + } } \ No newline at end of file diff --git a/test/marshalling/src/native/point.cpp b/test/marshalling/src/native/point.cpp index 702186786..ca2e19756 100644 --- a/test/marshalling/src/native/point.cpp +++ b/test/marshalling/src/native/point.cpp @@ -1,4 +1,8 @@ #include #include -hx::maths::point::point(double _x, double _y) : x(_x), y(_y) {} \ No newline at end of file +hx::maths::point::point(double _x, double _y) : x(_x), y(_y) {} + +void point_vec(std::vector<::hx::maths::point>& v) { + v[0].x = 300; +} \ No newline at end of file diff --git a/test/marshalling/src/native/point.hpp b/test/marshalling/src/native/point.hpp index f7d0e5c82..cae68c314 100644 --- a/test/marshalling/src/native/point.hpp +++ b/test/marshalling/src/native/point.hpp @@ -1,4 +1,5 @@ #pragma once +#include namespace hx { namespace maths { @@ -10,4 +11,6 @@ namespace hx { point(double _x, double _y); }; } -} \ No newline at end of file +} + +void point_vec(std::vector<::hx::maths::point>& v); \ No newline at end of file From f2a5e24922c16b9d837cfca70b328afe5712ae02 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 26 Jan 2025 14:23:49 +0000 Subject: [PATCH 33/89] add tests showing weird null behaviour --- .../src/enums/TestValueTypeEnumAbstract.hx | 2 +- .../src/pointers/TestLocalPointers.hx | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx b/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx index 9819b58bb..5b2a68058 100644 --- a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx +++ b/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx @@ -5,7 +5,7 @@ import utest.Test; @:semantics(reference) @:include('colour.hpp') -@:cpp.ValueType({ type : 'colour', namespace : [] }) +@:cpp.ValueType({ type : 'colour' }) private extern enum abstract Colour(Int) { @:native('red') var Red; diff --git a/test/marshalling/src/pointers/TestLocalPointers.hx b/test/marshalling/src/pointers/TestLocalPointers.hx index b84105f12..20146d7dc 100644 --- a/test/marshalling/src/pointers/TestLocalPointers.hx +++ b/test/marshalling/src/pointers/TestLocalPointers.hx @@ -230,6 +230,33 @@ class TestLocalPointers extends Test { Assert.raises(() -> ptr.number = 7); } + // function test_weird_nullness() { + // function isAnyNull(a:Any) { + // return a == null; + // } + + // final ptr = Context.createNull(); + + // Assert.isTrue(ptr == null); + // Assert.isTrue(isAnyNull(ptr)); + // } + + // function test_weird_promoted_nullness() { + // function isAnyNull(a:Any) { + // return a == null; + // } + + // final ptr = Context.createNull(); + // final f = () -> { + // return ptr; + // } + + // f(); + + // Assert.isTrue(ptr == null); + // Assert.isTrue(isAnyNull(ptr)); + // } + // function by_anon(a : { v : Context }) { From 82abbb4b83ddc57b8604ccc6f69b7f2cb1720ae4 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 26 Jan 2025 15:45:33 +0000 Subject: [PATCH 34/89] move marshalling tests to existing native tests --- test/marshalling/build.hxml | 5 ---- test/marshalling/src/Main.hx | 27 ----------------- test/native/Native.hx | 28 +++++++++++++++++- test/native/compile.hxml | 1 - test/native/test.txt | Bin 0 -> 4 bytes .../tests/marshalling}/Build.xml | 0 .../tests/marshalling}/Context.hx | 2 ++ .../tests/marshalling}/StdVector.hx | 2 ++ .../classes/TestAbstractValueType.hx | 4 +-- .../classes/TestClassValueType.hx | 2 +- .../marshalling}/classes/TestEnumValueType.hx | 2 +- .../marshalling}/classes/TestInheritance.hx | 2 +- .../classes/TestInterfaceValueType.hx | 2 +- .../classes/TestLocalValueType.hx | 2 +- .../classes/TestValueTypeCollections.hx | 2 +- .../classes/TestValueTypeFields.hx | 2 +- .../classes/TestValueTypeInterop.hx | 2 +- .../enums/TestValueTypeEnumAbstract.hx | 2 +- .../enums/TestValueTypeEnumClassAbstract.hx | 2 +- .../tests/marshalling}/native/Base.cpp | 0 .../tests/marshalling}/native/Base.hpp | 0 .../tests/marshalling}/native/Child.cpp | 0 .../tests/marshalling}/native/Child.hpp | 0 .../tests/marshalling}/native/Numbers.hpp | 0 .../tests/marshalling}/native/colour.hpp | 0 .../tests/marshalling}/native/ctx.cpp | 0 .../tests/marshalling}/native/ctx.hpp | 0 .../tests/marshalling}/native/holder.cpp | 0 .../tests/marshalling}/native/holder.hpp | 0 .../tests/marshalling}/native/point.cpp | 0 .../tests/marshalling}/native/point.hpp | 0 .../pointers/TestAbstractPointer.hx | 2 +- .../pointers/TestClassPointers.hx | 2 +- .../marshalling}/pointers/TestEnumPointers.hx | 2 +- .../pointers/TestInheritancePointers.hx | 2 +- .../pointers/TestInterfacePointers.hx | 2 +- .../pointers/TestLocalPointers.hx | 2 +- .../pointers/TestPointerCollections.hx | 2 +- .../pointers/TestPointerFields.hx | 2 +- .../pointers/TestPointerInterop.hx | 2 +- 40 files changed, 52 insertions(+), 55 deletions(-) delete mode 100644 test/marshalling/build.hxml delete mode 100644 test/marshalling/src/Main.hx create mode 100644 test/native/test.txt rename test/{marshalling/src => native/tests/marshalling}/Build.xml (100%) rename test/{marshalling/src => native/tests/marshalling}/Context.hx (92%) rename test/{marshalling/src => native/tests/marshalling}/StdVector.hx (93%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestAbstractValueType.hx (93%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestClassValueType.hx (99%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestEnumValueType.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestInheritance.hx (97%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestInterfaceValueType.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestLocalValueType.hx (99%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestValueTypeCollections.hx (97%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestValueTypeFields.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/classes/TestValueTypeInterop.hx (99%) rename test/{marshalling/src => native/tests/marshalling}/enums/TestValueTypeEnumAbstract.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/enums/TestValueTypeEnumClassAbstract.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/native/Base.cpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/Base.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/Child.cpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/Child.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/Numbers.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/colour.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/ctx.cpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/ctx.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/holder.cpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/holder.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/point.cpp (100%) rename test/{marshalling/src => native/tests/marshalling}/native/point.hpp (100%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestAbstractPointer.hx (95%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestClassPointers.hx (99%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestEnumPointers.hx (97%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestInheritancePointers.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestInterfacePointers.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestLocalPointers.hx (99%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestPointerCollections.hx (97%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestPointerFields.hx (98%) rename test/{marshalling/src => native/tests/marshalling}/pointers/TestPointerInterop.hx (99%) diff --git a/test/marshalling/build.hxml b/test/marshalling/build.hxml deleted file mode 100644 index 4ae32f8d5..000000000 --- a/test/marshalling/build.hxml +++ /dev/null @@ -1,5 +0,0 @@ --p src --m Main --L utest ---cpp bin ---debug \ No newline at end of file diff --git a/test/marshalling/src/Main.hx b/test/marshalling/src/Main.hx deleted file mode 100644 index 2395b82d6..000000000 --- a/test/marshalling/src/Main.hx +++ /dev/null @@ -1,27 +0,0 @@ -@:buildXml("") -class Main { - static function main() { - utest.UTest.run([ - new classes.TestLocalValueType(), - new classes.TestClassValueType(), - new classes.TestInterfaceValueType(), - new classes.TestEnumValueType(), - new classes.TestAbstractValueType(), - new classes.TestValueTypeInterop(), - new classes.TestValueTypeCollections(), - new classes.TestValueTypeFields(), - new classes.TestInheritance(), - new enums.TestValueTypeEnumAbstract(), - new enums.TestValueTypeEnumClassAbstract(), - new pointers.TestLocalPointers(), - new pointers.TestClassPointers(), - new pointers.TestInterfacePointers(), - new pointers.TestInheritancePointers(), - new pointers.TestEnumPointers(), - new pointers.TestPointerFields(), - new pointers.TestPointerCollections(), - new pointers.TestAbstractPointer(), - new pointers.TestPointerInterop() - ]); - } -} \ No newline at end of file diff --git a/test/native/Native.hx b/test/native/Native.hx index acab7aada..9be12a709 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -1,5 +1,8 @@ package; +#if (haxe_ver>=5) +@:buildXml("") +#end class Native { static function main() @@ -12,7 +15,30 @@ class Native new tests.TestNativeGen(), new tests.TestNonVirtual(), new tests.TestPtr(), - new tests.TestNativeEnum() + new tests.TestNativeEnum(), + + #if (haxe_ver>=5) + new tests.marshalling.classes.TestLocalValueType(), + new tests.marshalling.classes.TestClassValueType(), + new tests.marshalling.classes.TestInterfaceValueType(), + new tests.marshalling.classes.TestEnumValueType(), + new tests.marshalling.classes.TestAbstractValueType(), + new tests.marshalling.classes.TestValueTypeInterop(), + new tests.marshalling.classes.TestValueTypeCollections(), + new tests.marshalling.classes.TestValueTypeFields(), + new tests.marshalling.classes.TestInheritance(), + new tests.marshalling.enums.TestValueTypeEnumAbstract(), + new tests.marshalling.enums.TestValueTypeEnumClassAbstract(), + new tests.marshalling.pointers.TestLocalPointers(), + new tests.marshalling.pointers.TestClassPointers(), + new tests.marshalling.pointers.TestInterfacePointers(), + new tests.marshalling.pointers.TestInheritancePointers(), + new tests.marshalling.pointers.TestEnumPointers(), + new tests.marshalling.pointers.TestPointerFields(), + new tests.marshalling.pointers.TestPointerCollections(), + new tests.marshalling.pointers.TestAbstractPointer(), + new tests.marshalling.pointers.TestPointerInterop() + #end ]); } } diff --git a/test/native/compile.hxml b/test/native/compile.hxml index b2e405bb7..825082805 100644 --- a/test/native/compile.hxml +++ b/test/native/compile.hxml @@ -1,4 +1,3 @@ -m Native --D HXCPP_DEBUGGER -L utest --cpp bin \ No newline at end of file diff --git a/test/native/test.txt b/test/native/test.txt new file mode 100644 index 0000000000000000000000000000000000000000..f66c9cf4c9672fa2832bce76f4082fd97b823506 GIT binary patch literal 4 LcmZQ%U|;|M00;mA literal 0 HcmV?d00001 diff --git a/test/marshalling/src/Build.xml b/test/native/tests/marshalling/Build.xml similarity index 100% rename from test/marshalling/src/Build.xml rename to test/native/tests/marshalling/Build.xml diff --git a/test/marshalling/src/Context.hx b/test/native/tests/marshalling/Context.hx similarity index 92% rename from test/marshalling/src/Context.hx rename to test/native/tests/marshalling/Context.hx index b232dda96..6008a5c74 100644 --- a/test/marshalling/src/Context.hx +++ b/test/native/tests/marshalling/Context.hx @@ -1,3 +1,5 @@ +package tests.marshalling; + @:semantics(reference) @:include('ctx.hpp') @:cpp.PointerType({ type : 'ctx' }) diff --git a/test/marshalling/src/StdVector.hx b/test/native/tests/marshalling/StdVector.hx similarity index 93% rename from test/marshalling/src/StdVector.hx rename to test/native/tests/marshalling/StdVector.hx index 806d95af0..548f64678 100644 --- a/test/marshalling/src/StdVector.hx +++ b/test/native/tests/marshalling/StdVector.hx @@ -1,3 +1,5 @@ +package tests.marshalling; + import cpp.Reference; @:include('vector') diff --git a/test/marshalling/src/classes/TestAbstractValueType.hx b/test/native/tests/marshalling/classes/TestAbstractValueType.hx similarity index 93% rename from test/marshalling/src/classes/TestAbstractValueType.hx rename to test/native/tests/marshalling/classes/TestAbstractValueType.hx index 5073bb6dc..652f94b3a 100644 --- a/test/marshalling/src/classes/TestAbstractValueType.hx +++ b/test/native/tests/marshalling/classes/TestAbstractValueType.hx @@ -1,6 +1,6 @@ -package classes; +package tests.marshalling.classes; -import StdVector; +import tests.marshalling.StdVector; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestClassValueType.hx b/test/native/tests/marshalling/classes/TestClassValueType.hx similarity index 99% rename from test/marshalling/src/classes/TestClassValueType.hx rename to test/native/tests/marshalling/classes/TestClassValueType.hx index 54e01ed18..dc29e794b 100644 --- a/test/marshalling/src/classes/TestClassValueType.hx +++ b/test/native/tests/marshalling/classes/TestClassValueType.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestEnumValueType.hx b/test/native/tests/marshalling/classes/TestEnumValueType.hx similarity index 98% rename from test/marshalling/src/classes/TestEnumValueType.hx rename to test/native/tests/marshalling/classes/TestEnumValueType.hx index f0cf7807a..1955b90f1 100644 --- a/test/marshalling/src/classes/TestEnumValueType.hx +++ b/test/native/tests/marshalling/classes/TestEnumValueType.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import haxe.EnumTools; import utest.Assert; diff --git a/test/marshalling/src/classes/TestInheritance.hx b/test/native/tests/marshalling/classes/TestInheritance.hx similarity index 97% rename from test/marshalling/src/classes/TestInheritance.hx rename to test/native/tests/marshalling/classes/TestInheritance.hx index 1202c856a..8a5bad273 100644 --- a/test/marshalling/src/classes/TestInheritance.hx +++ b/test/native/tests/marshalling/classes/TestInheritance.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestInterfaceValueType.hx b/test/native/tests/marshalling/classes/TestInterfaceValueType.hx similarity index 98% rename from test/marshalling/src/classes/TestInterfaceValueType.hx rename to test/native/tests/marshalling/classes/TestInterfaceValueType.hx index 54a72722e..0819b1267 100644 --- a/test/marshalling/src/classes/TestInterfaceValueType.hx +++ b/test/native/tests/marshalling/classes/TestInterfaceValueType.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestLocalValueType.hx b/test/native/tests/marshalling/classes/TestLocalValueType.hx similarity index 99% rename from test/marshalling/src/classes/TestLocalValueType.hx rename to test/native/tests/marshalling/classes/TestLocalValueType.hx index a7f4ad276..2ba6702a4 100644 --- a/test/marshalling/src/classes/TestLocalValueType.hx +++ b/test/native/tests/marshalling/classes/TestLocalValueType.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestValueTypeCollections.hx b/test/native/tests/marshalling/classes/TestValueTypeCollections.hx similarity index 97% rename from test/marshalling/src/classes/TestValueTypeCollections.hx rename to test/native/tests/marshalling/classes/TestValueTypeCollections.hx index cced66c8a..43f2596d4 100644 --- a/test/marshalling/src/classes/TestValueTypeCollections.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeCollections.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestValueTypeFields.hx b/test/native/tests/marshalling/classes/TestValueTypeFields.hx similarity index 98% rename from test/marshalling/src/classes/TestValueTypeFields.hx rename to test/native/tests/marshalling/classes/TestValueTypeFields.hx index 29a213b0d..cdf2cff6d 100644 --- a/test/marshalling/src/classes/TestValueTypeFields.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeFields.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/classes/TestValueTypeInterop.hx b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx similarity index 99% rename from test/marshalling/src/classes/TestValueTypeInterop.hx rename to test/native/tests/marshalling/classes/TestValueTypeInterop.hx index ef41ceb04..d59f20686 100644 --- a/test/marshalling/src/classes/TestValueTypeInterop.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx @@ -1,4 +1,4 @@ -package classes; +package tests.marshalling.classes; import cpp.Native; import cpp.Star; diff --git a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx b/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx similarity index 98% rename from test/marshalling/src/enums/TestValueTypeEnumAbstract.hx rename to test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx index 5b2a68058..7c76c8375 100644 --- a/test/marshalling/src/enums/TestValueTypeEnumAbstract.hx +++ b/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx @@ -1,4 +1,4 @@ -package enums; +package tests.marshalling.enums; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx b/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx similarity index 98% rename from test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx rename to test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx index 74336fdaf..8f639585e 100644 --- a/test/marshalling/src/enums/TestValueTypeEnumClassAbstract.hx +++ b/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx @@ -1,4 +1,4 @@ -package enums; +package tests.marshalling.enums; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/native/Base.cpp b/test/native/tests/marshalling/native/Base.cpp similarity index 100% rename from test/marshalling/src/native/Base.cpp rename to test/native/tests/marshalling/native/Base.cpp diff --git a/test/marshalling/src/native/Base.hpp b/test/native/tests/marshalling/native/Base.hpp similarity index 100% rename from test/marshalling/src/native/Base.hpp rename to test/native/tests/marshalling/native/Base.hpp diff --git a/test/marshalling/src/native/Child.cpp b/test/native/tests/marshalling/native/Child.cpp similarity index 100% rename from test/marshalling/src/native/Child.cpp rename to test/native/tests/marshalling/native/Child.cpp diff --git a/test/marshalling/src/native/Child.hpp b/test/native/tests/marshalling/native/Child.hpp similarity index 100% rename from test/marshalling/src/native/Child.hpp rename to test/native/tests/marshalling/native/Child.hpp diff --git a/test/marshalling/src/native/Numbers.hpp b/test/native/tests/marshalling/native/Numbers.hpp similarity index 100% rename from test/marshalling/src/native/Numbers.hpp rename to test/native/tests/marshalling/native/Numbers.hpp diff --git a/test/marshalling/src/native/colour.hpp b/test/native/tests/marshalling/native/colour.hpp similarity index 100% rename from test/marshalling/src/native/colour.hpp rename to test/native/tests/marshalling/native/colour.hpp diff --git a/test/marshalling/src/native/ctx.cpp b/test/native/tests/marshalling/native/ctx.cpp similarity index 100% rename from test/marshalling/src/native/ctx.cpp rename to test/native/tests/marshalling/native/ctx.cpp diff --git a/test/marshalling/src/native/ctx.hpp b/test/native/tests/marshalling/native/ctx.hpp similarity index 100% rename from test/marshalling/src/native/ctx.hpp rename to test/native/tests/marshalling/native/ctx.hpp diff --git a/test/marshalling/src/native/holder.cpp b/test/native/tests/marshalling/native/holder.cpp similarity index 100% rename from test/marshalling/src/native/holder.cpp rename to test/native/tests/marshalling/native/holder.cpp diff --git a/test/marshalling/src/native/holder.hpp b/test/native/tests/marshalling/native/holder.hpp similarity index 100% rename from test/marshalling/src/native/holder.hpp rename to test/native/tests/marshalling/native/holder.hpp diff --git a/test/marshalling/src/native/point.cpp b/test/native/tests/marshalling/native/point.cpp similarity index 100% rename from test/marshalling/src/native/point.cpp rename to test/native/tests/marshalling/native/point.cpp diff --git a/test/marshalling/src/native/point.hpp b/test/native/tests/marshalling/native/point.hpp similarity index 100% rename from test/marshalling/src/native/point.hpp rename to test/native/tests/marshalling/native/point.hpp diff --git a/test/marshalling/src/pointers/TestAbstractPointer.hx b/test/native/tests/marshalling/pointers/TestAbstractPointer.hx similarity index 95% rename from test/marshalling/src/pointers/TestAbstractPointer.hx rename to test/native/tests/marshalling/pointers/TestAbstractPointer.hx index b63bf0fcc..2409273e1 100644 --- a/test/marshalling/src/pointers/TestAbstractPointer.hx +++ b/test/native/tests/marshalling/pointers/TestAbstractPointer.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestClassPointers.hx b/test/native/tests/marshalling/pointers/TestClassPointers.hx similarity index 99% rename from test/marshalling/src/pointers/TestClassPointers.hx rename to test/native/tests/marshalling/pointers/TestClassPointers.hx index 7991d3249..e2c403eff 100644 --- a/test/marshalling/src/pointers/TestClassPointers.hx +++ b/test/native/tests/marshalling/pointers/TestClassPointers.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestEnumPointers.hx b/test/native/tests/marshalling/pointers/TestEnumPointers.hx similarity index 97% rename from test/marshalling/src/pointers/TestEnumPointers.hx rename to test/native/tests/marshalling/pointers/TestEnumPointers.hx index ebf06cca1..0ba65d2ef 100644 --- a/test/marshalling/src/pointers/TestEnumPointers.hx +++ b/test/native/tests/marshalling/pointers/TestEnumPointers.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import haxe.EnumTools; import utest.Assert; diff --git a/test/marshalling/src/pointers/TestInheritancePointers.hx b/test/native/tests/marshalling/pointers/TestInheritancePointers.hx similarity index 98% rename from test/marshalling/src/pointers/TestInheritancePointers.hx rename to test/native/tests/marshalling/pointers/TestInheritancePointers.hx index 876dcaa9c..2cf1a765d 100644 --- a/test/marshalling/src/pointers/TestInheritancePointers.hx +++ b/test/native/tests/marshalling/pointers/TestInheritancePointers.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestInterfacePointers.hx b/test/native/tests/marshalling/pointers/TestInterfacePointers.hx similarity index 98% rename from test/marshalling/src/pointers/TestInterfacePointers.hx rename to test/native/tests/marshalling/pointers/TestInterfacePointers.hx index 16ecc6154..092c4508b 100644 --- a/test/marshalling/src/pointers/TestInterfacePointers.hx +++ b/test/native/tests/marshalling/pointers/TestInterfacePointers.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestLocalPointers.hx b/test/native/tests/marshalling/pointers/TestLocalPointers.hx similarity index 99% rename from test/marshalling/src/pointers/TestLocalPointers.hx rename to test/native/tests/marshalling/pointers/TestLocalPointers.hx index 20146d7dc..dcca7ff85 100644 --- a/test/marshalling/src/pointers/TestLocalPointers.hx +++ b/test/native/tests/marshalling/pointers/TestLocalPointers.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestPointerCollections.hx b/test/native/tests/marshalling/pointers/TestPointerCollections.hx similarity index 97% rename from test/marshalling/src/pointers/TestPointerCollections.hx rename to test/native/tests/marshalling/pointers/TestPointerCollections.hx index edfe60632..3611fe971 100644 --- a/test/marshalling/src/pointers/TestPointerCollections.hx +++ b/test/native/tests/marshalling/pointers/TestPointerCollections.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestPointerFields.hx b/test/native/tests/marshalling/pointers/TestPointerFields.hx similarity index 98% rename from test/marshalling/src/pointers/TestPointerFields.hx rename to test/native/tests/marshalling/pointers/TestPointerFields.hx index e1dde6188..19ad20091 100644 --- a/test/marshalling/src/pointers/TestPointerFields.hx +++ b/test/native/tests/marshalling/pointers/TestPointerFields.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import utest.Assert; import utest.Test; diff --git a/test/marshalling/src/pointers/TestPointerInterop.hx b/test/native/tests/marshalling/pointers/TestPointerInterop.hx similarity index 99% rename from test/marshalling/src/pointers/TestPointerInterop.hx rename to test/native/tests/marshalling/pointers/TestPointerInterop.hx index 20d422b05..6c1948c0a 100644 --- a/test/marshalling/src/pointers/TestPointerInterop.hx +++ b/test/native/tests/marshalling/pointers/TestPointerInterop.hx @@ -1,4 +1,4 @@ -package pointers; +package tests.marshalling.pointers; import cpp.RawPointer; import cpp.Star; From 7a45f5c541133eecbc8ad131df6821ba5ceab9c4 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 1 Feb 2025 16:47:38 +0000 Subject: [PATCH 35/89] initial managed extern tests --- test/native/Native.hx | 3 +- test/native/compile.hxml | 1 + test/native/tests/marshalling/Build.xml | 6 + .../managed/TestLocalManagedClass.hx | 133 ++++++++++++++++++ .../tests/marshalling/native/Managed.cpp | 45 ++++++ .../tests/marshalling/native/Managed.hpp | 38 +++++ .../pointers/TestInheritancePointers.hx | 2 - 7 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 test/native/tests/marshalling/managed/TestLocalManagedClass.hx create mode 100644 test/native/tests/marshalling/native/Managed.cpp create mode 100644 test/native/tests/marshalling/native/Managed.hpp diff --git a/test/native/Native.hx b/test/native/Native.hx index 9be12a709..e9b4dc7c9 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -37,7 +37,8 @@ class Native new tests.marshalling.pointers.TestPointerFields(), new tests.marshalling.pointers.TestPointerCollections(), new tests.marshalling.pointers.TestAbstractPointer(), - new tests.marshalling.pointers.TestPointerInterop() + new tests.marshalling.pointers.TestPointerInterop(), + new tests.marshalling.managed.TestLocalManagedClass(), #end ]); } diff --git a/test/native/compile.hxml b/test/native/compile.hxml index 825082805..76d71c20f 100644 --- a/test/native/compile.hxml +++ b/test/native/compile.hxml @@ -1,3 +1,4 @@ -m Native -L utest +--debug --cpp bin \ No newline at end of file diff --git a/test/native/tests/marshalling/Build.xml b/test/native/tests/marshalling/Build.xml index 81ff1a3b3..29f8ef243 100644 --- a/test/native/tests/marshalling/Build.xml +++ b/test/native/tests/marshalling/Build.xml @@ -1,5 +1,7 @@ + + @@ -23,6 +25,10 @@ + + + + diff --git a/test/native/tests/marshalling/managed/TestLocalManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalManagedClass.hx new file mode 100644 index 000000000..f618b5c80 --- /dev/null +++ b/test/native/tests/marshalling/managed/TestLocalManagedClass.hx @@ -0,0 +1,133 @@ +package tests.marshalling.managed; + +import utest.Assert; +import utest.Test; + +@:include('Managed.hpp') +@:cpp.ManagedType({ type : 'fooextern', namespace : [ 'hx' ] }) +extern class FooExtern { + static var constNumber : Int; + + var number : Int; + + function new() : Void; + + function doubleNumber() : Int; + + static function create(number : Int) : FooExtern; +} + +@:include('Managed.hpp') +@:cpp.ManagedType({ namespace : [ 'foo', 'bar' ], flags : [ StandardNaming ] }) +extern class StandardLayoutExtern { + function doubleNumber(input : Int) : Int; + + static function create() : StandardLayoutExtern; +} + +@:include('Managed.hpp') +@:cpp.ManagedType({ namespace : [ 'hx' ] }) +extern class WithClosure { + function new() : Void; + + @:native('ReturnSeven') + function returnSeven() : Int; +} + +class TestLocalManagedClass extends Test { + + function test_null_object() { + final o : FooExtern = null; + + Assert.isNull(o); + } + + function test_construction() { + final o = new FooExtern(); + + Assert.notNull(o); + } + + function test_equality() { + final o1 = new FooExtern(); + final o2 = o1; + + Assert.equals(o1, o2); + } + + function test_inequality() { + final o1 = new FooExtern(); + final o2 = new FooExtern(); + + Assert.notEquals(o1, o2); + } + + function test_var_access() { + final o = new FooExtern(); + + Assert.equals(0, o.number); + } + + function test_var_mutation() { + final o = new FooExtern(); + + o.number = 7; + + Assert.equals(7, o.number); + } + + function test_static_var_access() { + Assert.equals(300, FooExtern.constNumber); + } + + function test_static_var_mutation() { + FooExtern.constNumber = 200; + + Assert.equals(200, FooExtern.constNumber); + + FooExtern.constNumber = 300; + } + + function test_function_call() { + final o = new FooExtern(); + + o.number = 7; + + Assert.equals(14, o.doubleNumber()); + } + + function test_static_function_call() { + final o = FooExtern.create(7); + + Assert.notNull(o); + } + + function test_to_string() { + final o = new FooExtern(); + + Assert.equals("fooextern", Std.string(o)); + } + + function test_standard_naming() { + final o = StandardLayoutExtern.create(); + + Assert.equals(14, o.doubleNumber(7)); + } + + function test_null_access() { + final o : FooExtern = null; + + Assert.raises(() -> o.number = 7); + } + + function test_function_closures() { + final o = new WithClosure(); + final f = o.returnSeven; + + Assert.equals(7, f()); + } + + // function test_reflection() { + // // + // } +} \ No newline at end of file diff --git a/test/native/tests/marshalling/native/Managed.cpp b/test/native/tests/marshalling/native/Managed.cpp new file mode 100644 index 000000000..cbd6f9323 --- /dev/null +++ b/test/native/tests/marshalling/native/Managed.cpp @@ -0,0 +1,45 @@ +#include +#include + +int hx::fooextern::constNumber = 300; + +hx::fooextern::fooextern() {} + +int hx::fooextern::doubleNumber() +{ + return number * 2; +} + +::String hx::fooextern::toString() +{ + return ::String::create("fooextern"); +} + +hx::fooextern* hx::fooextern::create(int number) +{ + auto ptr = new hx::fooextern(); + + ptr->number = number; + + return ptr; +} + +int hx::WithClosure::ReturnSeven() +{ + return 7; +} + +int foo::bar::StandardLayoutExtern_obj::doubleNumber(int input) +{ + return input * 2; +} + +foo::bar::StandardLayoutExtern foo::bar::StandardLayoutExtern_obj::create() +{ + return foo::bar::StandardLayoutExtern(new StandardLayoutExtern_obj()); +} + +namespace hx +{ + HX_DEFINE_DYNAMIC_FUNC0(WithClosure, ReturnSeven, return) +} \ No newline at end of file diff --git a/test/native/tests/marshalling/native/Managed.hpp b/test/native/tests/marshalling/native/Managed.hpp new file mode 100644 index 000000000..00477ea07 --- /dev/null +++ b/test/native/tests/marshalling/native/Managed.hpp @@ -0,0 +1,38 @@ +#pragma once + +HX_DECLARE_CLASS2(foo,bar,StandardLayoutExtern) + +namespace foo +{ + namespace bar + { + struct StandardLayoutExtern_obj : public ::hx::Object { + virtual int doubleNumber(int input); + + static StandardLayoutExtern create(); + }; + } +} + +namespace hx +{ + struct fooextern : public ::hx::Object { + static int constNumber; + + int number; + + fooextern(); + + int doubleNumber(); + + ::String toString() override; + + static fooextern* create(int number); + }; + + struct WithClosure : public ::hx::Object { + int ReturnSeven(); + + ::Dynamic ReturnSeven_dyn(); + }; +} \ No newline at end of file diff --git a/test/native/tests/marshalling/pointers/TestInheritancePointers.hx b/test/native/tests/marshalling/pointers/TestInheritancePointers.hx index 2cf1a765d..0db1bb22d 100644 --- a/test/native/tests/marshalling/pointers/TestInheritancePointers.hx +++ b/test/native/tests/marshalling/pointers/TestInheritancePointers.hx @@ -14,8 +14,6 @@ private extern class Base { @:include('Child.hpp') @:cpp.PointerType private extern class Child extends Base { - function new():Void; - function bar():Int; } From d4e2d54335376347351db7db84729e68764d7445 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 2 Feb 2025 12:47:15 +0000 Subject: [PATCH 36/89] managed extern local tests for two different naming schemes --- test/native/Native.hx | 3 +- .../managed/TestLocalManagedClass.hx | 133 ------------------ .../TestLocalNonStandardManagedClass.hx | 133 ++++++++++++++++++ .../managed/TestLocalStandardManagedClass.hx | 116 +++++++++++++++ .../tests/marshalling/native/Managed.cpp | 41 ++---- .../tests/marshalling/native/Managed.hpp | 30 ++-- 6 files changed, 271 insertions(+), 185 deletions(-) delete mode 100644 test/native/tests/marshalling/managed/TestLocalManagedClass.hx create mode 100644 test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx create mode 100644 test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx diff --git a/test/native/Native.hx b/test/native/Native.hx index e9b4dc7c9..5ce1ab098 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -38,7 +38,8 @@ class Native new tests.marshalling.pointers.TestPointerCollections(), new tests.marshalling.pointers.TestAbstractPointer(), new tests.marshalling.pointers.TestPointerInterop(), - new tests.marshalling.managed.TestLocalManagedClass(), + new tests.marshalling.managed.TestLocalNonStandardManagedClass(), + new tests.marshalling.managed.TestLocalStandardManagedClass() #end ]); } diff --git a/test/native/tests/marshalling/managed/TestLocalManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalManagedClass.hx deleted file mode 100644 index f618b5c80..000000000 --- a/test/native/tests/marshalling/managed/TestLocalManagedClass.hx +++ /dev/null @@ -1,133 +0,0 @@ -package tests.marshalling.managed; - -import utest.Assert; -import utest.Test; - -@:include('Managed.hpp') -@:cpp.ManagedType({ type : 'fooextern', namespace : [ 'hx' ] }) -extern class FooExtern { - static var constNumber : Int; - - var number : Int; - - function new() : Void; - - function doubleNumber() : Int; - - static function create(number : Int) : FooExtern; -} - -@:include('Managed.hpp') -@:cpp.ManagedType({ namespace : [ 'foo', 'bar' ], flags : [ StandardNaming ] }) -extern class StandardLayoutExtern { - function doubleNumber(input : Int) : Int; - - static function create() : StandardLayoutExtern; -} - -@:include('Managed.hpp') -@:cpp.ManagedType({ namespace : [ 'hx' ] }) -extern class WithClosure { - function new() : Void; - - @:native('ReturnSeven') - function returnSeven() : Int; -} - -class TestLocalManagedClass extends Test { - - function test_null_object() { - final o : FooExtern = null; - - Assert.isNull(o); - } - - function test_construction() { - final o = new FooExtern(); - - Assert.notNull(o); - } - - function test_equality() { - final o1 = new FooExtern(); - final o2 = o1; - - Assert.equals(o1, o2); - } - - function test_inequality() { - final o1 = new FooExtern(); - final o2 = new FooExtern(); - - Assert.notEquals(o1, o2); - } - - function test_var_access() { - final o = new FooExtern(); - - Assert.equals(0, o.number); - } - - function test_var_mutation() { - final o = new FooExtern(); - - o.number = 7; - - Assert.equals(7, o.number); - } - - function test_static_var_access() { - Assert.equals(300, FooExtern.constNumber); - } - - function test_static_var_mutation() { - FooExtern.constNumber = 200; - - Assert.equals(200, FooExtern.constNumber); - - FooExtern.constNumber = 300; - } - - function test_function_call() { - final o = new FooExtern(); - - o.number = 7; - - Assert.equals(14, o.doubleNumber()); - } - - function test_static_function_call() { - final o = FooExtern.create(7); - - Assert.notNull(o); - } - - function test_to_string() { - final o = new FooExtern(); - - Assert.equals("fooextern", Std.string(o)); - } - - function test_standard_naming() { - final o = StandardLayoutExtern.create(); - - Assert.equals(14, o.doubleNumber(7)); - } - - function test_null_access() { - final o : FooExtern = null; - - Assert.raises(() -> o.number = 7); - } - - function test_function_closures() { - final o = new WithClosure(); - final f = o.returnSeven; - - Assert.equals(7, f()); - } - - // function test_reflection() { - // // - // } -} \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx new file mode 100644 index 000000000..50194966b --- /dev/null +++ b/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx @@ -0,0 +1,133 @@ +package tests.marshalling.managed; + +import utest.Assert; +import utest.Test; + +@:include('Managed.hpp') +@:cpp.ManagedType({ type : 'standard_naming_obj', namespace : [ 'foo', 'bar' ] }) +extern class NonStandardNamingExtern { + static var constNumber : Int; + + var number : Int; + + function new() : Void; + + function multiply(input : Int) : Int; + + static function create(number : Int) : NonStandardNamingExtern; +} + +// @:include('Managed.hpp') +// @:cpp.ManagedType({ type : 'standard_naming', namespace : [ 'foo', 'bar' ], flags : [ StandardNaming ] }) +// extern class StandardNamingExtern { +// function doubleNumber(input : Int) : Int; + +// static function create() : StandardNamingExtern; +// } + +// @:include('Managed.hpp') +// @:cpp.ManagedType({ namespace : [ 'hx' ] }) +// extern class WithClosure { +// function new() : Void; + +// @:native('ReturnSeven') +// function returnSeven() : Int; +// } + +class TestLocalNonStandardManagedClass extends Test { + + function test_null_object() { + final o : NonStandardNamingExtern = null; + + Assert.isNull(o); + } + + function test_construction() { + final o = new NonStandardNamingExtern(); + + Assert.notNull(o); + } + + function test_equality() { + final o1 = new NonStandardNamingExtern(); + final o2 = o1; + + Assert.equals(o1, o2); + } + + function test_inequality() { + final o1 = new NonStandardNamingExtern(); + final o2 = new NonStandardNamingExtern(); + + Assert.notEquals(o1, o2); + } + + function test_var_access() { + final o = new NonStandardNamingExtern(); + + Assert.equals(0, o.number); + } + + function test_var_mutation() { + final o = new NonStandardNamingExtern(); + + o.number = 7; + + Assert.equals(7, o.number); + } + + function test_static_var_access() { + Assert.equals(300, NonStandardNamingExtern.constNumber); + } + + function test_static_var_mutation() { + NonStandardNamingExtern.constNumber = 200; + + Assert.equals(200, NonStandardNamingExtern.constNumber); + + NonStandardNamingExtern.constNumber = 300; + } + + function test_function_call() { + final o = new NonStandardNamingExtern(); + + o.number = 7; + + Assert.equals(14, o.multiply(2)); + } + + function test_static_function_call() { + final o = NonStandardNamingExtern.create(7); + + Assert.notNull(o); + } + + function test_to_string() { + final o = new NonStandardNamingExtern(); + + Assert.equals("My Custom Managed Type", Std.string(o)); + } + + function test_null_access() { + final o : NonStandardNamingExtern = null; + + Assert.raises(() -> o.number = 7); + } + + // function test_type_check() { + // final o : Any = new NonStandardNamingExtern(); + + // Assert.isTrue(o is NonStandardNamingExtern); + // } + + // function test_function_closures() { + // final o = new WithClosure(); + // final f = o.returnSeven; + + // Assert.equals(7, f()); + // } + + // function test_reflection() { + // // + // } +} \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx new file mode 100644 index 000000000..474ac8389 --- /dev/null +++ b/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx @@ -0,0 +1,116 @@ +package tests.marshalling.managed; + +import utest.Assert; +import utest.Test; + +@:include('Managed.hpp') +@:cpp.ManagedType({ type : 'standard_naming', namespace : [ 'foo', 'bar' ], flags : [ StandardNaming ] }) +extern class StandardNamingExtern { + static var constNumber : Int; + + var number : Int; + + function new() : Void; + + function multiply(input : Int) : Int; + + static function create(number : Int) : StandardNamingExtern; +} + +class TestLocalStandardManagedClass extends Test { + + function test_null_object() { + final o : StandardNamingExtern = null; + + Assert.isNull(o); + } + + function test_construction() { + final o = new StandardNamingExtern(); + + Assert.notNull(o); + } + + function test_equality() { + final o1 = new StandardNamingExtern(); + final o2 = o1; + + Assert.equals(o1, o2); + } + + function test_inequality() { + final o1 = new StandardNamingExtern(); + final o2 = new StandardNamingExtern(); + + Assert.notEquals(o1, o2); + } + + function test_var_access() { + final o = new StandardNamingExtern(); + + Assert.equals(0, o.number); + } + + function test_var_mutation() { + final o = new StandardNamingExtern(); + + o.number = 7; + + Assert.equals(7, o.number); + } + + function test_static_var_access() { + Assert.equals(300, StandardNamingExtern.constNumber); + } + + function test_static_var_mutation() { + StandardNamingExtern.constNumber = 200; + + Assert.equals(200, StandardNamingExtern.constNumber); + + StandardNamingExtern.constNumber = 300; + } + + function test_function_call() { + final o = new StandardNamingExtern(); + + o.number = 7; + + Assert.equals(14, o.multiply(2)); + } + + function test_static_function_call() { + final o = StandardNamingExtern.create(7); + + Assert.notNull(o); + } + + function test_to_string() { + final o = new StandardNamingExtern(); + + Assert.equals("My Custom Managed Type", Std.string(o)); + } + + function test_null_access() { + final o : StandardNamingExtern = null; + + Assert.raises(() -> o.number = 7); + } + + // function test_type_check() { + // final o : Any = new NonStandardNamingExtern(); + + // Assert.isTrue(o is NonStandardNamingExtern); + // } + + // function test_function_closures() { + // final o = new WithClosure(); + // final f = o.returnSeven; + + // Assert.equals(7, f()); + // } + + // function test_reflection() { + // // + // } +} \ No newline at end of file diff --git a/test/native/tests/marshalling/native/Managed.cpp b/test/native/tests/marshalling/native/Managed.cpp index cbd6f9323..b163e54bb 100644 --- a/test/native/tests/marshalling/native/Managed.cpp +++ b/test/native/tests/marshalling/native/Managed.cpp @@ -1,45 +1,22 @@ #include #include -int hx::fooextern::constNumber = 300; +int foo::bar::standard_naming_obj::constNumber = 300; -hx::fooextern::fooextern() {} +foo::bar::standard_naming_obj::standard_naming_obj() : number(0) {} +foo::bar::standard_naming_obj::standard_naming_obj(int inNumber) : number(inNumber) {} -int hx::fooextern::doubleNumber() +int foo::bar::standard_naming_obj::multiply(int input) { - return number * 2; + return number * input; } -::String hx::fooextern::toString() +::String foo::bar::standard_naming_obj::toString() { - return ::String::create("fooextern"); + return ::String::create("My Custom Managed Type"); } -hx::fooextern* hx::fooextern::create(int number) +foo::bar::standard_naming_obj* foo::bar::standard_naming_obj::create(int inNumber) { - auto ptr = new hx::fooextern(); - - ptr->number = number; - - return ptr; -} - -int hx::WithClosure::ReturnSeven() -{ - return 7; -} - -int foo::bar::StandardLayoutExtern_obj::doubleNumber(int input) -{ - return input * 2; -} - -foo::bar::StandardLayoutExtern foo::bar::StandardLayoutExtern_obj::create() -{ - return foo::bar::StandardLayoutExtern(new StandardLayoutExtern_obj()); -} - -namespace hx -{ - HX_DEFINE_DYNAMIC_FUNC0(WithClosure, ReturnSeven, return) + return new foo::bar::standard_naming_obj(inNumber); } \ No newline at end of file diff --git a/test/native/tests/marshalling/native/Managed.hpp b/test/native/tests/marshalling/native/Managed.hpp index 00477ea07..a7a2886f2 100644 --- a/test/native/tests/marshalling/native/Managed.hpp +++ b/test/native/tests/marshalling/native/Managed.hpp @@ -1,34 +1,26 @@ #pragma once -HX_DECLARE_CLASS2(foo,bar,StandardLayoutExtern) +HX_DECLARE_CLASS2(foo,bar,standard_naming) namespace foo { namespace bar { - struct StandardLayoutExtern_obj : public ::hx::Object { - virtual int doubleNumber(int input); + struct standard_naming_obj : public ::hx::Object { + static int constNumber; - static StandardLayoutExtern create(); - }; - } -} - -namespace hx -{ - struct fooextern : public ::hx::Object { - static int constNumber; + int number; - int number; + standard_naming_obj(); + standard_naming_obj(int inNumber); - fooextern(); + int multiply(int input); - int doubleNumber(); + ::String toString() override; - ::String toString() override; - - static fooextern* create(int number); - }; + static standard_naming_obj* create(int inNumber); + }; + } struct WithClosure : public ::hx::Object { int ReturnSeven(); From 1354a5698ab4353bed0fb509c192a5082adba57a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 2 Feb 2025 14:05:57 +0000 Subject: [PATCH 37/89] reduce test duplication --- .../marshalling/managed/TestLocalHarness.hx | 102 ++++++++++++++++++ .../TestLocalNonStandardManagedClass.hx | 97 +---------------- .../managed/TestLocalStandardManagedClass.hx | 80 +------------- 3 files changed, 104 insertions(+), 175 deletions(-) create mode 100644 test/native/tests/marshalling/managed/TestLocalHarness.hx diff --git a/test/native/tests/marshalling/managed/TestLocalHarness.hx b/test/native/tests/marshalling/managed/TestLocalHarness.hx new file mode 100644 index 000000000..c11899ba5 --- /dev/null +++ b/test/native/tests/marshalling/managed/TestLocalHarness.hx @@ -0,0 +1,102 @@ +package tests.marshalling.managed; + +import haxe.Constraints; +import utest.Assert; +import utest.Test; + +private typedef TestType = { + public var number : Int; + + public function multiply(input : Int) : Int; +} + +@:generic class TestLocalHarnessVoid> & TestType> extends Test { + + function test_null_object() { + final o : T = null; + + Assert.isNull(o); + } + + function test_construction() { + final o = new T(); + + Assert.notNull(o); + } + + function test_equality() { + final o1 = new T(); + final o2 = o1; + + Assert.equals(o1, o2); + } + + function test_inequality() { + final o1 = new T(); + final o2 = new T(); + + Assert.notEquals(o1, o2); + } + + function test_var_access() { + final o = new T(); + + Assert.equals(0, o.number); + } + + function test_var_mutation() { + final o = new T(); + + o.number = 7; + + Assert.equals(7, o.number); + } + + function test_function_call() { + final o = new T(); + + o.number = 7; + + Assert.equals(14, o.multiply(2)); + } + + function test_to_string() { + final o = new T(); + + Assert.equals("My Custom Managed Type", Std.string(o)); + } + + function test_null_access() { + final o : T = null; + + Assert.raises(() -> o.number = 7); + } + + function test_casting() { + function create_as_any() : Any { + return new T(); + } + + final a = create_as_any(); + final o = (cast a : T); + + Assert.notNull(o); + } + + // function test_type_check() { + // final o : Any = new NonStandardNamingExtern(); + + // Assert.isTrue(o is NonStandardNamingExtern); + // } + + // function test_function_closures() { + // final o = new WithClosure(); + // final f = o.returnSeven; + + // Assert.equals(7, f()); + // } + + // function test_reflection() { + // // + // } +} \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx index 50194966b..7939ded25 100644 --- a/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx +++ b/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx @@ -17,65 +17,7 @@ extern class NonStandardNamingExtern { static function create(number : Int) : NonStandardNamingExtern; } -// @:include('Managed.hpp') -// @:cpp.ManagedType({ type : 'standard_naming', namespace : [ 'foo', 'bar' ], flags : [ StandardNaming ] }) -// extern class StandardNamingExtern { -// function doubleNumber(input : Int) : Int; - -// static function create() : StandardNamingExtern; -// } - -// @:include('Managed.hpp') -// @:cpp.ManagedType({ namespace : [ 'hx' ] }) -// extern class WithClosure { -// function new() : Void; - -// @:native('ReturnSeven') -// function returnSeven() : Int; -// } - -class TestLocalNonStandardManagedClass extends Test { - - function test_null_object() { - final o : NonStandardNamingExtern = null; - - Assert.isNull(o); - } - - function test_construction() { - final o = new NonStandardNamingExtern(); - - Assert.notNull(o); - } - - function test_equality() { - final o1 = new NonStandardNamingExtern(); - final o2 = o1; - - Assert.equals(o1, o2); - } - - function test_inequality() { - final o1 = new NonStandardNamingExtern(); - final o2 = new NonStandardNamingExtern(); - - Assert.notEquals(o1, o2); - } - - function test_var_access() { - final o = new NonStandardNamingExtern(); - - Assert.equals(0, o.number); - } - - function test_var_mutation() { - final o = new NonStandardNamingExtern(); - - o.number = 7; - - Assert.equals(7, o.number); - } - +class TestLocalNonStandardManagedClass extends TestLocalHarness { function test_static_var_access() { Assert.equals(300, NonStandardNamingExtern.constNumber); } @@ -88,46 +30,9 @@ class TestLocalNonStandardManagedClass extends Test { NonStandardNamingExtern.constNumber = 300; } - function test_function_call() { - final o = new NonStandardNamingExtern(); - - o.number = 7; - - Assert.equals(14, o.multiply(2)); - } - function test_static_function_call() { final o = NonStandardNamingExtern.create(7); Assert.notNull(o); } - - function test_to_string() { - final o = new NonStandardNamingExtern(); - - Assert.equals("My Custom Managed Type", Std.string(o)); - } - - function test_null_access() { - final o : NonStandardNamingExtern = null; - - Assert.raises(() -> o.number = 7); - } - - // function test_type_check() { - // final o : Any = new NonStandardNamingExtern(); - - // Assert.isTrue(o is NonStandardNamingExtern); - // } - - // function test_function_closures() { - // final o = new WithClosure(); - // final f = o.returnSeven; - - // Assert.equals(7, f()); - // } - - // function test_reflection() { - // // - // } } \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx index 474ac8389..18660d8ea 100644 --- a/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx +++ b/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx @@ -17,48 +17,7 @@ extern class StandardNamingExtern { static function create(number : Int) : StandardNamingExtern; } -class TestLocalStandardManagedClass extends Test { - - function test_null_object() { - final o : StandardNamingExtern = null; - - Assert.isNull(o); - } - - function test_construction() { - final o = new StandardNamingExtern(); - - Assert.notNull(o); - } - - function test_equality() { - final o1 = new StandardNamingExtern(); - final o2 = o1; - - Assert.equals(o1, o2); - } - - function test_inequality() { - final o1 = new StandardNamingExtern(); - final o2 = new StandardNamingExtern(); - - Assert.notEquals(o1, o2); - } - - function test_var_access() { - final o = new StandardNamingExtern(); - - Assert.equals(0, o.number); - } - - function test_var_mutation() { - final o = new StandardNamingExtern(); - - o.number = 7; - - Assert.equals(7, o.number); - } - +class TestLocalStandardManagedClass extends TestLocalHarness { function test_static_var_access() { Assert.equals(300, StandardNamingExtern.constNumber); } @@ -71,46 +30,9 @@ class TestLocalStandardManagedClass extends Test { StandardNamingExtern.constNumber = 300; } - function test_function_call() { - final o = new StandardNamingExtern(); - - o.number = 7; - - Assert.equals(14, o.multiply(2)); - } - function test_static_function_call() { final o = StandardNamingExtern.create(7); Assert.notNull(o); } - - function test_to_string() { - final o = new StandardNamingExtern(); - - Assert.equals("My Custom Managed Type", Std.string(o)); - } - - function test_null_access() { - final o : StandardNamingExtern = null; - - Assert.raises(() -> o.number = 7); - } - - // function test_type_check() { - // final o : Any = new NonStandardNamingExtern(); - - // Assert.isTrue(o is NonStandardNamingExtern); - // } - - // function test_function_closures() { - // final o = new WithClosure(); - // final f = o.returnSeven; - - // Assert.equals(7, f()); - // } - - // function test_reflection() { - // // - // } } \ No newline at end of file From 18846ffcd944d4bb6bb92872f35d029a782a6a86 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 2 Feb 2025 15:52:57 +0000 Subject: [PATCH 38/89] Add tests for classes holding managed externs --- test/native/Native.hx | 4 +- .../managed/NonStandardNamingExtern.hx | 15 +++++ .../managed/StandardNamingExtern.hx | 15 +++++ .../marshalling/managed/TestClassHarness.hx | 60 +++++++++++++++++++ .../TestClassNonStandardManagedClass.hx | 5 ++ .../managed/TestClassStandardManagedClass.hx | 5 ++ .../marshalling/managed/TestLocalHarness.hx | 11 +++- .../TestLocalNonStandardManagedClass.hx | 15 ----- .../managed/TestLocalStandardManagedClass.hx | 15 ----- 9 files changed, 113 insertions(+), 32 deletions(-) create mode 100644 test/native/tests/marshalling/managed/NonStandardNamingExtern.hx create mode 100644 test/native/tests/marshalling/managed/StandardNamingExtern.hx create mode 100644 test/native/tests/marshalling/managed/TestClassHarness.hx create mode 100644 test/native/tests/marshalling/managed/TestClassNonStandardManagedClass.hx create mode 100644 test/native/tests/marshalling/managed/TestClassStandardManagedClass.hx diff --git a/test/native/Native.hx b/test/native/Native.hx index 5ce1ab098..229fc7b6f 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -39,7 +39,9 @@ class Native new tests.marshalling.pointers.TestAbstractPointer(), new tests.marshalling.pointers.TestPointerInterop(), new tests.marshalling.managed.TestLocalNonStandardManagedClass(), - new tests.marshalling.managed.TestLocalStandardManagedClass() + new tests.marshalling.managed.TestLocalStandardManagedClass(), + new tests.marshalling.managed.TestClassNonStandardManagedClass(), + new tests.marshalling.managed.TestClassStandardManagedClass() #end ]); } diff --git a/test/native/tests/marshalling/managed/NonStandardNamingExtern.hx b/test/native/tests/marshalling/managed/NonStandardNamingExtern.hx new file mode 100644 index 000000000..0976448c8 --- /dev/null +++ b/test/native/tests/marshalling/managed/NonStandardNamingExtern.hx @@ -0,0 +1,15 @@ +package tests.marshalling.managed; + +@:include('Managed.hpp') +@:cpp.ManagedType({type: 'standard_naming_obj', namespace: ['foo', 'bar']}) +extern class NonStandardNamingExtern { + static var constNumber:Int; + + var number:Int; + + function new():Void; + + function multiply(input:Int):Int; + + static function create(number:Int):NonStandardNamingExtern; +} diff --git a/test/native/tests/marshalling/managed/StandardNamingExtern.hx b/test/native/tests/marshalling/managed/StandardNamingExtern.hx new file mode 100644 index 000000000..b5550b7f1 --- /dev/null +++ b/test/native/tests/marshalling/managed/StandardNamingExtern.hx @@ -0,0 +1,15 @@ +package tests.marshalling.managed; + +@:include('Managed.hpp') +@:cpp.ManagedType({type: 'standard_naming', namespace: ['foo', 'bar'], flags: [StandardNaming]}) +extern class StandardNamingExtern { + static var constNumber:Int; + + var number:Int; + + function new():Void; + + function multiply(input:Int):Int; + + static function create(number:Int):StandardNamingExtern; +} diff --git a/test/native/tests/marshalling/managed/TestClassHarness.hx b/test/native/tests/marshalling/managed/TestClassHarness.hx new file mode 100644 index 000000000..4e6bf3166 --- /dev/null +++ b/test/native/tests/marshalling/managed/TestClassHarness.hx @@ -0,0 +1,60 @@ +package tests.marshalling.managed; + +import haxe.Constraints; +import utest.Assert; +import utest.Test; + +private typedef TestType = { + public var number : Int; + + public function multiply(input : Int) : Int; +} + +@:generic private class FooVoid> & TestType> { + public var o : T; + + public function new() { + o = new T(); + } +} + +@:generic class TestClassHarnessVoid> & TestType> extends Test { + function test_construction() { + final c = new Foo(); + + Assert.notNull(c.o); + } + + function test_var_access() { + final c = new Foo(); + + Assert.equals(0, c.o.number); + } + + function test_var_mutation() { + final c = new Foo(); + + c.o.number = 7; + + Assert.equals(7, c.o.number); + } + + function test_reassignment() { + final c = new Foo(); + final o = new T(); + + o.number = 100; + + c.o = o; + + Assert.equals(100, c.o.number); + } + + function test_function_call() { + final c = new Foo(); + + c.o.number = 7; + + Assert.equals(14, c.o.multiply(2)); + } +} \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestClassNonStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestClassNonStandardManagedClass.hx new file mode 100644 index 000000000..ca9010571 --- /dev/null +++ b/test/native/tests/marshalling/managed/TestClassNonStandardManagedClass.hx @@ -0,0 +1,5 @@ +package tests.marshalling.managed; + +class TestClassNonStandardManagedClass extends TestClassHarness { + +} \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestClassStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestClassStandardManagedClass.hx new file mode 100644 index 000000000..e456edaf3 --- /dev/null +++ b/test/native/tests/marshalling/managed/TestClassStandardManagedClass.hx @@ -0,0 +1,5 @@ +package tests.marshalling.managed; + +class TestClassStandardManagedClass extends TestClassHarness { + // +} \ No newline at end of file diff --git a/test/native/tests/marshalling/managed/TestLocalHarness.hx b/test/native/tests/marshalling/managed/TestLocalHarness.hx index c11899ba5..4cd970853 100644 --- a/test/native/tests/marshalling/managed/TestLocalHarness.hx +++ b/test/native/tests/marshalling/managed/TestLocalHarness.hx @@ -11,7 +11,6 @@ private typedef TestType = { } @:generic class TestLocalHarnessVoid> & TestType> extends Test { - function test_null_object() { final o : T = null; @@ -83,6 +82,16 @@ private typedef TestType = { Assert.notNull(o); } + function test_anon() { + function create_anon() { + return { o : new T() }; + } + + final a = create_anon(); + + Assert.notNull(a.o); + } + // function test_type_check() { // final o : Any = new NonStandardNamingExtern(); diff --git a/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx index 7939ded25..fad9840ce 100644 --- a/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx +++ b/test/native/tests/marshalling/managed/TestLocalNonStandardManagedClass.hx @@ -1,21 +1,6 @@ package tests.marshalling.managed; import utest.Assert; -import utest.Test; - -@:include('Managed.hpp') -@:cpp.ManagedType({ type : 'standard_naming_obj', namespace : [ 'foo', 'bar' ] }) -extern class NonStandardNamingExtern { - static var constNumber : Int; - - var number : Int; - - function new() : Void; - - function multiply(input : Int) : Int; - - static function create(number : Int) : NonStandardNamingExtern; -} class TestLocalNonStandardManagedClass extends TestLocalHarness { function test_static_var_access() { diff --git a/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx b/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx index 18660d8ea..b6244c3ad 100644 --- a/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx +++ b/test/native/tests/marshalling/managed/TestLocalStandardManagedClass.hx @@ -1,21 +1,6 @@ package tests.marshalling.managed; import utest.Assert; -import utest.Test; - -@:include('Managed.hpp') -@:cpp.ManagedType({ type : 'standard_naming', namespace : [ 'foo', 'bar' ], flags : [ StandardNaming ] }) -extern class StandardNamingExtern { - static var constNumber : Int; - - var number : Int; - - function new() : Void; - - function multiply(input : Int) : Int; - - static function create(number : Int) : StandardNamingExtern; -} class TestLocalStandardManagedClass extends TestLocalHarness { function test_static_var_access() { From e8ac070409a7c993c020c948354f61ca88c8a4e8 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 2 Feb 2025 21:47:30 +0000 Subject: [PATCH 39/89] change tests so that static functions are tested --- test/native/tests/marshalling/Context.hx | 1 - .../tests/marshalling/classes/TestValueTypeInterop.hx | 7 +++---- test/native/tests/marshalling/native/ctx.cpp | 4 ++-- test/native/tests/marshalling/native/ctx.hpp | 6 +++--- test/native/tests/marshalling/native/point.cpp | 2 +- test/native/tests/marshalling/native/point.hpp | 6 +++--- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/test/native/tests/marshalling/Context.hx b/test/native/tests/marshalling/Context.hx index 6008a5c74..2ee1965b9 100644 --- a/test/native/tests/marshalling/Context.hx +++ b/test/native/tests/marshalling/Context.hx @@ -4,7 +4,6 @@ package tests.marshalling; @:include('ctx.hpp') @:cpp.PointerType({ type : 'ctx' }) extern class Context { - @:native('create') public static function create() : Context; @:native('create_null') diff --git a/test/native/tests/marshalling/classes/TestValueTypeInterop.hx b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx index d59f20686..762e6a44c 100644 --- a/test/native/tests/marshalling/classes/TestValueTypeInterop.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx @@ -17,6 +17,8 @@ private extern class Point { @:overload(function(_x : Float, _y : Float) : Void {}) function new(); + + static function point_vec(v:StdVector):Void; } private extern class NativeFunctions { @@ -28,9 +30,6 @@ private extern class NativeFunctions { @:native('vec_by_ptr') static function vec_by_ptr(v:StdVector):Void; - - @:native('point_vec') - static function point_vec(v:StdVector):Void; } private class HaxeFunctions { @@ -234,7 +233,7 @@ class TestValueTypeInterop extends Test { function test_vec_of_points() { final v = new StdVector(5); - NativeFunctions.point_vec(v); + Point.point_vec(v); Assert.equals(300f64, v.at(0).x); } diff --git a/test/native/tests/marshalling/native/ctx.cpp b/test/native/tests/marshalling/native/ctx.cpp index 8898cda00..79a8ad596 100644 --- a/test/native/tests/marshalling/native/ctx.cpp +++ b/test/native/tests/marshalling/native/ctx.cpp @@ -6,11 +6,11 @@ int ctx::Double() { return number * 2; } -ctx* create() { +ctx* ctx::create() { return new ctx(); } -ctx* create_null() { +ctx* ctx::create_null() { return nullptr; } diff --git a/test/native/tests/marshalling/native/ctx.hpp b/test/native/tests/marshalling/native/ctx.hpp index 586e8f5a0..089460d37 100644 --- a/test/native/tests/marshalling/native/ctx.hpp +++ b/test/native/tests/marshalling/native/ctx.hpp @@ -6,10 +6,10 @@ struct ctx { ctx(); int Double(); -}; -ctx* create(); -ctx* create_null(); + static ctx* create(); + static ctx* create_null(); +}; void ctx_ptr(ctx* pCtx); void ctx_ptr_ptr(ctx** ppCtx); diff --git a/test/native/tests/marshalling/native/point.cpp b/test/native/tests/marshalling/native/point.cpp index ca2e19756..fc97b389d 100644 --- a/test/native/tests/marshalling/native/point.cpp +++ b/test/native/tests/marshalling/native/point.cpp @@ -3,6 +3,6 @@ hx::maths::point::point(double _x, double _y) : x(_x), y(_y) {} -void point_vec(std::vector<::hx::maths::point>& v) { +void ::hx::maths::point::point_vec(std::vector<::hx::maths::point>& v) { v[0].x = 300; } \ No newline at end of file diff --git a/test/native/tests/marshalling/native/point.hpp b/test/native/tests/marshalling/native/point.hpp index cae68c314..241d470be 100644 --- a/test/native/tests/marshalling/native/point.hpp +++ b/test/native/tests/marshalling/native/point.hpp @@ -9,8 +9,8 @@ namespace hx { point() = default; point(double _x, double _y); + + static void point_vec(std::vector<::hx::maths::point>& v); }; } -} - -void point_vec(std::vector<::hx::maths::point>& v); \ No newline at end of file +} \ No newline at end of file From 7dbc2ad82040b9ecdbe6da7e26e8c2dd4e548e31 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 2 Feb 2025 21:48:28 +0000 Subject: [PATCH 40/89] un-private point --- test/native/tests/marshalling/Point.hx | 14 ++++++++++++++ .../marshalling/classes/TestValueTypeInterop.hx | 13 ------------- 2 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 test/native/tests/marshalling/Point.hx diff --git a/test/native/tests/marshalling/Point.hx b/test/native/tests/marshalling/Point.hx new file mode 100644 index 000000000..e56bc1cc4 --- /dev/null +++ b/test/native/tests/marshalling/Point.hx @@ -0,0 +1,14 @@ +package tests.marshalling; + +@:semantics(reference) +@:include('point.hpp') +@:cpp.ValueType({ type : 'point', namespace : [ 'hx', 'maths' ] }) +extern class Point { + var x : Float; + var y : Float; + + @:overload(function(_x : Float, _y : Float) : Void {}) + function new(); + + static function point_vec(v:StdVector):Void; +} \ No newline at end of file diff --git a/test/native/tests/marshalling/classes/TestValueTypeInterop.hx b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx index 762e6a44c..ae3fceddc 100644 --- a/test/native/tests/marshalling/classes/TestValueTypeInterop.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx @@ -8,19 +8,6 @@ import cpp.RawPointer; import utest.Assert; import utest.Test; -@:semantics(reference) -@:include('point.hpp') -@:cpp.ValueType({ type : 'point', namespace : [ 'hx', 'maths' ] }) -private extern class Point { - var x : Float; - var y : Float; - - @:overload(function(_x : Float, _y : Float) : Void {}) - function new(); - - static function point_vec(v:StdVector):Void; -} - private extern class NativeFunctions { @:native('vec_by_val') static function vec_by_val(v:StdVector):Void; From bf54265f4fe9fa337928597e2b4ab69e0efb3666 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 3 Feb 2025 17:50:23 +0000 Subject: [PATCH 41/89] let enum abstract include meta handle it --- test/native/compile.hxml | 2 +- .../native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx | 1 - .../tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/native/compile.hxml b/test/native/compile.hxml index 76d71c20f..a063c9266 100644 --- a/test/native/compile.hxml +++ b/test/native/compile.hxml @@ -1,4 +1,4 @@ -m Native -L utest ---debug +-D HXCPP-DEBUGGER --cpp bin \ No newline at end of file diff --git a/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx b/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx index 7c76c8375..3059de820 100644 --- a/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx +++ b/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx @@ -17,7 +17,6 @@ private extern enum abstract Colour(Int) { var Blue; } -@:headerInclude('colour.hpp') class TestValueTypeEnumAbstract extends Test { function test_switching_on_uncaptured_enum() { final e = Colour.Green; diff --git a/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx b/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx index 8f639585e..ed68a9980 100644 --- a/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx +++ b/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx @@ -12,7 +12,6 @@ private extern enum abstract Numbers(Int) { var Three; } -@:headerInclude('Numbers.hpp') class TestValueTypeEnumClassAbstract extends Test { function test_switching_on_uncaptured_enum() { final e = Numbers.Two; From 8eb9888dbec05f489b95c5ea85509b8a9286b0af Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 3 Feb 2025 17:57:21 +0000 Subject: [PATCH 42/89] remove analyser meta --- test/native/tests/marshalling/classes/TestLocalValueType.hx | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/native/tests/marshalling/classes/TestLocalValueType.hx b/test/native/tests/marshalling/classes/TestLocalValueType.hx index 2ba6702a4..dc694d60f 100644 --- a/test/native/tests/marshalling/classes/TestLocalValueType.hx +++ b/test/native/tests/marshalling/classes/TestLocalValueType.hx @@ -74,7 +74,6 @@ class TestLocalValueType extends Test { Assert.notNull(v2); } - @:analyzer(no_local_dce) function test_nullable_var_null_to_non_null() { final v1 : Null> = null; @@ -91,14 +90,12 @@ class TestLocalValueType extends Test { }); } - @:analyzer(no_local_dce) function test_initialising_non_null_var_to_null() { Assert.raises(() -> { var _ : StdVector = null; }); } - @:analyzer(no_local_dce) function test_initialising_non_null_var_to_dynamic_null() { function get_null() : Any { return null; From 7fcb9203ae2da9e01e82877232d7cac7122ec7bb Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 21 Mar 2025 21:57:46 +0000 Subject: [PATCH 43/89] Fix test related to recent pointer changes --- test/native/tests/marshalling/classes/TestValueTypeInterop.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/native/tests/marshalling/classes/TestValueTypeInterop.hx b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx index ae3fceddc..08e96231b 100644 --- a/test/native/tests/marshalling/classes/TestValueTypeInterop.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeInterop.hx @@ -190,7 +190,7 @@ class TestValueTypeInterop extends Test { function test_copying_from_pointer() { final src = new StdVector(10); final ptr = Pointer.addressOf(src); - final copy = ptr.value; + final copy : StdVector = ptr.value; copy.resize(100); From f6ecf8f45c2e2552c71b5a835b381775dc719e33 Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sun, 9 Nov 2025 13:33:14 +0000 Subject: [PATCH 44/89] Add pointer ctor overload --- include/cpp/Marshal.h | 7 +++++++ include/cpp/Pointer.h | 1 + test/RunTests.hx | 3 --- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 6f215ece7..0d14968af 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -646,4 +646,11 @@ inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::ValueRe return Pointer(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 +inline cpp::Pointer::Pointer(const ::cpp::marshal::PointerReference ref) +{ + ptr = *ref.ptr; +} + #endif \ No newline at end of file diff --git a/include/cpp/Pointer.h b/include/cpp/Pointer.h index 55db33a03..6ac2cb43f 100644 --- a/include/cpp/Pointer.h +++ b/include/cpp/Pointer.h @@ -215,6 +215,7 @@ class Pointer hx::Object *obj = inVariant.asObject(); ptr = obj ? (T*)inVariant.valObject->__GetHandle() : 0; } + inline Pointer(const ::cpp::marshal::PointerReference); template inline Pointer( const O *inValue ) : ptr( (T*) inValue) { } diff --git a/test/RunTests.hx b/test/RunTests.hx index 7a3a88c37..dd194fff9 100644 --- a/test/RunTests.hx +++ b/test/RunTests.hx @@ -195,9 +195,6 @@ class RunTests //run("opMatrix", opMatrix); run("haxe", runHaxe); run("telemetry", runTelemetry); -#if (haxe_ver >= 5) - run("marshalling", marshalling); -#end run("std32", std32); run("std64", std64); run("native", native); From 11bc87033e1597ef3b6f1d3b8938495045d0bc0e Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 15 Nov 2025 20:28:26 +0000 Subject: [PATCH 45/89] view marshalling type --- include/cpp/Marshal.h | 210 +++++++++++++++++++++++++++++++++++++++++- include/hxcpp.h | 1 + 2 files changed, 207 insertions(+), 4 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 0d14968af..2c052e7bd 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -2,6 +2,8 @@ #define CPP_MARSHAL_H #include +#include +#include namespace cpp { @@ -33,10 +35,6 @@ namespace cpp template class ValueType final { - // These true and false variants are called based on if T is a pointer - // If T is not a pointer trying to assign a value type to null results in a null pointer exception being thrown. - // But if T is a pointer then the value type holds a null pointer value. - static T FromReference(const ValueReference& inRHS); static T FromBoxed(const Boxed& inRHS); static T FromDynamic(const Dynamic& inRHS); @@ -131,6 +129,12 @@ namespace cpp bool operator==(const ValueReference& inRHS) const; bool operator!=(const ValueReference& inRHS) const; + + template + K get(int index); + + template + void set(int index, K value); }; template @@ -179,8 +183,185 @@ namespace cpp operator void**(); TPtr operator->() const; + + template + K get(int index); + + template + void set(int index, K value); + }; + + template + struct View final + { + ::cpp::Pointer ptr; + int length; + + View(::cpp::Pointer _ptr, int _length); + + void clear(); + void fill(T value); + bool isEmpty(); + View slice(int index); + View slice(int index, int length); + bool tryCopyTo(const View& destination); + template View reinterpret(); + + bool operator==(const View& inRHS) const; + bool operator!=(const View& inRHS) const; + + T& operator[] (int index); }; + + struct Marshal final + { + template + static T zero() { + return T(); + } + + template + static int size(T _) { + return sizeof(T); + } + + static View utf8ViewOfString(::String string); + static View wideViewOfString(::String string); + template static bool tryWrite(View view, T value); + template static T read(View view); + }; + } +} + +// + +inline cpp::marshal::View cpp::marshal::Marshal::utf8ViewOfString(::String string) +{ + auto length = int{ 0 }; + auto ptr = string.utf8_str(nullptr, true, &length); + + return View(reinterpret_cast(const_cast(ptr)), length); +} + +inline cpp::marshal::View cpp::marshal::Marshal::wideViewOfString(::String string) +{ + auto length = int{ 0 }; + auto ptr = string.wc_str(nullptr, &length); + + return View(reinterpret_cast(const_cast(ptr)), length); +} + +template +inline bool cpp::marshal::Marshal::tryWrite(View view, T value) +{ + auto requiredSize = sizeof(T); + if (requiredSize > view.length) + { + return false; + } + + std::memcpy(view.ptr, reinterpret_cast(&value), sizeof(T)); + + return true; +} + +template +inline T cpp::marshal::Marshal::read(View view) +{ + return reinterpret_cast(view.ptr); +} + +// + +template +inline cpp::marshal::View::View(::cpp::Pointer _ptr, int _length) : ptr(_ptr), length(_length) {} + +template +inline bool cpp::marshal::View::tryCopyTo(const View& destination) +{ + auto requiredSize = sizeof(T) * length; + if (destination.length < requiredSize) + { + return false; } + + std::memcpy(destination.ptr, ptr, requiredSize); + + return true; +} + +template +inline void cpp::marshal::View::clear() +{ + std::memset(ptr, 0, sizeof(T) * length); +} + +template +inline void cpp::marshal::View::fill(T value) +{ + for (auto i = 0; i < length; i++) + { + ptr[i] = value; + } +} + +template +inline bool cpp::marshal::View::isEmpty() +{ + return length == 0; +} + +template +inline cpp::marshal::View cpp::marshal::View::slice(int index) +{ + return View(ptr + index, length - index); +} + +template +inline cpp::marshal::View cpp::marshal::View::slice(int index, int length) +{ + return View(ptr + index, length); +} + +template +template +inline cpp::marshal::View cpp::marshal::View::reinterpret() +{ + auto newPtr = ::cpp::Pointer{ ptr.reinterpret() }; + auto fromSize = sizeof(T); + auto toSize = sizeof(K); + + if (toSize == fromSize) + { + return cpp::marshal::View(newPtr, length); + } + if (toSize < fromSize) + { + return cpp::marshal::View(newPtr, length * (fromSize / toSize)); + } + + auto shrink = static_cast(fromSize) / toSize; + auto newLength = static_cast(std::floor(length * shrink)); + + return cpp::marshal::View(newPtr, newLength); +} + +template +inline bool cpp::marshal::View::operator==(const View& inRHS) const +{ + return length == inRHS.length && ptr.ptr == inRHS.ptr.ptr; +} + +template +inline bool cpp::marshal::View::operator!=(const View& inRHS) const +{ + return length != inRHS.length || ptr.ptr != inRHS.ptr.ptr; +} + +template +inline T& cpp::marshal::View::operator[](int index) +{ + return ptr[index]; } // Boxed implementation @@ -272,6 +453,20 @@ template template inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} +template +template +inline K cpp::marshal::ValueReference::get(int index) +{ + return (*Super::ptr)[index]; +} + +template +template +inline void cpp::marshal::ValueReference::set(int index, K value) +{ + (*Super::ptr)[index] = value; +} + template inline cpp::marshal::ValueReference::ValueReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} @@ -398,6 +593,13 @@ template template inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} +template +template +inline void cpp::marshal::PointerReference::set(int index, K value) +{ + (*Super::ptr)[index] = value; +} + template inline cpp::marshal::PointerReference::PointerReference(const TPtr& inRHS) : Super(inRHS) {} diff --git a/include/hxcpp.h b/include/hxcpp.h index 4a1a6eeb5..9ece840f5 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -265,6 +265,7 @@ namespace cpp { namespace marshal { template class ValueType; } } namespace cpp { namespace marshal { template class ValueReference; } } namespace cpp { namespace marshal { template class PointerType; } } namespace cpp { namespace marshal { template class PointerReference; } } +namespace cpp { namespace marshal { template class View; } } template class Array_obj; template class Array; namespace hx { From 92aa55f8a546f812242bf0dcf32beab0047c295b Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sat, 15 Nov 2025 21:05:59 +0000 Subject: [PATCH 46/89] Change to value semantics --- test/native/Native.hx | 4 +++- test/native/tests/marshalling/Context.hx | 2 +- test/native/tests/marshalling/Point.hx | 2 +- test/native/tests/marshalling/StdVector.hx | 2 +- test/native/tests/marshalling/classes/TestInheritance.hx | 4 ++-- test/native/tests/marshalling/classes/TestValueTypeFields.hx | 4 ++-- .../tests/marshalling/enums/TestValueTypeEnumAbstract.hx | 2 +- .../tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx | 2 +- test/native/tests/marshalling/native/point.hpp | 2 +- .../tests/marshalling/pointers/TestInheritancePointers.hx | 4 ++-- test/native/tests/marshalling/pointers/TestPointerFields.hx | 4 ++-- 11 files changed, 17 insertions(+), 15 deletions(-) diff --git a/test/native/Native.hx b/test/native/Native.hx index 229fc7b6f..d9568ceea 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -41,7 +41,9 @@ class Native new tests.marshalling.managed.TestLocalNonStandardManagedClass(), new tests.marshalling.managed.TestLocalStandardManagedClass(), new tests.marshalling.managed.TestClassNonStandardManagedClass(), - new tests.marshalling.managed.TestClassStandardManagedClass() + new tests.marshalling.managed.TestClassStandardManagedClass(), + + new tests.marshalling.view.TestView() #end ]); } diff --git a/test/native/tests/marshalling/Context.hx b/test/native/tests/marshalling/Context.hx index 2ee1965b9..014899872 100644 --- a/test/native/tests/marshalling/Context.hx +++ b/test/native/tests/marshalling/Context.hx @@ -1,6 +1,6 @@ package tests.marshalling; -@:semantics(reference) +@:semantics(value) @:include('ctx.hpp') @:cpp.PointerType({ type : 'ctx' }) extern class Context { diff --git a/test/native/tests/marshalling/Point.hx b/test/native/tests/marshalling/Point.hx index e56bc1cc4..dda13f517 100644 --- a/test/native/tests/marshalling/Point.hx +++ b/test/native/tests/marshalling/Point.hx @@ -1,6 +1,6 @@ package tests.marshalling; -@:semantics(reference) +@:semantics(value) @:include('point.hpp') @:cpp.ValueType({ type : 'point', namespace : [ 'hx', 'maths' ] }) extern class Point { diff --git a/test/native/tests/marshalling/StdVector.hx b/test/native/tests/marshalling/StdVector.hx index 548f64678..0d6780582 100644 --- a/test/native/tests/marshalling/StdVector.hx +++ b/test/native/tests/marshalling/StdVector.hx @@ -3,7 +3,7 @@ package tests.marshalling; import cpp.Reference; @:include('vector') -@:semantics(reference) +@:semantics(value) @:cpp.ValueType({ type : 'vector', namespace : [ 'std' ] }) extern class StdVector implements ArrayAccess { @:overload(function ():Void {}) diff --git a/test/native/tests/marshalling/classes/TestInheritance.hx b/test/native/tests/marshalling/classes/TestInheritance.hx index 8a5bad273..805d2992d 100644 --- a/test/native/tests/marshalling/classes/TestInheritance.hx +++ b/test/native/tests/marshalling/classes/TestInheritance.hx @@ -3,14 +3,14 @@ package tests.marshalling.classes; import utest.Assert; import utest.Test; -@:semantics(reference) +@:semantics(value) @:include('Base.hpp') @:cpp.ValueType private extern class Base { function foo():Int; } -@:semantics(reference) +@:semantics(value) @:include('Child.hpp') @:cpp.ValueType private extern class Child extends Base { diff --git a/test/native/tests/marshalling/classes/TestValueTypeFields.hx b/test/native/tests/marshalling/classes/TestValueTypeFields.hx index cdf2cff6d..ca1076942 100644 --- a/test/native/tests/marshalling/classes/TestValueTypeFields.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeFields.hx @@ -3,7 +3,7 @@ package tests.marshalling.classes; import utest.Assert; import utest.Test; -@:semantics(reference) +@:semantics(value) @:include('point.hpp') @:cpp.ValueType({ type : 'point', namespace : [ 'hx', 'maths' ] }) private extern class Point { @@ -14,7 +14,7 @@ private extern class Point { function new(); } -@:semantics(reference) +@:semantics(value) @:include('holder.hpp') @:cpp.ValueType({ type : 'holder', namespace : [] }) private extern class Holder { diff --git a/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx b/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx index 3059de820..6dc5c55d0 100644 --- a/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx +++ b/test/native/tests/marshalling/enums/TestValueTypeEnumAbstract.hx @@ -3,7 +3,7 @@ package tests.marshalling.enums; import utest.Assert; import utest.Test; -@:semantics(reference) +@:semantics(value) @:include('colour.hpp') @:cpp.ValueType({ type : 'colour' }) private extern enum abstract Colour(Int) { diff --git a/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx b/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx index ed68a9980..af0f29e7d 100644 --- a/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx +++ b/test/native/tests/marshalling/enums/TestValueTypeEnumClassAbstract.hx @@ -3,7 +3,7 @@ package tests.marshalling.enums; import utest.Assert; import utest.Test; -@:semantics(reference) +@:semantics(value) @:include('Numbers.hpp') @:cpp.ValueType({ namespace : [ 'foo' ] }) private extern enum abstract Numbers(Int) { diff --git a/test/native/tests/marshalling/native/point.hpp b/test/native/tests/marshalling/native/point.hpp index 241d470be..1feb3366d 100644 --- a/test/native/tests/marshalling/native/point.hpp +++ b/test/native/tests/marshalling/native/point.hpp @@ -10,7 +10,7 @@ namespace hx { point() = default; point(double _x, double _y); - static void point_vec(std::vector<::hx::maths::point>& v); + static void point_vec(::std::vector<::hx::maths::point>& v); }; } } \ No newline at end of file diff --git a/test/native/tests/marshalling/pointers/TestInheritancePointers.hx b/test/native/tests/marshalling/pointers/TestInheritancePointers.hx index 0db1bb22d..91c83a6d5 100644 --- a/test/native/tests/marshalling/pointers/TestInheritancePointers.hx +++ b/test/native/tests/marshalling/pointers/TestInheritancePointers.hx @@ -3,14 +3,14 @@ package tests.marshalling.pointers; import utest.Assert; import utest.Test; -@:semantics(reference) +@:semantics(value) @:include('Base.hpp') @:cpp.PointerType private extern class Base { function foo():Int; } -@:semantics(reference) +@:semantics(value) @:include('Child.hpp') @:cpp.PointerType private extern class Child extends Base { diff --git a/test/native/tests/marshalling/pointers/TestPointerFields.hx b/test/native/tests/marshalling/pointers/TestPointerFields.hx index 19ad20091..3b0fde545 100644 --- a/test/native/tests/marshalling/pointers/TestPointerFields.hx +++ b/test/native/tests/marshalling/pointers/TestPointerFields.hx @@ -3,7 +3,7 @@ package tests.marshalling.pointers; import utest.Assert; import utest.Test; -@:semantics(reference) +@:semantics(value) @:include('point.hpp') @:cpp.PointerType({ type : 'point', namespace : [ 'hx', 'maths' ] }) private extern class Point { @@ -11,7 +11,7 @@ private extern class Point { var y : Float; } -@:semantics(reference) +@:semantics(value) @:include('holder.hpp') @:cpp.ValueType({ type : 'holder', namespace : [] }) private extern class Holder { From e655568e1bd695886cfa03f805938b13f6215825 Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sat, 15 Nov 2025 21:06:08 +0000 Subject: [PATCH 47/89] Add view tests --- .../native/tests/marshalling/view/TestView.hx | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 test/native/tests/marshalling/view/TestView.hx diff --git a/test/native/tests/marshalling/view/TestView.hx b/test/native/tests/marshalling/view/TestView.hx new file mode 100644 index 000000000..7853a139f --- /dev/null +++ b/test/native/tests/marshalling/view/TestView.hx @@ -0,0 +1,206 @@ +package tests.marshalling.view; + +import cpp.Int64; +import cpp.UInt32; +import cpp.Int16; +import cpp.Pointer; +import cpp.marshal.View; +import utest.Test; +import utest.Assert; +import tests.marshalling.Point; + +class TestView extends Test { + function test_reading_ints() { + final buffer = [ for (i in 0...10) i + 1 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + + for (i in 0...10) { + Assert.equals(i + 1, view[i]); + } + } + + function test_writing_ints() { + final buffer = [ for (_ in 0...10) 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + + for (i in 0...10) { + view[i] = i + 1; + } + + Assert.same([ for (i in 0...buffer.length) i + 1 ], buffer); + } + + function test_reading_value_types() { + final buffer = new Point(0, 0); + final view = new View(Pointer.addressOf(buffer), 1); + final point = view[0]; + + Assert.equals(0f64, point.x); + Assert.equals(0f64, point.y); + + buffer.x = 200; + buffer.y = 300; + + Assert.notEquals(buffer.x, point.x); + Assert.notEquals(buffer.y, point.y); + } + + function test_writing_value_types() { + final buffer = new Point(0, 0); + final view = new View(Pointer.addressOf(buffer), 1); + final point = new Point(); + + view[0] = point; + + Assert.equals(buffer.x, point.x); + Assert.equals(buffer.y, point.y); + + point.x = 200; + point.y = 300; + + Assert.notEquals(buffer.x, point.x); + Assert.notEquals(buffer.y, point.y); + } + + function test_reading_value_type_fields() { + final point = new Point(); + final view = new View(Pointer.addressOf(point), 1); + + Assert.equals( 7f64, view[0].x); + Assert.equals(26f64, view[0].y); + } + + function test_writing_value_type_fields() { + final point = new Point(); + final view = new View(Pointer.addressOf(point), 1); + + view[0].x = 8; + view[0].y = 40; + + Assert.equals( 8f64, point.x); + Assert.equals(40f64, point.y); + } + + function test_slice() { + final buffer = [ for (i in 0...10) i + 1 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final index = 3; + final slice = view.slice(index); + + if (Assert.equals(7, slice.length)) { + for (i in 0...slice.length) { + Assert.equals(i + index + 1, slice[i]); + } + } + } + + function test_slice_with_length() { + final buffer = [ for (i in 0...10) i + 1 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final index = 3; + final length = 4; + final slice = view.slice(index, length); + + if (Assert.equals(length, slice.length)) { + for (i in 0...slice.length) { + Assert.equals(i + index + 1, slice[i]); + } + } + } + + function test_clear() { + final buffer = [ for (_ in 0...10) 8 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + + view.slice(2, 6).clear(); + + Assert.same([ 8, 8, 0, 0, 0, 0, 0, 0, 8, 8 ], buffer); + } + + function test_fill() { + final buffer = [ for (_ in 0...10) 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final value = 8; + + view.slice(2, 6).fill(value); + + Assert.same([ 0, 0, value, value, value, value, value, value, 0, 0 ], buffer); + } + + function test_isEmpty() { + Assert.isTrue(new View(null, 0).isEmpty()); + + final buffer = [ for (_ in 0...10) 0 ]; + + Assert.isFalse(new View(Pointer.ofArray(buffer), buffer.length).isEmpty()); + } + + function test_equality() { + final buffer = [ for (_ in 0...10) 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + + final fst = view.slice(0); + final snd = view.slice(0); + + Assert.isTrue(fst == snd); + Assert.isFalse(fst != snd); + + final trd = view.slice(2); + + Assert.isFalse(fst == trd); + Assert.isTrue(fst != trd); + } + + function test_reinterpret_equal_size() { + final buffer = [ for (_ in 0...10) 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final second : View = view.reinterpret(); + + Assert.equals(view.length, second.length); + } + + function test_reinterpret_to_smaller_type() { + final buffer = [ for (_ in 0...10) 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final second : View = view.reinterpret(); + + Assert.equals(view.length * 2, second.length); + } + + function test_reinterpret_to_larger_type() { + final buffer = [ for (_ in 0...3) 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final second : View = view.reinterpret(); + + Assert.equals(1, second.length); + } + + function test_reinterpret_to_larger_type_not_enough_length() { + final buffer = [ 0 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final second : View = view.reinterpret(); + + Assert.equals(0, second.length); + } + + function test_reinterpret_to_value_type() { + final buffer = [ 0f64, 0f64, 0f64, 0f64 ]; + final view = new View(Pointer.ofArray(buffer), buffer.length); + final points = (view.reinterpret() : View); + + Assert.equals(2, points.length); + Assert.equals(0f64, points[0].x); + Assert.equals(0f64, points[0].y); + + points[0].x = 200; + points[0].y = 300; + + Assert.equals(200f64, buffer[0]); + Assert.equals(300f64, buffer[1]); + + points[0] = new Point(); + + Assert.equals(7f64, buffer[0]); + Assert.equals(26f64, buffer[1]); + } +} From cc0fbcc89e76c8e341a66c949d062495befcf2cf Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sun, 16 Nov 2025 14:36:29 +0000 Subject: [PATCH 48/89] Update some tests --- .../classes/TestValueTypeCollections.hx | 18 ++++++++++ .../pointers/TestPointerInterop.hx | 34 +++++++++--------- .../native/tests/marshalling/view/TestView.hx | 36 ++++++++++++++++++- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/test/native/tests/marshalling/classes/TestValueTypeCollections.hx b/test/native/tests/marshalling/classes/TestValueTypeCollections.hx index 43f2596d4..e24c1d665 100644 --- a/test/native/tests/marshalling/classes/TestValueTypeCollections.hx +++ b/test/native/tests/marshalling/classes/TestValueTypeCollections.hx @@ -61,4 +61,22 @@ class TestValueTypeCollections extends Test { Assert.fail('expected array to have one element'); } } + + public function test_collection_of_pointers() { + final v = new StdVector(); + + v.push_back(Context.create()); + + Assert.equals(1, v.size()); + + Assert.equals(7, v[0].number); + + v[0].number = v[0].double(); + + Assert.equals(14, v[0].number); + + v[0] = Context.create(); + + Assert.equals(7, v[0].number); + } } \ No newline at end of file diff --git a/test/native/tests/marshalling/pointers/TestPointerInterop.hx b/test/native/tests/marshalling/pointers/TestPointerInterop.hx index 6c1948c0a..d02f507bf 100644 --- a/test/native/tests/marshalling/pointers/TestPointerInterop.hx +++ b/test/native/tests/marshalling/pointers/TestPointerInterop.hx @@ -30,21 +30,21 @@ private class HaxeFunctions { ctx[0].number = 20; } - @:unreflective public static function set_number_star(ctx : Star) { - ctx.number = 20; - } + // @:unreflective public static function set_number_star(ctx : Star) { + // ctx.number = 20; + // } @:unreflective public static function is_ptr_null(ctx : Pointer) { - return ctx == null; + return ctx[0] == null; } @:unreflective public static function is_raw_ptr_null(ctx : RawPointer) { - return ctx == null; + return ctx[0] == null; } - @:unreflective public static function is_star_null(ctx : Star) { - return ctx == null; - } + // @:unreflective public static function is_star_null(ctx : Star) { + // return ctx == null; + // } } class TestPointerInterop extends Test { @@ -152,17 +152,17 @@ class TestPointerInterop extends Test { Assert.isTrue(HaxeFunctions.is_raw_ptr_null(cast ctx)); } - function test_to_cpp_star() { - final ctx = Context.create(); + // function test_to_cpp_star() { + // final ctx = Context.create(); - HaxeFunctions.set_number_star(cast ctx); + // HaxeFunctions.set_number_star(cast ctx); - Assert.equals(20, ctx.number); - } + // Assert.equals(20, ctx.number); + // } - function test_null_to_cpp_star_throws() { - final ctx : Context = null; + // function test_null_to_cpp_star_throws() { + // final ctx : Context = null; - Assert.isTrue(HaxeFunctions.is_star_null(cast ctx)); - } + // Assert.isTrue(HaxeFunctions.is_star_null(cast ctx)); + // } } \ No newline at end of file diff --git a/test/native/tests/marshalling/view/TestView.hx b/test/native/tests/marshalling/view/TestView.hx index 7853a139f..90126e069 100644 --- a/test/native/tests/marshalling/view/TestView.hx +++ b/test/native/tests/marshalling/view/TestView.hx @@ -32,7 +32,7 @@ class TestView extends Test { function test_reading_value_types() { final buffer = new Point(0, 0); - final view = new View(Pointer.addressOf(buffer), 1); + final view = new View(Pointer.addressOf(buffer), 1); final point = view[0]; Assert.equals(0f64, point.x); @@ -81,6 +81,40 @@ class TestView extends Test { Assert.equals(40f64, point.y); } + function test_reading_pointer_type() { + final obj = Context.create(); + final view = new View(Pointer.addressOf(obj), 1); + + Assert.isTrue(obj == view[0]); + } + + function test_writing_pointer_type() { + final obj = Context.createNull(); + final view = new View(Pointer.addressOf(obj), 1); + final next = Context.create(); + + view[0] = next; + + Assert.isTrue(next == view[0]); + Assert.isTrue(obj == view[0]); + } + + function test_reading_pointer_type_field() { + final obj = Context.create(); + final view = new View(Pointer.addressOf(obj), 1); + + Assert.equals(7, view[0].number); + } + + function test_writing_pointer_type_field() { + final obj = Context.create(); + final view = new View(Pointer.addressOf(obj), 1); + + view[0].number = 200; + + Assert.equals(200, obj.number); + } + function test_slice() { final buffer = [ for (i in 0...10) i + 1 ]; final view = new View(Pointer.ofArray(buffer), buffer.length); From 5f46ac6e43fab0d252fe9cd617b1f4fe9913d95e Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 16 Nov 2025 22:33:36 +0000 Subject: [PATCH 49/89] String marshalling functions --- include/cpp/Marshal.h | 98 ++++++++++++++++++++++++--------- include/cpp/Pointer.h | 3 + include/hxString.h | 5 ++ src/String.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 27 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 2c052e7bd..597d7acf4 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -215,60 +215,91 @@ namespace cpp struct Marshal final { - template - static T zero() { - return T(); - } - - template - static int size(T _) { - return sizeof(T); - } - - static View utf8ViewOfString(::String string); - static View wideViewOfString(::String string); - template static bool tryWrite(View view, T value); + static View toCharView(::String string); + static int toCharView(::String, View buffer); + + static View toWideCharView(::String string); + static int toWideCharView(::String, View buffer); + + static ::String toString(View buffer); + static ::String toString(View buffer); + template static T read(View view); + template static void write(View view, const T& value); }; } } // -inline cpp::marshal::View cpp::marshal::Marshal::utf8ViewOfString(::String string) +inline cpp::marshal::View cpp::marshal::Marshal::toCharView(::String string) { - auto length = int{ 0 }; + auto length = 0; auto ptr = string.utf8_str(nullptr, true, &length); - return View(reinterpret_cast(const_cast(ptr)), length); + return View(const_cast(ptr), length + 1); +} + +inline int cpp::marshal::Marshal::toCharView(::String string, View buffer) +{ + auto length = 0; + + if (string.utf8_str(buffer, &length)) + { + return length; + } + else + { + hx::Throw(HX_CSTRING("Not enough space in the view to write the string")); + + return 0; + } } -inline cpp::marshal::View cpp::marshal::Marshal::wideViewOfString(::String string) +inline cpp::marshal::View cpp::marshal::Marshal::toWideCharView(::String string) { - auto length = int{ 0 }; + auto length = 0; auto ptr = string.wc_str(nullptr, &length); - return View(reinterpret_cast(const_cast(ptr)), length); + return View(const_cast(ptr), length + 1); } -template -inline bool cpp::marshal::Marshal::tryWrite(View view, T value) +inline int cpp::marshal::Marshal::toWideCharView(::String string, View buffer) { - auto requiredSize = sizeof(T); - if (requiredSize > view.length) + auto length = 0; + + if (string.wc_str(buffer, &length)) { - return false; + return length; } + else + { + hx::Throw(HX_CSTRING("Not enough space in the view to write the string")); - std::memcpy(view.ptr, reinterpret_cast(&value), sizeof(T)); + return 0; + } +} - return true; +inline ::String cpp::marshal::Marshal::toString(View buffer) +{ + return ::String::create(buffer.ptr, buffer.length); +} + +inline ::String cpp::marshal::Marshal::toString(View buffer) +{ + return ::String::create(buffer.ptr, buffer.length); +} + +template +inline void cpp::marshal::Marshal::write(View view, const T& value) +{ + std::memcpy(view.ptr, reinterpret_cast(&value), sizeof(T)); } template inline T cpp::marshal::Marshal::read(View view) { - return reinterpret_cast(view.ptr); + return *(reinterpret_cast(view.ptr.ptr)); } // @@ -593,6 +624,13 @@ template template inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} +template +template +inline K cpp::marshal::PointerReference::get(int index) +{ + return (*Super::ptr)[index]; +} + template template inline void cpp::marshal::PointerReference::set(int index, K value) @@ -848,6 +886,12 @@ inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::ValueRe return Pointer(ref.ptr); } +template +inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::PointerReference& ref) +{ + return Pointer(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 inline cpp::Pointer::Pointer(const ::cpp::marshal::PointerReference ref) diff --git a/include/cpp/Pointer.h b/include/cpp/Pointer.h index 6ac2cb43f..48aaa50f7 100644 --- a/include/cpp/Pointer.h +++ b/include/cpp/Pointer.h @@ -516,6 +516,9 @@ class Pointer_obj template inline static Pointer addressOf(const ::cpp::marshal::ValueReference&); + template + inline static Pointer addressOf(const ::cpp::marshal::PointerReference&); + template inline static Pointer addressOf(T &value) { return Pointer(&value); } diff --git a/include/hxString.h b/include/hxString.h index b53ddd4a3..89fc8d8a0 100644 --- a/include/hxString.h +++ b/include/hxString.h @@ -168,6 +168,11 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES String const wchar_t *wchar_str(hx::IStringAlloc *inBuffer = 0) const; const char16_t *wc_str(hx::IStringAlloc *inBuffer = 0, int *outCharLength = 0) const; +#if (HXCPP_API_LEVEL >= 500) + bool wc_str(::cpp::marshal::View buffer, int* outCharLength = nullptr) const; + bool utf8_str(::cpp::marshal::View buffer, int* outByteLength = nullptr) const; +#endif + const char *__CStr() const { return utf8_str(); }; const wchar_t *__WCStr() const { return wchar_str(0); } inline operator const char *() { return utf8_str(); } diff --git a/src/String.cpp b/src/String.cpp index 723017fc9..35e137b30 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -1761,6 +1761,131 @@ const char16_t * String::wc_str(hx::IStringAlloc *inBuffer, int *outCharLength) return str; } +#if (HXCPP_API_LEVEL >= 500) + +bool String::wc_str(::cpp::marshal::View buffer, int* outCharLength) const +{ +#ifdef HX_SMART_STRINGS + if (isUTF16Encoded()) + { + if (buffer.length < length + 1) + { + return false; + } + + if (nullptr != outCharLength) + { + *outCharLength = length + 1; + } + + std::memcpy(buffer.ptr, __w, sizeof(char16_t) * length); + + buffer[length] = 0; + + return true; + } +#endif + + auto charCount = 0; + auto source = reinterpret_cast(__s); + auto cursor = source; + auto end = source + length; + + while (cursor < end) + { + auto code = DecodeAdvanceUTF8(cursor, end); + + charCount += UTF16BytesCheck(code); + } + + if (buffer.length < charCount + 1) + { + return false; + } + + cursor = source; + auto output = buffer.ptr.ptr; + + while (cursor < end) + { + auto code = DecodeAdvanceUTF8(cursor, end); + + Char16AdvanceSet(output, code); + } + + *output = 0; + + if (nullptr != outCharLength) + { + *outCharLength = length + 1; + } + + return true; +} + +bool String::utf8_str(::cpp::marshal::View buffer, int* outByteLength) const +{ +#ifdef HX_SMART_STRINGS + if (isUTF16Encoded()) + { + auto cursor = __w; + + while (Char16Advance(cursor)) {} + + auto calculated = cursor - __w - 1; + + cursor = __w; + + auto end = cursor + calculated; + auto chars = 0; + + while (cursor < end) + { + chars += UTF8Bytes(Char16Advance(cursor)); + } + + if (buffer.length < chars + 1) + { + return false; + } + + auto output = buffer.ptr.ptr; + cursor = __w; + + while (cursor < end) + { + UTF8EncodeAdvance(output, Char16Advance(cursor)); + } + + *output = 0; + + if (nullptr != outByteLength) + { + *outByteLength = chars + 1; + } + + return true; + } +#endif + + if (buffer.length < length) + { + return false; + } + + if (nullptr != outByteLength) + { + *outByteLength = length + 1; + } + + std::memcpy(buffer.ptr, __s, sizeof(char) * length); + + buffer[length] = 0; + + return true; +} + +#endif const wchar_t * String::wchar_str(hx::IStringAlloc *inBuffer) const { From 5db27cecb7017b714575fcc69a0bf8fd1de8f125 Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sun, 16 Nov 2025 22:34:03 +0000 Subject: [PATCH 50/89] Marshalling tests --- test/native/Native.hx | 3 +- .../tests/marshalling/view/TestMarshal.hx | 248 ++++++++++++++++++ 2 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 test/native/tests/marshalling/view/TestMarshal.hx diff --git a/test/native/Native.hx b/test/native/Native.hx index d9568ceea..5852a55cc 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -43,7 +43,8 @@ class Native new tests.marshalling.managed.TestClassNonStandardManagedClass(), new tests.marshalling.managed.TestClassStandardManagedClass(), - new tests.marshalling.view.TestView() + new tests.marshalling.view.TestView(), + new tests.marshalling.view.TestMarshal() #end ]); } diff --git a/test/native/tests/marshalling/view/TestMarshal.hx b/test/native/tests/marshalling/view/TestMarshal.hx new file mode 100644 index 000000000..791be3399 --- /dev/null +++ b/test/native/tests/marshalling/view/TestMarshal.hx @@ -0,0 +1,248 @@ +package tests.marshalling.view; + +import cpp.Char; +import cpp.Char16; +import cpp.Pointer; +import cpp.marshal.View; +import haxe.io.Bytes; +import utest.Test; +import utest.Assert; +import tests.marshalling.Point; + +using cpp.marshal.Marshal; +using cpp.marshal.ViewExtensions; + +class TestMarshal extends Test { + function test_write_int() { + final storage = 0; + final source = new View(Pointer.addressOf(storage), 1); + final value = 200; + + source.asBytesView().write(value); + + Assert.equals(value, storage); + } + + function test_read_int() { + final storage = 200; + final source = new View(Pointer.addressOf(storage), 1); + + Assert.isTrue(storage == source.asBytesView().read()); + } + + function test_write_float() { + final storage = 0f64; + final source = new View(Pointer.addressOf(storage), 1); + final value = 200.81; + + source.asBytesView().write(value); + + Assert.equals(value, storage); + } + + function test_read_float() { + final storage = 200.81; + final source = new View(Pointer.addressOf(storage), 1); + + Assert.isTrue(storage == source.asBytesView().read()); + } + + function test_write_bool() { + final storage = false; + final source = new View(Pointer.addressOf(storage), 1); + final value = true; + + source.asBytesView().write(value); + + Assert.equals(value, storage); + } + + function test_read_bool() { + final storage = true; + final source = new View(Pointer.addressOf(storage), 1); + + Assert.isTrue(storage == source.asBytesView().read()); + } + + function test_write_value_type() { + final storage = new Point(0, 0); + final source = new View(Pointer.addressOf(storage), 1); + final value = new Point(); + + source.asBytesView().write(value); + + Assert.equals(value.x, storage.x); + Assert.equals(value.y, storage.y); + } + + function test_read_value_type() { + final storage = new Point(); + final source = new View(Pointer.addressOf(storage), 1); + final value = (source.asBytesView().read() : Point); + + Assert.equals(value.x, storage.x); + Assert.equals(value.y, storage.y); + } + + function test_write_pointer_type() { + final storage = Context.createNull(); + final source = new View(Pointer.addressOf(storage), 1); + final value = Context.create(); + + source.asBytesView().write(value); + + Assert.isTrue(storage == value); + } + + function test_read_pointer_type() { + final storage = Context.create(); + final source = new View(Pointer.addressOf(storage), 1); + final value = (source.asBytesView().read() : Context); + + Assert.isTrue(storage == value); + } + + function test_ascii_string_to_utf8() { + final source = "Hello, World!"; + final view = source.toCharView(); + + if (Assert.equals(source.length + 1, view.length)) { + Assert.equals(view[ 0], "H".code); + Assert.equals(view[ 1], "e".code); + Assert.equals(view[ 2], "l".code); + Assert.equals(view[ 3], "l".code); + Assert.equals(view[ 4], "o".code); + Assert.equals(view[ 5], ",".code); + Assert.equals(view[ 6], " ".code); + Assert.equals(view[ 7], "W".code); + Assert.equals(view[ 8], "o".code); + Assert.equals(view[ 9], "r".code); + Assert.equals(view[10], "l".code); + Assert.equals(view[11], "d".code); + Assert.equals(view[12], "!".code); + Assert.equals(view[13], 0); + } + } + + function test_ascii_string_to_utf8_buffer() { + final source = "Hello, World!"; + final buffer = Bytes.ofHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + final view = new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret(); + final count = Marshal.toCharView(source, view); + + if (Assert.equals(source.length + 1, count)) { + Assert.equals(view[ 0], "H".code); + Assert.equals(view[ 1], "e".code); + Assert.equals(view[ 2], "l".code); + Assert.equals(view[ 3], "l".code); + Assert.equals(view[ 4], "o".code); + Assert.equals(view[ 5], ",".code); + Assert.equals(view[ 6], " ".code); + Assert.equals(view[ 7], "W".code); + Assert.equals(view[ 8], "o".code); + Assert.equals(view[ 9], "r".code); + Assert.equals(view[10], "l".code); + Assert.equals(view[11], "d".code); + Assert.equals(view[12], "!".code); + Assert.equals(view[13], 0); + } + } + + function test_emoji_string_to_utf8() { + final source = "😂"; + final view = source.toCharView(); + + if (Assert.equals(5, view.length)) { + Assert.equals((0xf0:Char), view[0]); + Assert.equals((0x9f:Char), view[1]); + Assert.equals((0x98:Char), view[2]); + Assert.equals((0x82:Char), view[3]); + Assert.equals(0, view[4]); + } + } + + function test_emoji_string_to_utf8_buffer() { + final source = "😂"; + final buffer = Bytes.ofHex("FFFFFFFFFF"); + final view = new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret(); + final count = Marshal.toCharView(source, view); + + if (Assert.equals(5, count)) { + Assert.equals((0xf0:Char), view[0]); + Assert.equals((0x9f:Char), view[1]); + Assert.equals((0x98:Char), view[2]); + Assert.equals((0x82:Char), view[3]); + Assert.equals(0, view[4]); + } + } + + function test_ascii_string_to_utf16() { + final source = "Hello, World!"; + final view = source.toWideCharView(); + + if (Assert.equals(source.length + 1, view.length)) { + Assert.equals(view[ 0], "H".code); + Assert.equals(view[ 1], "e".code); + Assert.equals(view[ 2], "l".code); + Assert.equals(view[ 3], "l".code); + Assert.equals(view[ 4], "o".code); + Assert.equals(view[ 5], ",".code); + Assert.equals(view[ 6], " ".code); + Assert.equals(view[ 7], "W".code); + Assert.equals(view[ 8], "o".code); + Assert.equals(view[ 9], "r".code); + Assert.equals(view[10], "l".code); + Assert.equals(view[11], "d".code); + Assert.equals(view[12], "!".code); + Assert.equals(view[13], 0); + } + } + + function test_ascii_string_to_utf16_buffer() { + final source = "Hello, World!"; + final buffer = Bytes.ofHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + final view = new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret(); + final count = Marshal.toWideCharView(source, view); + + if (Assert.equals(count, view.length)) { + Assert.equals(view[ 0], "H".code); + Assert.equals(view[ 1], "e".code); + Assert.equals(view[ 2], "l".code); + Assert.equals(view[ 3], "l".code); + Assert.equals(view[ 4], "o".code); + Assert.equals(view[ 5], ",".code); + Assert.equals(view[ 6], " ".code); + Assert.equals(view[ 7], "W".code); + Assert.equals(view[ 8], "o".code); + Assert.equals(view[ 9], "r".code); + Assert.equals(view[10], "l".code); + Assert.equals(view[11], "d".code); + Assert.equals(view[12], "!".code); + Assert.equals(view[13], 0); + } + } + + function test_emoji_string_to_utf16() { + final source = "😂"; + final view = source.toWideCharView(); + + if (Assert.equals(3, view.length)) { + Assert.equals((0xD83D:Char16), view[0]); + Assert.equals((0xDE02:Char16), view[1]); + Assert.equals(0, view[2]); + } + } + + function test_emoji_string_to_utf16_buffer() { + final source = "😂"; + final buffer = Bytes.ofHex("FFFFFFFFFFFFFFFF"); + final view = new View(Pointer.ofArray(buffer.getData()), 3 * 2).reinterpret(); + final count = Marshal.toWideCharView(source, view); + + if (Assert.equals(count, view.length)) { + Assert.equals((0xD83D:Char16), view[0]); + Assert.equals((0xDE02:Char16), view[1]); + Assert.equals(0, view[2]); + } + } +} \ No newline at end of file From d595c91dce7772f4228dafcefb0802132f6f806e Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 17 Nov 2025 18:19:40 +0000 Subject: [PATCH 51/89] view based string creation and support char16_t in various hxcpp types --- include/Array.h | 2 ++ include/Dynamic.h | 8 ++++++++ include/cpp/Marshal.h | 5 +++-- include/cpp/Variant.h | 6 ++++++ include/hxString.h | 5 +++++ include/null.h | 3 +++ src/Dynamic.cpp | 6 +++++- src/String.cpp | 13 +++++++++++++ 8 files changed, 45 insertions(+), 3 deletions(-) diff --git a/include/Array.h b/include/Array.h index ed6f7386c..e95c433de 100644 --- a/include/Array.h +++ b/include/Array.h @@ -39,6 +39,7 @@ template<> struct ReturnNull { typedef Dynamic type; }; template<> struct ReturnNull { typedef Dynamic type; }; template<> struct ReturnNull { typedef Dynamic type; }; template<> struct ReturnNull { typedef Dynamic type; }; +template<> struct ReturnNull { typedef Dynamic type; }; template<> struct ReturnNull { typedef Dynamic type; }; template<> struct ReturnNull { typedef Dynamic type; }; template<> struct ReturnNull { typedef Dynamic type; }; @@ -431,6 +432,7 @@ template<> struct ArrayClassId { enum { id=hx::clsIdArrayByte }; template<> struct ArrayClassId { enum { id=hx::clsIdArrayByte }; }; template<> struct ArrayClassId { enum { id=hx::clsIdArrayShort }; }; template<> struct ArrayClassId { enum { id=hx::clsIdArrayShort }; }; +template<> struct ArrayClassId { enum { id = hx::clsIdArrayShort }; }; template<> struct ArrayClassId { enum { id=hx::clsIdArrayInt }; }; template<> struct ArrayClassId { enum { id=hx::clsIdArrayInt }; }; template<> struct ArrayClassId { enum { id=hx::clsIdArrayFloat32 }; }; diff --git a/include/Dynamic.h b/include/Dynamic.h index dbf23c836..1d655f47b 100644 --- a/include/Dynamic.h +++ b/include/Dynamic.h @@ -24,6 +24,7 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic : public hx::ObjectPtr Dynamic(unsigned short inVal); Dynamic(unsigned char inVal); Dynamic(signed char inVal); + Dynamic(char16_t inVal); Dynamic(const cpp::CppInt32__ &inVal); Dynamic(bool inVal); Dynamic(double inVal); @@ -71,6 +72,7 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic : public hx::ObjectPtr inline operator unsigned char () const { return mPtr ? mPtr->__ToInt() : 0; } inline operator char () const { return mPtr ? mPtr->__ToInt() : 0; } inline operator signed char () const { return mPtr ? mPtr->__ToInt() : 0; } + inline operator char16_t () const { return mPtr ? mPtr->__ToInt() : 0; } inline operator bool() const { return mPtr && mPtr->__ToInt(); } inline operator cpp::Int64() const { return mPtr ? mPtr->__ToInt64() : 0; } inline operator cpp::UInt64() const { return mPtr ? mPtr->__ToInt64() : 0; } @@ -171,6 +173,7 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic : public hx::ObjectPtr bool operator op (unsigned short inRHS) const { return IsNumeric() && ((double)(*this) op (double)inRHS); } \ bool operator op (signed char inRHS) const { return IsNumeric() && ((double)(*this) op (double)inRHS); } \ bool operator op (unsigned char inRHS) const { return IsNumeric() && ((double)(*this) op (double)inRHS); } \ + bool operator op (char16_t inRHS) const { return IsNumeric() && ((double)(*this) op (double)inRHS); } \ bool operator op (bool inRHS) const { return IsBool() && ((double)(*this) op (double)inRHS); } \ bool operator != (const String &inRHS) const { return !mPtr || ((String)(*this) != inRHS); } @@ -184,6 +187,7 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic : public hx::ObjectPtr bool operator != (unsigned short inRHS) const { return !IsNumeric() || ((double)(*this) != (double)inRHS); } bool operator != (signed char inRHS) const { return !IsNumeric() || ((double)(*this) != (double)inRHS); } bool operator != (unsigned char inRHS) const { return !IsNumeric() || ((double)(*this) != (double)inRHS); } + bool operator != (char16_t inRHS) const { return !IsNumeric() || ((double)(*this) != (double)inRHS); } bool operator != (bool inRHS) const { return !IsBool() || ((double)(*this) != (double)inRHS); } @@ -229,6 +233,7 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic : public hx::ObjectPtr Dynamic operator+(const unsigned short &i) const; Dynamic operator+(const signed char &i) const; Dynamic operator+(const unsigned char &i) const; + Dynamic operator+(const char16_t& i) const; Dynamic operator+(const double &d) const; Dynamic operator+(const float &d) const; Dynamic operator+(const cpp::Variant &d) const; @@ -270,6 +275,8 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES Dynamic : public hx::ObjectPtr { return mPtr->__GetType()==vtInt ? Dynamic((int)(*this) op inRHS) : Dynamic((double)(*this) op inRHS); } \ Dynamic operator op (const unsigned char &inRHS) const \ { return mPtr->__GetType()==vtInt ? Dynamic((int)(*this) op inRHS) : Dynamic((double)(*this) op inRHS); } \ + Dynamic operator op (const char16_t &inRHS) const \ + { return mPtr->__GetType()==vtInt ? Dynamic((int)(*this) op inRHS) : Dynamic((double)(*this) op inRHS); } \ Dynamic operator op (const cpp::Int64 &inRHS) const \ { return Dynamic((double)(*this) op inRHS); } \ Dynamic operator op (const cpp::UInt64 &inRHS) const \ @@ -457,6 +464,7 @@ COMPARE_DYNAMIC_OP( > ) inline double operator op (const unsigned short &inLHS,const Dynamic &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const signed char &inLHS,const Dynamic &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const unsigned char &inLHS,const Dynamic &inRHS) { return inLHS op (double)inRHS; } \ + inline double operator op (const char16_t &inLHS,const Dynamic &inRHS) { return inLHS op (double)inRHS; } \ ARITH_DYNAMIC( - ) ARITH_DYNAMIC( + ) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 597d7acf4..538e068d9 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace cpp @@ -282,12 +283,12 @@ inline int cpp::marshal::Marshal::toWideCharView(::String string, View inline ::String cpp::marshal::Marshal::toString(View buffer) { - return ::String::create(buffer.ptr, buffer.length); + return ::String::create(buffer); } inline ::String cpp::marshal::Marshal::toString(View buffer) { - return ::String::create(buffer.ptr, buffer.length); + return ::String::create(buffer); } template diff --git a/include/cpp/Variant.h b/include/cpp/Variant.h index 842b4338e..7197927a7 100644 --- a/include/cpp/Variant.h +++ b/include/cpp/Variant.h @@ -109,6 +109,7 @@ namespace cpp inline operator unsigned char () const { return asInt(); } inline operator char () const { return asInt(); } inline operator signed char () const { return asInt(); } + inline operator char16_t() const { return asInt(); } inline operator cpp::Int64 () const { return asInt64(); } inline operator cpp::UInt64 () const { return asInt64(); } inline bool operator !() const { return !asInt(); } @@ -206,6 +207,7 @@ namespace cpp inline bool operator op (unsigned short inRHS) const { return isNumeric() && (asDouble() op (double)inRHS); } \ inline bool operator op (signed char inRHS) const { return isNumeric() && (asDouble() op (double)inRHS); } \ inline bool operator op (unsigned char inRHS) const { return isNumeric() && (asDouble() op (double)inRHS); } \ + inline bool operator op (char16_t inRHS) const { return isNumeric() && (asDouble() op (double)inRHS); } \ inline bool operator op (bool inRHS) const { return isBool() && (asDouble() op (double)inRHS); } \ inline bool operator op (const Dynamic &inRHS) const { return Compare(inRHS) op 0; } \ @@ -278,6 +280,7 @@ namespace cpp inline double operator op (const unsigned int &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const signed char &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const unsigned char &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ + inline double operator op (const char16_t &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const signed short &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const unsigned short &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ inline double operator op (const cpp::Int64 &inLHS,const cpp::Variant &inRHS) { return inLHS op (double)inRHS; } \ @@ -604,6 +607,7 @@ HX_VARIANT_OP_ISEQ(short) HX_VARIANT_OP_ISEQ(unsigned short) HX_VARIANT_OP_ISEQ(signed char) HX_VARIANT_OP_ISEQ(unsigned char) +HX_VARIANT_OP_ISEQ(char16_t) HX_VARIANT_OP_ISEQ(bool) inline bool operator < (bool inLHS,const cpp::Variant &inRHS) { return false; } @@ -633,6 +637,8 @@ inline bool operator > (bool inLHS,const cpp::Variant &inRHS) { return false; } { return inRHS.isNumeric() && (inLHS op (double)inRHS); } \ inline bool operator op (unsigned char inLHS,const ::cpp::Variant &inRHS) \ { return inRHS.isNumeric() && (inLHS op (double)inRHS); } \ + inline bool operator op (char16_t inLHS,const ::cpp::Variant &inRHS) \ + { return inRHS.isNumeric() && (inLHS op (double)inRHS); } \ inline bool operator op (const null &,const ::cpp::Variant &inRHS) \ { return false; } \ diff --git a/include/hxString.h b/include/hxString.h index 89fc8d8a0..280a8abba 100644 --- a/include/hxString.h +++ b/include/hxString.h @@ -46,6 +46,11 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES String static String create(const char16_t *inPtr,int inLen=-1); static String create(const char *inPtr,int inLen=-1); +#if (HXCPP_API_LEVEL>=500) + static String create(const ::cpp::marshal::View& buffer); + static String create(const ::cpp::marshal::View& buffer); +#endif + // Uses non-gc memory and wont ever be collected static ::String createPermanent(const char *inUtf8, int inLen); const ::String &makePermanent() const; diff --git a/include/null.h b/include/null.h index b3a977c36..d01f97ad8 100644 --- a/include/null.h +++ b/include/null.h @@ -90,6 +90,7 @@ class null operator char () { return 0; } operator unsigned char () { return 0; } operator signed char () { return 0; } + operator char16_t () { return 0; } operator short () { return 0; } operator unsigned short () { return 0; } operator cpp::UInt64 () { return 0; } @@ -144,6 +145,7 @@ class null HX_NULL_COMPARE_OPS(unsigned short) HX_NULL_COMPARE_OPS(signed char) HX_NULL_COMPARE_OPS(unsigned char) + HX_NULL_COMPARE_OPS(char16_t) HX_NULL_COMPARE_OPS(cpp::Int64) HX_NULL_COMPARE_OPS(cpp::UInt64) HX_NULL_COMPARE_MOST_OPS(String) @@ -212,6 +214,7 @@ HX_COMPARE_NULL_OPS(short) HX_COMPARE_NULL_OPS(unsigned short) HX_COMPARE_NULL_OPS(signed char) HX_COMPARE_NULL_OPS(unsigned char) +HX_COMPARE_NULL_OPS(char16_t) HX_COMPARE_NULL_OPS(cpp::UInt64) HX_COMPARE_NULL_OPS(cpp::Int64) diff --git a/src/Dynamic.cpp b/src/Dynamic.cpp index 9d52c070e..daf7eae5a 100644 --- a/src/Dynamic.cpp +++ b/src/Dynamic.cpp @@ -397,7 +397,10 @@ Dynamic::Dynamic(signed char inVal) mPtr = fromInt(inVal); } - +Dynamic::Dynamic(char16_t inVal) +{ + mPtr = fromInt(inVal); +} Dynamic::Dynamic(double inVal) { @@ -493,6 +496,7 @@ DYN_OP_ADD(short) DYN_OP_ADD(unsigned short) DYN_OP_ADD(signed char) DYN_OP_ADD(unsigned char) +DYN_OP_ADD(char16_t) DYN_OP_ADD(cpp::Int64) DYN_OP_ADD(cpp::UInt64) diff --git a/src/String.cpp b/src/String.cpp index 35e137b30..e612d675f 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -788,10 +788,23 @@ String String::create(const char *inString,int inLength) return String(s,len); } +#if (HXCPP_API_LEVEL>=500) +String String::create(const::cpp::marshal::View& buffer) +{ + return String::create(buffer.ptr.ptr, std::char_traits::length(buffer.ptr.ptr)); +} +String String::create(const cpp::marshal::View& buffer) +{ + auto cursor = reinterpret_cast(buffer.ptr.ptr); + while (Char16Advance(cursor)) {} + auto calculated = cursor - buffer.ptr.ptr - 1; + return String::create(buffer.ptr.ptr, calculated); +} +#endif String::String(const Dynamic &inRHS) { From 4dc482bd23ee8afc579a2a497aec3919268443f4 Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Mon, 17 Nov 2025 18:21:16 +0000 Subject: [PATCH 52/89] Marshalling string tests --- .../tests/marshalling/view/TestMarshal.hx | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/test/native/tests/marshalling/view/TestMarshal.hx b/test/native/tests/marshalling/view/TestMarshal.hx index 791be3399..6a1633c56 100644 --- a/test/native/tests/marshalling/view/TestMarshal.hx +++ b/test/native/tests/marshalling/view/TestMarshal.hx @@ -1,5 +1,6 @@ package tests.marshalling.view; +import haxe.ds.Vector; import cpp.Char; import cpp.Char16; import cpp.Pointer; @@ -245,4 +246,90 @@ class TestMarshal extends Test { Assert.equals(0, view[2]); } } + + function test_ascii_chars_to_string() { + final buffer = new Vector(5); + buffer[0] = 'H'.code; + buffer[1] = 'e'.code; + buffer[2] = 'l'.code; + buffer[3] = 'l'.code; + buffer[4] = 'o'.code; + final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final string = view.toString(); + + Assert.equals('Hello', string); + } + + function test_ascii_wide_chars_to_string() { + final buffer = new Vector(5); + buffer[0] = 'H'.code; + buffer[1] = 'e'.code; + buffer[2] = 'l'.code; + buffer[3] = 'l'.code; + buffer[4] = 'o'.code; + final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final string = view.toString(); + + Assert.equals('Hello', string); + } + + function test_null_terminated_ascii_chars_to_string() { + final buffer = new Vector(5); + buffer[0] = 'H'.code; + buffer[1] = 'e'.code; + buffer[2] = 'l'.code; + buffer[3] = 'l'.code; + buffer[4] = 'o'.code; + buffer[5] = 0; + final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final string = view.toString(); + + Assert.equals('Hello', string); + } + + function test_null_terminated_ascii_wide_chars_to_string() { + final buffer = new Vector(5); + buffer[0] = 'H'.code; + buffer[1] = 'e'.code; + buffer[2] = 'l'.code; + buffer[3] = 'l'.code; + buffer[4] = 'o'.code; + buffer[5] = 0; + final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final string = view.toString(); + + Assert.equals('Hello', string); + } + + function test_utf8_bytes_to_string() { + final buffer = Bytes.ofHex("f09f9882"); + final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final string = view.toString(); + + Assert.equals('😂', string); + } + + function test_null_terminated_utf8_bytes_to_string() { + final buffer = Bytes.ofHex("f09f98820000"); + final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final string = view.toString(); + + Assert.equals('😂', string); + } + + function test_utf16_bytes_to_string() { + final buffer = Bytes.ofHex("3DD802De"); + final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final string = view.toString(); + + Assert.equals('😂', string); + } + + function test_null_terminated_utf16_bytes_to_string() { + final buffer = Bytes.ofHex("3DD802De00000000"); + final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final string = view.toString(); + + Assert.equals('😂', string); + } } \ No newline at end of file From e15836da80d020af1151c1d55c9930298cd7e2b3 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 17 Nov 2025 19:58:35 +0000 Subject: [PATCH 53/89] const ref a bit --- include/cpp/Marshal.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index 538e068d9..cd5df1a43 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -216,11 +216,11 @@ namespace cpp struct Marshal final { - static View toCharView(::String string); - static int toCharView(::String, View buffer); + static View toCharView(const ::String& string); + static int toCharView(const ::String&, View buffer); - static View toWideCharView(::String string); - static int toWideCharView(::String, View buffer); + static View toWideCharView(const ::String& string); + static int toWideCharView(const ::String& string, View buffer); static ::String toString(View buffer); static ::String toString(View buffer); @@ -233,7 +233,7 @@ namespace cpp // -inline cpp::marshal::View cpp::marshal::Marshal::toCharView(::String string) +inline cpp::marshal::View cpp::marshal::Marshal::toCharView(const ::String& string) { auto length = 0; auto ptr = string.utf8_str(nullptr, true, &length); @@ -241,7 +241,7 @@ inline cpp::marshal::View cpp::marshal::Marshal::toCharView(::String strin return View(const_cast(ptr), length + 1); } -inline int cpp::marshal::Marshal::toCharView(::String string, View buffer) +inline int cpp::marshal::Marshal::toCharView(const ::String& string, View buffer) { auto length = 0; @@ -257,7 +257,7 @@ inline int cpp::marshal::Marshal::toCharView(::String string, View buffer) } } -inline cpp::marshal::View cpp::marshal::Marshal::toWideCharView(::String string) +inline cpp::marshal::View cpp::marshal::Marshal::toWideCharView(const ::String& string) { auto length = 0; auto ptr = string.wc_str(nullptr, &length); @@ -265,7 +265,7 @@ inline cpp::marshal::View cpp::marshal::Marshal::toWideCharView(::Stri return View(const_cast(ptr), length + 1); } -inline int cpp::marshal::Marshal::toWideCharView(::String string, View buffer) +inline int cpp::marshal::Marshal::toWideCharView(const ::String& string, View buffer) { auto length = 0; From 4e706d487135edd71ca84068550bf39282cdb75b Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 17 Nov 2025 22:03:35 +0000 Subject: [PATCH 54/89] Don't use byte size in copyTo comparison check --- include/cpp/Marshal.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h index cd5df1a43..845e851d7 100644 --- a/include/cpp/Marshal.h +++ b/include/cpp/Marshal.h @@ -311,13 +311,12 @@ inline cpp::marshal::View::View(::cpp::Pointer _ptr, int _length) : ptr(_p template inline bool cpp::marshal::View::tryCopyTo(const View& destination) { - auto requiredSize = sizeof(T) * length; - if (destination.length < requiredSize) + if (destination.length < length) { return false; } - std::memcpy(destination.ptr, ptr, requiredSize); + std::memcpy(destination.ptr.ptr, ptr.ptr, sizeof(T) * length); return true; } From a8b47b5626e3a9970a4f73dd00b32fa16b7d4a1b Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Mon, 17 Nov 2025 22:08:38 +0000 Subject: [PATCH 55/89] view extension tests --- test/native/Native.hx | 3 +- .../tests/marshalling/view/TestMarshal.hx | 24 +-- .../native/tests/marshalling/view/TestView.hx | 28 +-- .../marshalling/view/TestViewExtensions.hx | 169 ++++++++++++++++++ 4 files changed, 198 insertions(+), 26 deletions(-) create mode 100644 test/native/tests/marshalling/view/TestViewExtensions.hx diff --git a/test/native/Native.hx b/test/native/Native.hx index 5852a55cc..0c8cb9506 100644 --- a/test/native/Native.hx +++ b/test/native/Native.hx @@ -44,7 +44,8 @@ class Native new tests.marshalling.managed.TestClassStandardManagedClass(), new tests.marshalling.view.TestView(), - new tests.marshalling.view.TestMarshal() + new tests.marshalling.view.TestMarshal(), + new tests.marshalling.view.TestViewExtensions() #end ]); } diff --git a/test/native/tests/marshalling/view/TestMarshal.hx b/test/native/tests/marshalling/view/TestMarshal.hx index 6a1633c56..2f2e8e7d6 100644 --- a/test/native/tests/marshalling/view/TestMarshal.hx +++ b/test/native/tests/marshalling/view/TestMarshal.hx @@ -128,7 +128,7 @@ class TestMarshal extends Test { function test_ascii_string_to_utf8_buffer() { final source = "Hello, World!"; final buffer = Bytes.ofHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF"); - final view = new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret(); + final view = buffer.asView().reinterpret(); final count = Marshal.toCharView(source, view); if (Assert.equals(source.length + 1, count)) { @@ -165,7 +165,7 @@ class TestMarshal extends Test { function test_emoji_string_to_utf8_buffer() { final source = "😂"; final buffer = Bytes.ofHex("FFFFFFFFFF"); - final view = new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret(); + final view = buffer.asView().reinterpret(); final count = Marshal.toCharView(source, view); if (Assert.equals(5, count)) { @@ -202,7 +202,7 @@ class TestMarshal extends Test { function test_ascii_string_to_utf16_buffer() { final source = "Hello, World!"; final buffer = Bytes.ofHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); - final view = new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret(); + final view = buffer.asView().reinterpret(); final count = Marshal.toWideCharView(source, view); if (Assert.equals(count, view.length)) { @@ -237,7 +237,7 @@ class TestMarshal extends Test { function test_emoji_string_to_utf16_buffer() { final source = "😂"; final buffer = Bytes.ofHex("FFFFFFFFFFFFFFFF"); - final view = new View(Pointer.ofArray(buffer.getData()), 3 * 2).reinterpret(); + final view = buffer.asView().slice(0, 3 * 2).reinterpret(); final count = Marshal.toWideCharView(source, view); if (Assert.equals(count, view.length)) { @@ -254,7 +254,7 @@ class TestMarshal extends Test { buffer[2] = 'l'.code; buffer[3] = 'l'.code; buffer[4] = 'o'.code; - final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final view = buffer.asView(); final string = view.toString(); Assert.equals('Hello', string); @@ -267,7 +267,7 @@ class TestMarshal extends Test { buffer[2] = 'l'.code; buffer[3] = 'l'.code; buffer[4] = 'o'.code; - final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final view = buffer.asView(); final string = view.toString(); Assert.equals('Hello', string); @@ -281,7 +281,7 @@ class TestMarshal extends Test { buffer[3] = 'l'.code; buffer[4] = 'o'.code; buffer[5] = 0; - final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final view = buffer.asView(); final string = view.toString(); Assert.equals('Hello', string); @@ -295,7 +295,7 @@ class TestMarshal extends Test { buffer[3] = 'l'.code; buffer[4] = 'o'.code; buffer[5] = 0; - final view = new View(Pointer.ofArray(buffer.toData()), buffer.length); + final view = buffer.asView(); final string = view.toString(); Assert.equals('Hello', string); @@ -303,7 +303,7 @@ class TestMarshal extends Test { function test_utf8_bytes_to_string() { final buffer = Bytes.ofHex("f09f9882"); - final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final view = (buffer.asView().reinterpret() : View); final string = view.toString(); Assert.equals('😂', string); @@ -311,7 +311,7 @@ class TestMarshal extends Test { function test_null_terminated_utf8_bytes_to_string() { final buffer = Bytes.ofHex("f09f98820000"); - final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final view = (buffer.asView().reinterpret() : View); final string = view.toString(); Assert.equals('😂', string); @@ -319,7 +319,7 @@ class TestMarshal extends Test { function test_utf16_bytes_to_string() { final buffer = Bytes.ofHex("3DD802De"); - final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final view = (buffer.asView().reinterpret() : View); final string = view.toString(); Assert.equals('😂', string); @@ -327,7 +327,7 @@ class TestMarshal extends Test { function test_null_terminated_utf16_bytes_to_string() { final buffer = Bytes.ofHex("3DD802De00000000"); - final view = (new View(Pointer.ofArray(buffer.getData()), buffer.length).reinterpret() : View); + final view = (buffer.asView().reinterpret() : View); final string = view.toString(); Assert.equals('😂', string); diff --git a/test/native/tests/marshalling/view/TestView.hx b/test/native/tests/marshalling/view/TestView.hx index 90126e069..2cc078692 100644 --- a/test/native/tests/marshalling/view/TestView.hx +++ b/test/native/tests/marshalling/view/TestView.hx @@ -9,10 +9,12 @@ import utest.Test; import utest.Assert; import tests.marshalling.Point; +using cpp.marshal.ViewExtensions; + class TestView extends Test { function test_reading_ints() { final buffer = [ for (i in 0...10) i + 1 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); for (i in 0...10) { Assert.equals(i + 1, view[i]); @@ -21,7 +23,7 @@ class TestView extends Test { function test_writing_ints() { final buffer = [ for (_ in 0...10) 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); for (i in 0...10) { view[i] = i + 1; @@ -117,7 +119,7 @@ class TestView extends Test { function test_slice() { final buffer = [ for (i in 0...10) i + 1 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final index = 3; final slice = view.slice(index); @@ -130,7 +132,7 @@ class TestView extends Test { function test_slice_with_length() { final buffer = [ for (i in 0...10) i + 1 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final index = 3; final length = 4; final slice = view.slice(index, length); @@ -144,7 +146,7 @@ class TestView extends Test { function test_clear() { final buffer = [ for (_ in 0...10) 8 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); view.slice(2, 6).clear(); @@ -153,7 +155,7 @@ class TestView extends Test { function test_fill() { final buffer = [ for (_ in 0...10) 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final value = 8; view.slice(2, 6).fill(value); @@ -166,12 +168,12 @@ class TestView extends Test { final buffer = [ for (_ in 0...10) 0 ]; - Assert.isFalse(new View(Pointer.ofArray(buffer), buffer.length).isEmpty()); + Assert.isFalse(buffer.asView().isEmpty()); } function test_equality() { final buffer = [ for (_ in 0...10) 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final fst = view.slice(0); final snd = view.slice(0); @@ -187,7 +189,7 @@ class TestView extends Test { function test_reinterpret_equal_size() { final buffer = [ for (_ in 0...10) 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final second : View = view.reinterpret(); Assert.equals(view.length, second.length); @@ -195,7 +197,7 @@ class TestView extends Test { function test_reinterpret_to_smaller_type() { final buffer = [ for (_ in 0...10) 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final second : View = view.reinterpret(); Assert.equals(view.length * 2, second.length); @@ -203,7 +205,7 @@ class TestView extends Test { function test_reinterpret_to_larger_type() { final buffer = [ for (_ in 0...3) 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final second : View = view.reinterpret(); Assert.equals(1, second.length); @@ -211,7 +213,7 @@ class TestView extends Test { function test_reinterpret_to_larger_type_not_enough_length() { final buffer = [ 0 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final second : View = view.reinterpret(); Assert.equals(0, second.length); @@ -219,7 +221,7 @@ class TestView extends Test { function test_reinterpret_to_value_type() { final buffer = [ 0f64, 0f64, 0f64, 0f64 ]; - final view = new View(Pointer.ofArray(buffer), buffer.length); + final view = buffer.asView(); final points = (view.reinterpret() : View); Assert.equals(2, points.length); diff --git a/test/native/tests/marshalling/view/TestViewExtensions.hx b/test/native/tests/marshalling/view/TestViewExtensions.hx new file mode 100644 index 000000000..667922ff0 --- /dev/null +++ b/test/native/tests/marshalling/view/TestViewExtensions.hx @@ -0,0 +1,169 @@ +package tests.marshalling.view; + +import haxe.io.UInt8Array; +import haxe.io.UInt16Array; +import haxe.io.UInt32Array; +import haxe.io.Int32Array; +import haxe.io.Float64Array; +import cpp.Float32; +import haxe.io.Float32Array; +import haxe.io.ArrayBufferView; +import haxe.io.Bytes; +import haxe.ds.Vector; +import cpp.Int64; +import cpp.UInt32; +import cpp.Int16; +import cpp.Pointer; +import cpp.marshal.View; +import utest.Test; +import utest.Assert; +import tests.marshalling.Point; + +using cpp.marshal.ViewExtensions; + +class TestViewExtensions extends Test { + function test_toArray() { + final source = 200; + final view = new View(Pointer.addressOf(source), 1); + final array = view.toArray(); + + Assert.same([ source ], array); + } + + function test_toVector() { + final source = 200; + final view = new View(Pointer.addressOf(source), 1); + final vector = view.toVector(); + + if (Assert.equals(1, vector.length)) { + Assert.equals(source, vector[0]); + } + } + + function test_toBytes() { + final source = 200; + final view = new View(Pointer.addressOf(source), 1); + final bytes = view.toBytes(); + + if (Assert.equals(4, bytes.length)) { + Assert.equals(source, bytes.getInt32(0)); + } + } + + function test_array_as_view() { + final array = [ 100, 200, 300, 400 ]; + final view = array.asView(); + + if (Assert.equals(array.length, view.length)) { + for (i in 0...array.length) { + Assert.equals(array[i], view[i]); + } + } + } + + function test_vector_as_view() { + final vector = Vector.fromData([ 100, 200, 300, 400 ]); + final view = vector.asView(); + + if (Assert.equals(vector.length, view.length)) { + for (i in 0...vector.length) { + Assert.equals(vector[i], view[i]); + } + } + } + + function test_bytes_as_view() { + final bytes = Bytes.ofData([ 10, 20, 30, 40 ]); + final view = bytes.asView(); + + if (Assert.equals(bytes.length, view.length)) { + for (i in 0...bytes.length) { + Assert.equals(bytes.get(i), view[i]); + } + } + } + + function test_array_buffer_view_as_view() { + final index = 7; + final buffer = ArrayBufferView.fromBytes(Bytes.ofData([ for (i in 0...100) i ])).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.byteLength, view.length)) { + for (i in 0...buffer.byteLength) { + Assert.equals(buffer.buffer.get(index + i), view[i]); + } + } + } + + function test_float32_array_as_view() { + final index = 7; + final buffer = Float32Array.fromArray([ for (i in 0...100) i ]).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.length, view.length)) { + for (i in 0...buffer.length) { + Assert.equals(buffer[i], view[i]); + } + } + } + + function test_float64_array_as_view() { + final index = 7; + final buffer = Float64Array.fromArray([ for (i in 0...100) i ]).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.length, view.length)) { + for (i in 0...buffer.length) { + Assert.equals(buffer[i], view[i]); + } + } + } + + function test_int32_array_as_view() { + final index = 7; + final buffer = Int32Array.fromArray([ for (i in 0...100) i ]).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.length, view.length)) { + for (i in 0...buffer.length) { + Assert.equals(buffer[i], view[i]); + } + } + } + + function test_uint32_array_as_view() { + final index = 7; + final buffer = UInt32Array.fromArray([ for (i in 0...100) i ]).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.length, view.length)) { + for (i in 0...buffer.length) { + Assert.equals(buffer[i], view[i]); + } + } + } + + function test_uint16_array_as_view() { + final index = 7; + final buffer = UInt16Array.fromArray([ for (i in 0...100) i ]).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.length, view.length)) { + for (i in 0...buffer.length) { + Assert.equals(buffer[i], view[i]); + } + } + } + + function test_uint8_array_as_view() { + final index = 7; + final buffer = UInt8Array.fromArray([ for (i in 0...100) i ]).sub(index, 10); + final view = buffer.asView(); + + if (Assert.equals(buffer.length, view.length)) { + for (i in 0...buffer.length) { + Assert.equals(buffer[i], view[i]); + } + } + } +} \ No newline at end of file From f3d750a6a2fc04f498387426ed5e4bd96f8e3cbe Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 18 Nov 2025 20:27:32 +0000 Subject: [PATCH 56/89] Split across multiple headers --- include/cpp/Marshal.h | 902 ----------------------- include/cpp/marshal/Boxed.hpp | 39 + include/cpp/marshal/Definitions.inc | 249 +++++++ include/cpp/marshal/Marshal.hpp | 74 ++ include/cpp/marshal/PointerReference.hpp | 170 +++++ include/cpp/marshal/PointerType.hpp | 68 ++ include/cpp/marshal/ValueReference.hpp | 137 ++++ include/cpp/marshal/ValueType.hpp | 74 ++ include/cpp/marshal/View.hpp | 95 +++ include/hxcpp.h | 8 +- toolchain/haxe-target.xml | 9 +- 11 files changed, 921 insertions(+), 904 deletions(-) delete mode 100644 include/cpp/Marshal.h create mode 100644 include/cpp/marshal/Boxed.hpp create mode 100644 include/cpp/marshal/Definitions.inc create mode 100644 include/cpp/marshal/Marshal.hpp create mode 100644 include/cpp/marshal/PointerReference.hpp create mode 100644 include/cpp/marshal/PointerType.hpp create mode 100644 include/cpp/marshal/ValueReference.hpp create mode 100644 include/cpp/marshal/ValueType.hpp create mode 100644 include/cpp/marshal/View.hpp diff --git a/include/cpp/Marshal.h b/include/cpp/Marshal.h deleted file mode 100644 index 845e851d7..000000000 --- a/include/cpp/Marshal.h +++ /dev/null @@ -1,902 +0,0 @@ -#ifndef CPP_MARSHAL_H -#define CPP_MARSHAL_H - -#include -#include -#include -#include - -namespace cpp -{ - namespace marshal - { - /// - /// 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. - /// - template - 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 - Boxed_obj(TArgs... args); - }; - - template - class ValueType final - { - static T FromReference(const ValueReference& inRHS); - static T FromBoxed(const Boxed& 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& inRHS); - ValueType(const null& inRHS); - ValueType(const Boxed& inRHS); - ValueType(const Variant& inRHS); - ValueType(const Dynamic& inRHS); - - template - ValueType(TArgs... args); - - ValueType& operator=(const ValueReference& inRHS); - ValueType& operator=(const null& inRHS); - }; - - template - class PointerType final - { - public: - using TPtr = T*; - - private: - static TPtr FromReference(const PointerReference& inRHS); - static TPtr FromBoxed(const Boxed& 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& inRHS); - PointerType(const null& inRHS); - PointerType(const Boxed& inRHS); - PointerType(const Variant& inRHS); - PointerType(const Dynamic& inRHS); - - PointerType& operator=(const PointerReference& inRHS); - PointerType& operator=(const null& inRHS); - }; - - template - class ValueReference final : public ::cpp::Reference - { - using Super = ::cpp::Reference; - - template - static O* FromDynamic(const Dynamic& inRHS); - template - static O* FromBoxed(const Boxed& inRHS); - Boxed ToBoxed() const; - - public: - // This allows 'StaticCast' to be used from arrays - using Ptr = Dynamic; - - ValueReference(const null& inRHS); - ValueReference(const ValueType& inRHS); - ValueReference(const Boxed& inRHS); - ValueReference(const T& inRHS); - ValueReference(T& inRHS); - ValueReference(const T* inRHS); - - template - ValueReference(const ValueReference& inRHS); - template - ValueReference(const ValueType& inRHS); - template - ValueReference(const Boxed& inRHS); - - ValueReference(const Variant& inRHS); - ValueReference(const Dynamic& inRHS); - - operator Dynamic() const; - operator Variant() const; - operator Boxed() const; - - T* operator->() const; - T operator*() const; - - bool operator==(const ValueReference& inRHS) const; - bool operator!=(const ValueReference& inRHS) const; - - template - K get(int index); - - template - void set(int index, K value); - }; - - template - class PointerReference final : public ::cpp::Reference - { - public: - using TPtr = T*; - - private: - using Super = ::cpp::Reference; - - template - static O* FromDynamic(const Dynamic& inRHS); - - template - static O* FromBoxed(const Boxed& inRHS); - - Boxed ToBoxed() const; - - public: - PointerReference(const null& inRHS); - PointerReference(const PointerType& inRHS); - PointerReference(const Boxed& inRHS); - - template - PointerReference(const PointerReference& inRHS); - template - PointerReference(const PointerType& inRHS); - template - PointerReference(const Boxed& 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() const; - operator Pointer() const; - - operator TPtr&(); - operator TPtr*(); - operator void*(); - operator void**(); - - TPtr operator->() const; - - template - K get(int index); - - template - void set(int index, K value); - }; - - template - struct View final - { - ::cpp::Pointer ptr; - int length; - - View(::cpp::Pointer _ptr, int _length); - - void clear(); - void fill(T value); - bool isEmpty(); - View slice(int index); - View slice(int index, int length); - bool tryCopyTo(const View& destination); - template View reinterpret(); - - bool operator==(const View& inRHS) const; - bool operator!=(const View& inRHS) const; - - T& operator[] (int index); - }; - - struct Marshal final - { - static View toCharView(const ::String& string); - static int toCharView(const ::String&, View buffer); - - static View toWideCharView(const ::String& string); - static int toWideCharView(const ::String& string, View buffer); - - static ::String toString(View buffer); - static ::String toString(View buffer); - - template static T read(View view); - template static void write(View view, const T& value); - }; - } -} - -// - -inline cpp::marshal::View cpp::marshal::Marshal::toCharView(const ::String& string) -{ - auto length = 0; - auto ptr = string.utf8_str(nullptr, true, &length); - - return View(const_cast(ptr), length + 1); -} - -inline int cpp::marshal::Marshal::toCharView(const ::String& string, View buffer) -{ - auto length = 0; - - if (string.utf8_str(buffer, &length)) - { - return length; - } - else - { - hx::Throw(HX_CSTRING("Not enough space in the view to write the string")); - - return 0; - } -} - -inline cpp::marshal::View cpp::marshal::Marshal::toWideCharView(const ::String& string) -{ - auto length = 0; - auto ptr = string.wc_str(nullptr, &length); - - return View(const_cast(ptr), length + 1); -} - -inline int cpp::marshal::Marshal::toWideCharView(const ::String& string, View buffer) -{ - auto length = 0; - - if (string.wc_str(buffer, &length)) - { - return length; - } - else - { - hx::Throw(HX_CSTRING("Not enough space in the view to write the string")); - - return 0; - } -} - -inline ::String cpp::marshal::Marshal::toString(View buffer) -{ - return ::String::create(buffer); -} - -inline ::String cpp::marshal::Marshal::toString(View buffer) -{ - return ::String::create(buffer); -} - -template -inline void cpp::marshal::Marshal::write(View view, const T& value) -{ - std::memcpy(view.ptr, reinterpret_cast(&value), sizeof(T)); -} - -template -inline T cpp::marshal::Marshal::read(View view) -{ - return *(reinterpret_cast(view.ptr.ptr)); -} - -// - -template -inline cpp::marshal::View::View(::cpp::Pointer _ptr, int _length) : ptr(_ptr), length(_length) {} - -template -inline bool cpp::marshal::View::tryCopyTo(const View& destination) -{ - if (destination.length < length) - { - return false; - } - - std::memcpy(destination.ptr.ptr, ptr.ptr, sizeof(T) * length); - - return true; -} - -template -inline void cpp::marshal::View::clear() -{ - std::memset(ptr, 0, sizeof(T) * length); -} - -template -inline void cpp::marshal::View::fill(T value) -{ - for (auto i = 0; i < length; i++) - { - ptr[i] = value; - } -} - -template -inline bool cpp::marshal::View::isEmpty() -{ - return length == 0; -} - -template -inline cpp::marshal::View cpp::marshal::View::slice(int index) -{ - return View(ptr + index, length - index); -} - -template -inline cpp::marshal::View cpp::marshal::View::slice(int index, int length) -{ - return View(ptr + index, length); -} - -template -template -inline cpp::marshal::View cpp::marshal::View::reinterpret() -{ - auto newPtr = ::cpp::Pointer{ ptr.reinterpret() }; - auto fromSize = sizeof(T); - auto toSize = sizeof(K); - - if (toSize == fromSize) - { - return cpp::marshal::View(newPtr, length); - } - if (toSize < fromSize) - { - return cpp::marshal::View(newPtr, length * (fromSize / toSize)); - } - - auto shrink = static_cast(fromSize) / toSize; - auto newLength = static_cast(std::floor(length * shrink)); - - return cpp::marshal::View(newPtr, newLength); -} - -template -inline bool cpp::marshal::View::operator==(const View& inRHS) const -{ - return length == inRHS.length && ptr.ptr == inRHS.ptr.ptr; -} - -template -inline bool cpp::marshal::View::operator!=(const View& inRHS) const -{ - return length != inRHS.length || ptr.ptr != inRHS.ptr.ptr; -} - -template -inline T& cpp::marshal::View::operator[](int index) -{ - return ptr[index]; -} - -// Boxed implementation - -template -inline void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) -{ - auto ptr = reinterpret_cast*>(obj); - - ptr->value.~T(); -} - -template -inline void cpp::marshal::Boxed_obj::setFinaliser(std::true_type) -{ - ::hx::GCSetFinalizer(this, finalise); -} - -template -inline void cpp::marshal::Boxed_obj::setFinaliser(std::false_type) {} - -template -inline cpp::marshal::Boxed_obj::Boxed_obj() : value() -{ - setFinaliser(std::is_destructible{}); -} - -template -inline cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) -{ - setFinaliser(std::is_destructible{}); -} - -template -template -inline cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value( std::forward(args)... ) -{ - setFinaliser(std::is_destructible{}); -} - -// Reference implementation - -template -template -inline O* cpp::marshal::ValueReference::FromDynamic(const Dynamic& inRHS) -{ - return FromBoxed(inRHS.StaticCast>()); -} - -template -template -inline O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) -{ - if (nullptr == inRHS.mPtr) - { - return nullptr; - } - - return const_cast(&inRHS->value); -} - -template -inline cpp::marshal::ValueReference::ValueReference(const null& inRHS) : Super(inRHS) {} - -template -inline cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(inRHS.value) {} - -template -inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} - -template -inline cpp::marshal::ValueReference::ValueReference(const T& inRHS) : Super(inRHS) {} - -template -inline cpp::marshal::ValueReference::ValueReference(T& inRHS) : Super(inRHS) {} - -template -inline cpp::marshal::ValueReference::ValueReference(const T* inRHS) : Super(inRHS) {} - -template -template -inline cpp::marshal::ValueReference::ValueReference(const ValueReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} - -template -template -inline cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} - -template -template -inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} - -template -template -inline K cpp::marshal::ValueReference::get(int index) -{ - return (*Super::ptr)[index]; -} - -template -template -inline void cpp::marshal::ValueReference::set(int index, K value) -{ - (*Super::ptr)[index] = value; -} - -template -inline cpp::marshal::ValueReference::ValueReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} - -template -inline cpp::marshal::ValueReference::ValueReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} - -template -inline cpp::marshal::Boxed cpp::marshal::ValueReference::ToBoxed() const -{ - if (Super::ptr) - { - return Boxed(new Boxed_obj(Super::ptr)); - } - else - { - return Boxed(); - } -} - -template -inline cpp::marshal::ValueReference::operator ::Dynamic() const -{ - return ToBoxed(); -} - -template -inline cpp::marshal::ValueReference::operator ::cpp::Variant() const -{ - return ToBoxed(); -} - -template -inline cpp::marshal::ValueReference::operator ::cpp::marshal::Boxed() const -{ - return ToBoxed(); -} - -template -inline T* cpp::marshal::ValueReference::operator ->() const -{ - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return Super::ptr; -} - -template -inline bool cpp::marshal::ValueReference::operator==(const ValueReference& inRHS) const -{ - return (*Super::ptr) == (*inRHS.ptr); -} - -template -inline bool cpp::marshal::ValueReference::operator!=(const ValueReference& inRHS) const -{ - return (*Super::ptr) != (*inRHS.ptr); -} - -template -inline T cpp::marshal::ValueReference::operator*() const -{ - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return *Super::ptr; -} - -// Pointer implementation - -template -inline cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const -{ - if (nullptr == Super::ptr) - { - return new Boxed_obj(); - } - else - { - return new Boxed_obj(Super::ptr); - } -} - -template -template -inline O* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) -{ - if (nullptr == inRHS.mPtr) - { - return nullptr; - } - - return const_cast(&inRHS->value); -} - -template -template -inline O* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) -{ - return FromBoxed(inRHS.StaticCast>()); -} - -template -inline cpp::marshal::PointerReference::PointerReference(const null& inRHS) : Super(inRHS) {} - -template -inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(const_cast(&inRHS.value)) {} - -template -inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} - -template -template -inline cpp::marshal::PointerReference::PointerReference(const PointerReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} - -template -template -inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} - -template -template -inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} - -template -template -inline K cpp::marshal::PointerReference::get(int index) -{ - return (*Super::ptr)[index]; -} - -template -template -inline void cpp::marshal::PointerReference::set(int index, K value) -{ - (*Super::ptr)[index] = value; -} - -template -inline cpp::marshal::PointerReference::PointerReference(const TPtr& inRHS) : Super(inRHS) {} - -template -inline cpp::marshal::PointerReference::PointerReference(TPtr& inRHS) -{ - if (nullptr != inRHS) - { - Super::ptr = &inRHS; - } -} - -template -inline cpp::marshal::PointerReference::PointerReference(const TPtr* inRHS) : Super(inRHS) {} - -template -inline cpp::marshal::PointerReference::PointerReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} - -template -inline cpp::marshal::PointerReference::PointerReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} - -template -inline cpp::marshal::PointerReference::operator ::Dynamic() const -{ - return ToBoxed(); -} - -template -inline cpp::marshal::PointerReference::operator ::cpp::Variant() const -{ - return ToBoxed(); -} - -template -inline cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const -{ - return ToBoxed(); -} - -template -inline cpp::marshal::PointerReference::operator ::cpp::Pointer() const -{ - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return ::cpp::Pointer(*Super::ptr); -} - -template -inline cpp::marshal::PointerReference::operator TPtr&() -{ - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return *Super::ptr; -} - -template -inline cpp::marshal::PointerReference::operator TPtr* () -{ - return Super::ptr; -} - -template -inline cpp::marshal::PointerReference::operator void* () -{ - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return *Super::ptr; -} - -template -inline cpp::marshal::PointerReference::operator void** () -{ - return reinterpret_cast(Super::ptr); -} - -template -inline T* cpp::marshal::PointerReference::operator->() const -{ - if (nullptr == Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - if (nullptr == *Super::ptr) - { - ::hx::NullReference("ValueType", true); - } - - return *Super::ptr; -} - -// - -template -inline T* cpp::marshal::PointerType::FromDynamic(const Dynamic& inRHS) -{ - return FromBoxed(inRHS.StaticCast>()); -} - -template -inline T* cpp::marshal::PointerType::FromBoxed(const Boxed& inRHS) -{ - if (nullptr == inRHS.mPtr) - { - return nullptr; - } - - return inRHS->value; -} - -template -inline T* cpp::marshal::PointerType::FromReference(const PointerReference& inRHS) -{ - if (nullptr == inRHS.ptr) - { - return nullptr; - } - - return *inRHS.ptr; -} - -template -inline cpp::marshal::PointerType::PointerType() : value(nullptr) {} - -template -inline cpp::marshal::PointerType::PointerType(TPtr inRHS) : value(inRHS) {} - -template -inline cpp::marshal::PointerType::PointerType(const PointerReference& inRHS) : value(FromReference(inRHS.ptr)) {} - -template -inline cpp::marshal::PointerType::PointerType(const null&) : value(nullptr) {} - -template -inline cpp::marshal::PointerType::PointerType(const Boxed& inRHS) : value(FromBoxed(inRHS)) {} - -template -inline cpp::marshal::PointerType::PointerType(const Variant& inRHS) : value(FromDynamic(inRHS)) {} - -template -inline cpp::marshal::PointerType::PointerType(const Dynamic& inRHS) : value(FromDynamic(inRHS)) {} - -template -inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(const PointerReference& inRHS) -{ - value = *inRHS.ptr; - - return *this; -} - -template -inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(const null& inRHS) -{ - value = nullptr; - - return *this; -} - -// ValueType implementation - -template -inline T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) -{ - return FromBoxed(inRHS.StaticCast>()); -} - -template -inline T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) -{ - if (nullptr == inRHS.mPtr) - { - ::hx::NullReference("ValueType", true); - } - - return inRHS->value; -} - -template -inline T cpp::marshal::ValueType::FromReference(const ValueReference& inRHS) -{ - if (nullptr == inRHS.ptr) - { - ::hx::NullReference("ValueType", true); - } - - return *inRHS.ptr; -} - -template -inline cpp::marshal::ValueType::ValueType() : value() {} - -template -inline cpp::marshal::ValueType::ValueType(const ValueReference& inRHS) : value(FromReference(inRHS.ptr)) {} - -template -inline cpp::marshal::ValueType::ValueType(const null& inRHS) : ValueType(::cpp::marshal::ValueReference(inRHS)) {} - -template -inline cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::ValueReference(FromBoxed(inRHS))) {} - -template -inline cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS.asDynamic()))) {} - -template -inline cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS))) {} - -template -template -inline cpp::marshal::ValueType::ValueType(TArgs... args) : value( std::forward(args)... ) {} - -template -inline cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const ValueReference& inRHS) -{ - if (nullptr == inRHS.ptr) - { - ::hx::NullReference("ValueType", true); - } - - value = *inRHS.ptr; - - return *this; -} - -template -inline cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& inRHS) -{ - ::hx::NullReference("ValueType", true); - - return *this; -} - -// Implement some pointer helpers here - -template -inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::ValueReference& ref) -{ - return Pointer(ref.ptr); -} - -template -inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::PointerReference& ref) -{ - return Pointer(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 -inline cpp::Pointer::Pointer(const ::cpp::marshal::PointerReference ref) -{ - ptr = *ref.ptr; -} - -#endif \ No newline at end of file diff --git a/include/cpp/marshal/Boxed.hpp b/include/cpp/marshal/Boxed.hpp new file mode 100644 index 000000000..b92556609 --- /dev/null +++ b/include/cpp/marshal/Boxed.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "Definitions.inc" + +template +inline void cpp::marshal::Boxed_obj::finalise(::hx::Object* obj) +{ + auto ptr = reinterpret_cast*>(obj); + + ptr->value.~T(); +} + +template +inline void cpp::marshal::Boxed_obj::setFinaliser(std::true_type) +{ + ::hx::GCSetFinalizer(this, finalise); +} + +template +inline void cpp::marshal::Boxed_obj::setFinaliser(std::false_type) {} + +template +inline cpp::marshal::Boxed_obj::Boxed_obj() : value() +{ + setFinaliser(std::is_destructible{}); +} + +template +inline cpp::marshal::Boxed_obj::Boxed_obj(T* ptr) : value(*ptr) +{ + setFinaliser(std::is_destructible{}); +} + +template +template +inline cpp::marshal::Boxed_obj::Boxed_obj(TArgs... args) : value(std::forward(args)...) +{ + setFinaliser(std::is_destructible{}); +} \ No newline at end of file diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc new file mode 100644 index 000000000..9274f9e92 --- /dev/null +++ b/include/cpp/marshal/Definitions.inc @@ -0,0 +1,249 @@ +#pragma once + +#include + +namespace cpp +{ + namespace marshal + { + /// + /// 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. + /// + template + 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 + Boxed_obj(TArgs... args); + }; + + template + class ValueType final + { + static T FromReference(const ValueReference& inRHS); + static T FromBoxed(const Boxed& 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& inRHS); + ValueType(const null& inRHS); + ValueType(const Boxed& inRHS); + ValueType(const Variant& inRHS); + ValueType(const Dynamic& inRHS); + + template + ValueType(TArgs... args); + + ValueType& operator=(const ValueReference& inRHS); + ValueType& operator=(const null& inRHS); + }; + + template + class PointerType final + { + public: + using TPtr = T*; + + private: + static TPtr FromReference(const PointerReference& inRHS); + static TPtr FromBoxed(const Boxed& 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& inRHS); + PointerType(const null& inRHS); + PointerType(const Boxed& inRHS); + PointerType(const Variant& inRHS); + PointerType(const Dynamic& inRHS); + + PointerType& operator=(const PointerReference& inRHS); + PointerType& operator=(const null& inRHS); + }; + + template + class ValueReference final : public ::cpp::Reference + { + using Super = ::cpp::Reference; + + template + static O* FromDynamic(const Dynamic& inRHS); + template + static O* FromBoxed(const Boxed& inRHS); + Boxed ToBoxed() const; + + public: + // This allows 'StaticCast' to be used from arrays + using Ptr = Dynamic; + + ValueReference(const null& inRHS); + ValueReference(const ValueType& inRHS); + ValueReference(const Boxed& inRHS); + ValueReference(const T& inRHS); + ValueReference(T& inRHS); + ValueReference(const T* inRHS); + + template + ValueReference(const ValueReference& inRHS); + template + ValueReference(const ValueType& inRHS); + template + ValueReference(const Boxed& inRHS); + + ValueReference(const Variant& inRHS); + ValueReference(const Dynamic& inRHS); + + operator Dynamic() const; + operator Variant() const; + operator Boxed() const; + + T* operator->() const; + T operator*() const; + + bool operator==(const ValueReference& inRHS) const; + bool operator!=(const ValueReference& inRHS) const; + + template + K get(int index); + + template + void set(int index, K value); + }; + + template + class PointerReference final : public ::cpp::Reference + { + public: + using TPtr = T*; + + private: + using Super = ::cpp::Reference; + + template + static O* FromDynamic(const Dynamic& inRHS); + + template + static O* FromBoxed(const Boxed& inRHS); + + Boxed ToBoxed() const; + + public: + PointerReference(const null& inRHS); + PointerReference(const PointerType& inRHS); + PointerReference(const Boxed& inRHS); + + template + PointerReference(const PointerReference& inRHS); + template + PointerReference(const PointerType& inRHS); + template + PointerReference(const Boxed& 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() const; + operator Pointer() const; + + operator TPtr&(); + operator TPtr*(); + operator void*(); + operator void**(); + + TPtr operator->() const; + + template + K get(int index); + + template + void set(int index, K value); + }; + + template + struct View final + { + ::cpp::Pointer ptr; + int length; + + View(::cpp::Pointer _ptr, int _length); + + void clear(); + void fill(T value); + bool isEmpty(); + View slice(int index); + View slice(int index, int length); + bool tryCopyTo(const View& destination); + template View reinterpret(); + + bool operator==(const View& inRHS) const; + bool operator!=(const View& inRHS) const; + + T& operator[] (int index); + }; + + struct Marshal final + { + static View toCharView(const ::String& string); + static int toCharView(const ::String&, View buffer); + + static View toWideCharView(const ::String& string); + static int toWideCharView(const ::String& string, View buffer); + + static ::String toString(View buffer); + static ::String toString(View buffer); + + template static T read(View view); + template static void write(View view, const T& value); + }; + } +} + +// Implement some pointer helpers here + +template +inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::ValueReference& ref) +{ + return Pointer(ref.ptr); +} + +template +inline cpp::Pointer cpp::Pointer_obj::addressOf(const ::cpp::marshal::PointerReference& ref) +{ + return Pointer(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 +inline cpp::Pointer::Pointer(const ::cpp::marshal::PointerReference ref) +{ + ptr = *ref.ptr; +} \ No newline at end of file diff --git a/include/cpp/marshal/Marshal.hpp b/include/cpp/marshal/Marshal.hpp new file mode 100644 index 000000000..28aa0655e --- /dev/null +++ b/include/cpp/marshal/Marshal.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "Definitions.inc" +#include + +inline cpp::marshal::View cpp::marshal::Marshal::toCharView(const ::String& string) +{ + auto length = 0; + auto ptr = string.utf8_str(nullptr, true, &length); + + return View(const_cast(ptr), length + 1); +} + +inline int cpp::marshal::Marshal::toCharView(const ::String& string, View buffer) +{ + auto length = 0; + + if (string.utf8_str(buffer, &length)) + { + return length; + } + else + { + hx::Throw(HX_CSTRING("Not enough space in the view to write the string")); + + return 0; + } +} + +inline cpp::marshal::View cpp::marshal::Marshal::toWideCharView(const ::String& string) +{ + auto length = 0; + auto ptr = string.wc_str(nullptr, &length); + + return View(const_cast(ptr), length + 1); +} + +inline int cpp::marshal::Marshal::toWideCharView(const ::String& string, View buffer) +{ + auto length = 0; + + if (string.wc_str(buffer, &length)) + { + return length; + } + else + { + hx::Throw(HX_CSTRING("Not enough space in the view to write the string")); + + return 0; + } +} + +inline ::String cpp::marshal::Marshal::toString(View buffer) +{ + return ::String::create(buffer); +} + +inline ::String cpp::marshal::Marshal::toString(View buffer) +{ + return ::String::create(buffer); +} + +template +inline void cpp::marshal::Marshal::write(View view, const T& value) +{ + std::memcpy(view.ptr, reinterpret_cast(&value), sizeof(T)); +} + +template +inline T cpp::marshal::Marshal::read(View view) +{ + return *(reinterpret_cast(view.ptr.ptr)); +} \ No newline at end of file diff --git a/include/cpp/marshal/PointerReference.hpp b/include/cpp/marshal/PointerReference.hpp new file mode 100644 index 000000000..41830620e --- /dev/null +++ b/include/cpp/marshal/PointerReference.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include "Definitions.inc" + +template +inline cpp::marshal::Boxed cpp::marshal::PointerReference::ToBoxed() const +{ + if (nullptr == Super::ptr) + { + return new Boxed_obj(); + } + else + { + return new Boxed_obj(Super::ptr); + } +} + +template +template +inline O* cpp::marshal::PointerReference::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return const_cast(&inRHS->value); +} + +template +template +inline O* cpp::marshal::PointerReference::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); +} + +template +inline cpp::marshal::PointerReference::PointerReference(const null& inRHS) : Super(inRHS) {} + +template +inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(const_cast(&inRHS.value)) {} + +template +inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} + +template +template +inline cpp::marshal::PointerReference::PointerReference(const PointerReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} + +template +template +inline cpp::marshal::PointerReference::PointerReference(const PointerType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} + +template +template +inline cpp::marshal::PointerReference::PointerReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} + +template +template +inline K cpp::marshal::PointerReference::get(int index) +{ + return (*Super::ptr)[index]; +} + +template +template +inline void cpp::marshal::PointerReference::set(int index, K value) +{ + (*Super::ptr)[index] = value; +} + +template +inline cpp::marshal::PointerReference::PointerReference(const TPtr& inRHS) : Super(inRHS) {} + +template +inline cpp::marshal::PointerReference::PointerReference(TPtr& inRHS) +{ + if (nullptr != inRHS) + { + Super::ptr = &inRHS; + } +} + +template +inline cpp::marshal::PointerReference::PointerReference(const TPtr* inRHS) : Super(inRHS) {} + +template +inline cpp::marshal::PointerReference::PointerReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::PointerReference::PointerReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::PointerReference::operator ::Dynamic() const +{ + return ToBoxed(); +} + +template +inline cpp::marshal::PointerReference::operator ::cpp::Variant() const +{ + return ToBoxed(); +} + +template +inline cpp::marshal::PointerReference::operator ::cpp::marshal::Boxed() const +{ + return ToBoxed(); +} + +template +inline cpp::marshal::PointerReference::operator ::cpp::Pointer() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return ::cpp::Pointer(*Super::ptr); +} + +template +inline cpp::marshal::PointerReference::operator TPtr& () +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *Super::ptr; +} + +template +inline cpp::marshal::PointerReference::operator TPtr* () +{ + return Super::ptr; +} + +template +inline cpp::marshal::PointerReference::operator void* () +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *Super::ptr; +} + +template +inline cpp::marshal::PointerReference::operator void** () +{ + return reinterpret_cast(Super::ptr); +} + +template +inline T* cpp::marshal::PointerReference::operator->() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + if (nullptr == *Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *Super::ptr; +} \ No newline at end of file diff --git a/include/cpp/marshal/PointerType.hpp b/include/cpp/marshal/PointerType.hpp new file mode 100644 index 000000000..e2bd26af2 --- /dev/null +++ b/include/cpp/marshal/PointerType.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "Definitions.inc" + +template +inline T* cpp::marshal::PointerType::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); +} + +template +inline T* cpp::marshal::PointerType::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return inRHS->value; +} + +template +inline T* cpp::marshal::PointerType::FromReference(const PointerReference& inRHS) +{ + if (nullptr == inRHS.ptr) + { + return nullptr; + } + + return *inRHS.ptr; +} + +template +inline cpp::marshal::PointerType::PointerType() : value(nullptr) {} + +template +inline cpp::marshal::PointerType::PointerType(TPtr inRHS) : value(inRHS) {} + +template +inline cpp::marshal::PointerType::PointerType(const PointerReference& inRHS) : value(FromReference(inRHS.ptr)) {} + +template +inline cpp::marshal::PointerType::PointerType(const null&) : value(nullptr) {} + +template +inline cpp::marshal::PointerType::PointerType(const Boxed& inRHS) : value(FromBoxed(inRHS)) {} + +template +inline cpp::marshal::PointerType::PointerType(const Variant& inRHS) : value(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::PointerType::PointerType(const Dynamic& inRHS) : value(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(const PointerReference& inRHS) +{ + value = *inRHS.ptr; + + return *this; +} + +template +inline cpp::marshal::PointerType& cpp::marshal::PointerType::operator=(const null& inRHS) +{ + value = nullptr; + + return *this; +} \ No newline at end of file diff --git a/include/cpp/marshal/ValueReference.hpp b/include/cpp/marshal/ValueReference.hpp new file mode 100644 index 000000000..e2aaec3df --- /dev/null +++ b/include/cpp/marshal/ValueReference.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include "Definitions.inc" + +template +template +inline O* cpp::marshal::ValueReference::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); +} + +template +template +inline O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + return nullptr; + } + + return const_cast(&inRHS->value); +} + +template +inline cpp::marshal::ValueReference::ValueReference(const null& inRHS) : Super(inRHS) {} + +template +inline cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(inRHS.value) {} + +template +inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(FromBoxed(inRHS)) {} + +template +inline cpp::marshal::ValueReference::ValueReference(const T& inRHS) : Super(inRHS) {} + +template +inline cpp::marshal::ValueReference::ValueReference(T& inRHS) : Super(inRHS) {} + +template +inline cpp::marshal::ValueReference::ValueReference(const T* inRHS) : Super(inRHS) {} + +template +template +inline cpp::marshal::ValueReference::ValueReference(const ValueReference& inRHS) : Super(reinterpret_cast(const_cast(inRHS.ptr))) {} + +template +template +inline cpp::marshal::ValueReference::ValueReference(const ValueType& inRHS) : Super(reinterpret_cast(const_cast(&inRHS.value))) {} + +template +template +inline cpp::marshal::ValueReference::ValueReference(const Boxed& inRHS) : Super(reinterpret_cast(FromBoxed(inRHS))) {} + +template +template +inline K cpp::marshal::ValueReference::get(int index) +{ + return (*Super::ptr)[index]; +} + +template +template +inline void cpp::marshal::ValueReference::set(int index, K value) +{ + (*Super::ptr)[index] = value; +} + +template +inline cpp::marshal::ValueReference::ValueReference(const Variant& inRHS) : Super(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::ValueReference::ValueReference(const Dynamic& inRHS) : Super(FromDynamic(inRHS)) {} + +template +inline cpp::marshal::Boxed cpp::marshal::ValueReference::ToBoxed() const +{ + if (Super::ptr) + { + return Boxed(new Boxed_obj(Super::ptr)); + } + else + { + return Boxed(); + } +} + +template +inline cpp::marshal::ValueReference::operator ::Dynamic() const +{ + return ToBoxed(); +} + +template +inline cpp::marshal::ValueReference::operator ::cpp::Variant() const +{ + return ToBoxed(); +} + +template +inline cpp::marshal::ValueReference::operator ::cpp::marshal::Boxed() const +{ + return ToBoxed(); +} + +template +inline T* cpp::marshal::ValueReference::operator ->() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return Super::ptr; +} + +template +inline bool cpp::marshal::ValueReference::operator==(const ValueReference& inRHS) const +{ + return (*Super::ptr) == (*inRHS.ptr); +} + +template +inline bool cpp::marshal::ValueReference::operator!=(const ValueReference& inRHS) const +{ + return (*Super::ptr) != (*inRHS.ptr); +} + +template +inline T cpp::marshal::ValueReference::operator*() const +{ + if (nullptr == Super::ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *Super::ptr; +} \ No newline at end of file diff --git a/include/cpp/marshal/ValueType.hpp b/include/cpp/marshal/ValueType.hpp new file mode 100644 index 000000000..70e530939 --- /dev/null +++ b/include/cpp/marshal/ValueType.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "Definitions.inc" + +template +inline T cpp::marshal::ValueType::FromDynamic(const Dynamic& inRHS) +{ + return FromBoxed(inRHS.StaticCast>()); +} + +template +inline T cpp::marshal::ValueType::FromBoxed(const Boxed& inRHS) +{ + if (nullptr == inRHS.mPtr) + { + ::hx::NullReference("ValueType", true); + } + + return inRHS->value; +} + +template +inline T cpp::marshal::ValueType::FromReference(const ValueReference& inRHS) +{ + if (nullptr == inRHS.ptr) + { + ::hx::NullReference("ValueType", true); + } + + return *inRHS.ptr; +} + +template +inline cpp::marshal::ValueType::ValueType() : value() {} + +template +inline cpp::marshal::ValueType::ValueType(const ValueReference& inRHS) : value(FromReference(inRHS.ptr)) {} + +template +inline cpp::marshal::ValueType::ValueType(const null& inRHS) : ValueType(::cpp::marshal::ValueReference(inRHS)) {} + +template +inline cpp::marshal::ValueType::ValueType(const Boxed& inRHS) : ValueType(::cpp::marshal::ValueReference(FromBoxed(inRHS))) {} + +template +inline cpp::marshal::ValueType::ValueType(const Variant& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS.asDynamic()))) {} + +template +inline cpp::marshal::ValueType::ValueType(const Dynamic& inRHS) : ValueType(::cpp::marshal::ValueReference(FromDynamic(inRHS))) {} + +template +template +inline cpp::marshal::ValueType::ValueType(TArgs... args) : value(std::forward(args)...) {} + +template +inline cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const ValueReference& inRHS) +{ + if (nullptr == inRHS.ptr) + { + ::hx::NullReference("ValueType", true); + } + + value = *inRHS.ptr; + + return *this; +} + +template +inline cpp::marshal::ValueType& cpp::marshal::ValueType::operator=(const null& inRHS) +{ + ::hx::NullReference("ValueType", true); + + return *this; +} \ No newline at end of file diff --git a/include/cpp/marshal/View.hpp b/include/cpp/marshal/View.hpp new file mode 100644 index 000000000..d6675560a --- /dev/null +++ b/include/cpp/marshal/View.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include "Definitions.inc" +#include +#include + +template +inline cpp::marshal::View::View(::cpp::Pointer _ptr, int _length) : ptr(_ptr), length(_length) {} + +template +inline bool cpp::marshal::View::tryCopyTo(const View& destination) +{ + if (destination.length < length) + { + return false; + } + + std::memcpy(destination.ptr.ptr, ptr.ptr, sizeof(T) * length); + + return true; +} + +template +inline void cpp::marshal::View::clear() +{ + std::memset(ptr, 0, sizeof(T) * length); +} + +template +inline void cpp::marshal::View::fill(T value) +{ + for (auto i = 0; i < length; i++) + { + ptr[i] = value; + } +} + +template +inline bool cpp::marshal::View::isEmpty() +{ + return length == 0; +} + +template +inline cpp::marshal::View cpp::marshal::View::slice(int index) +{ + return View(ptr + index, length - index); +} + +template +inline cpp::marshal::View cpp::marshal::View::slice(int index, int length) +{ + return View(ptr + index, length); +} + +template +template +inline cpp::marshal::View cpp::marshal::View::reinterpret() +{ + auto newPtr = ::cpp::Pointer{ ptr.reinterpret() }; + auto fromSize = sizeof(T); + auto toSize = sizeof(K); + + if (toSize == fromSize) + { + return cpp::marshal::View(newPtr, length); + } + if (toSize < fromSize) + { + return cpp::marshal::View(newPtr, length * (fromSize / toSize)); + } + + auto shrink = static_cast(fromSize) / toSize; + auto newLength = static_cast(std::floor(length * shrink)); + + return cpp::marshal::View(newPtr, newLength); +} + +template +inline bool cpp::marshal::View::operator==(const View& inRHS) const +{ + return length == inRHS.length && ptr.ptr == inRHS.ptr.ptr; +} + +template +inline bool cpp::marshal::View::operator!=(const View& inRHS) const +{ + return length != inRHS.length || ptr.ptr != inRHS.ptr.ptr; +} + +template +inline T& cpp::marshal::View::operator[](int index) +{ + return ptr[index]; +} \ No newline at end of file diff --git a/include/hxcpp.h b/include/hxcpp.h index 9ece840f5..ad4efd2d8 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -355,7 +355,13 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/toolchain/haxe-target.xml b/toolchain/haxe-target.xml index 34950e649..a5aa5ea5d 100644 --- a/toolchain/haxe-target.xml +++ b/toolchain/haxe-target.xml @@ -57,10 +57,17 @@ - + + + + + + + +
From 5f991def3db7381782d0237b8db0263c7e9946f2 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 18 Nov 2025 21:20:13 +0000 Subject: [PATCH 57/89] typed read and write helper functions --- include/cpp/marshal/Definitions.inc | 29 +++++++ include/cpp/marshal/Marshal.hpp | 116 +++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 2 deletions(-) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index 9274f9e92..39cd85883 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -212,6 +212,12 @@ namespace cpp struct Marshal final { +#ifdef HXCPP_BIG_ENDIAN + static const bool isBigEndian = true; +#else + static const bool isBigEndian = false; +#endif + static View toCharView(const ::String& string); static int toCharView(const ::String&, View buffer); @@ -222,7 +228,30 @@ namespace cpp static ::String toString(View buffer); template static T read(View view); + template static ::cpp::Pointer readPointer(View view); + static int8_t readInt8(View view); + static int16_t readInt16(View view); + static int32_t readInt32(View view); + static int64_t readInt64(View view); + static uint8_t readUInt8(View view); + static uint16_t readUInt16(View view); + static uint32_t readUInt32(View view); + static uint64_t readUInt64(View view); + static float readFloat32(View view); + static double readFloat64(View view); + template static void write(View view, const T& value); + template static void writePointer(View view, const Pointer& value); + static void writeInt8(View view, const int8_t& value); + static void writeInt16(View view, const int16_t& value); + static void writeInt32(View view, const int32_t& value); + static void writeInt64(View view, const int64_t& value); + static void writeUInt8(View view, const uint8_t& value); + static void writeUInt16(View view, const uint16_t& value); + static void writeUInt32(View view, const uint32_t& value); + static void writeUInt64(View view, const uint64_t& value); + static void writeFloat32(View view, const float& value); + static void writeFloat64(View view, const double& value); }; } } diff --git a/include/cpp/marshal/Marshal.hpp b/include/cpp/marshal/Marshal.hpp index 28aa0655e..8e0c56d51 100644 --- a/include/cpp/marshal/Marshal.hpp +++ b/include/cpp/marshal/Marshal.hpp @@ -61,6 +61,68 @@ inline ::String cpp::marshal::Marshal::toString(View buffer) return ::String::create(buffer); } +template +inline T cpp::marshal::Marshal::read(View view) +{ + return *(reinterpret_cast(view.ptr.ptr)); +} + +template +inline ::cpp::Pointer cpp::marshal::Marshal::readPointer(View view) +{ + return read(view); +} + +inline int8_t cpp::marshal::Marshal::readInt8(View view) +{ + return read(view); +} + +inline int16_t cpp::marshal::Marshal::readInt16(View view) +{ + return read(view); +} + +inline int32_t cpp::marshal::Marshal::readInt32(View view) +{ + return read(view); +} + +inline int64_t cpp::marshal::Marshal::readInt64(View view) +{ + return read(view); +} + +inline uint8_t cpp::marshal::Marshal::readUInt8(View view) +{ + return read(view); +} + +inline uint16_t cpp::marshal::Marshal::readUInt16(View view) +{ + return read(view); +} + +inline uint32_t cpp::marshal::Marshal::readUInt32(View view) +{ + return read(view); +} + +inline uint64_t cpp::marshal::Marshal::readUInt64(View view) +{ + return read(view); +} + +inline float cpp::marshal::Marshal::readFloat32(View view) +{ + return read(view); +} + +inline double cpp::marshal::Marshal::readFloat64(View view) +{ + return read(view); +} + template inline void cpp::marshal::Marshal::write(View view, const T& value) { @@ -68,7 +130,57 @@ inline void cpp::marshal::Marshal::write(View view, const T& value) } template -inline T cpp::marshal::Marshal::read(View view) +inline void cpp::marshal::Marshal::writePointer(View view, const ::cpp::Pointer& value) { - return *(reinterpret_cast(view.ptr.ptr)); + write(view, value.ptr); +} + +inline void cpp::marshal::Marshal::writeInt8(View view, const int8_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeInt16(View view, const int16_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeInt32(View view, const int32_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeInt64(View view, const int64_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeUInt8(View view, const uint8_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeUInt16(View view, const uint16_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeUInt32(View view, const uint32_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeUInt64(View view, const uint64_t& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeFloat32(View view, const float& value) +{ + write(view, value); +} + +inline void cpp::marshal::Marshal::writeFloat64(View view, const double& value) +{ + write(view, value); } \ No newline at end of file From 40e7fa1aceefe99755ecd9af6f1a392946611ca6 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Tue, 18 Nov 2025 21:38:33 +0000 Subject: [PATCH 58/89] Add compare function --- include/cpp/marshal/Definitions.inc | 1 + include/cpp/marshal/View.hpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index 39cd85883..1635aab40 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -203,6 +203,7 @@ namespace cpp View slice(int index, int length); bool tryCopyTo(const View& destination); template View reinterpret(); + int compare(const View& inRHS); bool operator==(const View& inRHS) const; bool operator!=(const View& inRHS) const; diff --git a/include/cpp/marshal/View.hpp b/include/cpp/marshal/View.hpp index d6675560a..19d09add5 100644 --- a/include/cpp/marshal/View.hpp +++ b/include/cpp/marshal/View.hpp @@ -76,6 +76,12 @@ inline cpp::marshal::View cpp::marshal::View::reinterpret() return cpp::marshal::View(newPtr, newLength); } +template +inline int cpp::marshal::View::compare(const View& inRHS) +{ + return std::memcmp(ptr.ptr, inRHS.ptr.ptr, sizeof(T) * length); +} + template inline bool cpp::marshal::View::operator==(const View& inRHS) const { From 45c112e26a33835c8b9477252363820ba88d5faa Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 23 Nov 2025 15:11:45 +0000 Subject: [PATCH 59/89] Some new typed zip work --- include/hx/zip/Compress.hpp | 20 +++++++++ include/hx/zip/Uncompress.hpp | 34 +++++++++++++++ src/hx/libs/zlib/Build.xml | 2 + src/hx/libs/zlib/ZLibCompress.cpp | 17 ++++++++ src/hx/libs/zlib/ZLibCompress.hpp | 25 +++++++++++ src/hx/libs/zlib/ZLibUncompress.cpp | 68 +++++++++++++++++++++++++++++ src/hx/libs/zlib/ZlibUncompress.hpp | 25 +++++++++++ 7 files changed, 191 insertions(+) create mode 100644 include/hx/zip/Compress.hpp create mode 100644 include/hx/zip/Uncompress.hpp create mode 100644 src/hx/libs/zlib/ZLibCompress.cpp create mode 100644 src/hx/libs/zlib/ZLibCompress.hpp create mode 100644 src/hx/libs/zlib/ZLibUncompress.cpp create mode 100644 src/hx/libs/zlib/ZlibUncompress.hpp diff --git a/include/hx/zip/Compress.hpp b/include/hx/zip/Compress.hpp new file mode 100644 index 000000000..cf8831284 --- /dev/null +++ b/include/hx/zip/Compress.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +HX_DECLARE_CLASS2(hx, zip, Compress) + +namespace hx +{ + namespace zip + { + struct Compress_obj : hx::Object + { + static Compress create(int level); + + virtual void execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; + virtual void setFlushMode(int mode) = 0; + virtual void close() = 0; + }; + } +} diff --git a/include/hx/zip/Uncompress.hpp b/include/hx/zip/Uncompress.hpp new file mode 100644 index 000000000..772cf3825 --- /dev/null +++ b/include/hx/zip/Uncompress.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +HX_DECLARE_CLASS2(hx, zip, Uncompress) + +namespace hx +{ + namespace zip + { + struct UncompressResult final { + bool done; + int read; + int write; + + UncompressResult() = default; + }; + + struct Uncompress_obj : hx::Object + { + static int flushNone; + static int flushSync; + static int flushFull; + static int flushFinish; + static int flushBlock; + + static Uncompress create(int windowSize); + + virtual UncompressResult execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; + virtual void setFlushMode(int mode) = 0; + virtual void close() = 0; + }; + } +} diff --git a/src/hx/libs/zlib/Build.xml b/src/hx/libs/zlib/Build.xml index c7549ba6d..dd1678ea7 100644 --- a/src/hx/libs/zlib/Build.xml +++ b/src/hx/libs/zlib/Build.xml @@ -10,10 +10,12 @@ + +
diff --git a/src/hx/libs/zlib/ZLibCompress.cpp b/src/hx/libs/zlib/ZLibCompress.cpp new file mode 100644 index 000000000..a23638b4f --- /dev/null +++ b/src/hx/libs/zlib/ZLibCompress.cpp @@ -0,0 +1,17 @@ +#include "ZLibCompress.hpp" + +hx::zip::zlib::ZLibCompress::ZLibCompress(z_stream* inHandle, int inFlush) +{ +} + +void hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View src, cpp::marshal::View dst) +{ +} + +void hx::zip::zlib::ZLibCompress::setFlushMode(int mode) +{ +} + +void hx::zip::zlib::ZLibCompress::close() +{ +} diff --git a/src/hx/libs/zlib/ZLibCompress.hpp b/src/hx/libs/zlib/ZLibCompress.hpp new file mode 100644 index 000000000..35961af60 --- /dev/null +++ b/src/hx/libs/zlib/ZLibCompress.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace hx +{ + namespace zip + { + namespace zlib + { + struct ZLibCompress final : Compress_obj + { + z_stream* handle; + int flush; + + ZLibCompress(z_stream* inHandle, int inFlush); + + void execute(cpp::marshal::View src, cpp::marshal::View dst) override; + void setFlushMode(int mode) override; + void close() override; + }; + } + } +} \ No newline at end of file diff --git a/src/hx/libs/zlib/ZLibUncompress.cpp b/src/hx/libs/zlib/ZLibUncompress.cpp new file mode 100644 index 000000000..07199deec --- /dev/null +++ b/src/hx/libs/zlib/ZLibUncompress.cpp @@ -0,0 +1,68 @@ +#include "ZlibUncompress.hpp" + +#include + +int hx::zip::Uncompress_obj::flushNone = Z_NO_FLUSH; +int hx::zip::Uncompress_obj::flushSync = Z_SYNC_FLUSH; +int hx::zip::Uncompress_obj::flushFull = Z_FULL_FLUSH; +int hx::zip::Uncompress_obj::flushFinish = Z_FINISH; +int hx::zip::Uncompress_obj::flushBlock = Z_BLOCK; + +hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) +{ + auto handle = std::make_unique(); + auto error = inflateInit2(handle.get(), windowSize); + + if (error != Z_OK) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + return new hx::zip::zlib::ZLibUncompress(handle.release(), windowSize); +} + +hx::zip::zlib::ZLibUncompress::ZLibUncompress(z_stream* inHandle, int inFlush) : handle(inHandle), flush(inFlush) +{ + _hx_set_finalizer(this, [](Dynamic obj) { reinterpret_cast(obj.mPtr)->close(); }); +} + +hx::zip::UncompressResult hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::View src, cpp::marshal::View dst) +{ + handle->next_in = src.ptr; + handle->next_out = dst.ptr; + handle->avail_in = src.length; + handle->avail_out = dst.length; + + EnterGCFreeZone(); + auto error = inflate(handle, flush); + ExitGCFreeZone(); + + if (error < 0) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + auto result = UncompressResult(); + result.done = error == Z_STREAM_END; + result.write = src.length - handle->avail_in; + result.read = dst.length - handle->avail_out; + + return result; +} + +void hx::zip::zlib::ZLibUncompress::setFlushMode(int mode) +{ + flush = mode; +} + +void hx::zip::zlib::ZLibUncompress::close() +{ + if (nullptr == handle) + { + return; + } + + inflateEnd(handle); + + handle = nullptr; +} diff --git a/src/hx/libs/zlib/ZlibUncompress.hpp b/src/hx/libs/zlib/ZlibUncompress.hpp new file mode 100644 index 000000000..34b0069c7 --- /dev/null +++ b/src/hx/libs/zlib/ZlibUncompress.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace hx +{ + namespace zip + { + namespace zlib + { + struct ZLibUncompress final : Uncompress_obj + { + z_stream* handle; + int flush; + + ZLibUncompress(z_stream* inHandle, int inFlush); + + UncompressResult execute(cpp::marshal::View src, cpp::marshal::View dst) override; + void setFlushMode(int mode) override; + void close() override; + }; + } + } +} From 4395cfc1c2febbe5d90db09591b94fc634d75cc8 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Mon, 24 Nov 2025 22:03:22 +0000 Subject: [PATCH 60/89] more zlib impl --- include/hx/zip/Compress.hpp | 6 +- include/hx/zip/Uncompress.hpp | 19 +---- include/hx/zip/Zip.hpp | 23 ++++++ src/hx/libs/zlib/Build.xml | 1 + src/hx/libs/zlib/ZLib.cpp | 1 + src/hx/libs/zlib/ZLibCompress.cpp | 109 +++++++++++++++++++++++++++- src/hx/libs/zlib/ZLibCompress.hpp | 6 +- src/hx/libs/zlib/ZLibUncompress.cpp | 47 ++++++++---- src/hx/libs/zlib/ZlibUncompress.hpp | 6 +- 9 files changed, 175 insertions(+), 43 deletions(-) create mode 100644 include/hx/zip/Zip.hpp diff --git a/include/hx/zip/Compress.hpp b/include/hx/zip/Compress.hpp index cf8831284..37daade1c 100644 --- a/include/hx/zip/Compress.hpp +++ b/include/hx/zip/Compress.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include "Zip.hpp" HX_DECLARE_CLASS2(hx, zip, Compress) @@ -11,9 +12,10 @@ namespace hx struct Compress_obj : hx::Object { static Compress create(int level); + static Array run(cpp::marshal::View src, int level); - virtual void execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; - virtual void setFlushMode(int mode) = 0; + virtual Result execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; + virtual void setFlushMode(Flush mode) = 0; virtual void close() = 0; }; } diff --git a/include/hx/zip/Uncompress.hpp b/include/hx/zip/Uncompress.hpp index 772cf3825..305de6401 100644 --- a/include/hx/zip/Uncompress.hpp +++ b/include/hx/zip/Uncompress.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include "Zip.hpp" HX_DECLARE_CLASS2(hx, zip, Uncompress) @@ -8,26 +9,12 @@ namespace hx { namespace zip { - struct UncompressResult final { - bool done; - int read; - int write; - - UncompressResult() = default; - }; - struct Uncompress_obj : hx::Object { - static int flushNone; - static int flushSync; - static int flushFull; - static int flushFinish; - static int flushBlock; - static Uncompress create(int windowSize); - virtual UncompressResult execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; - virtual void setFlushMode(int mode) = 0; + virtual Result execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; + virtual void setFlushMode(Flush mode) = 0; virtual void close() = 0; }; } diff --git a/include/hx/zip/Zip.hpp b/include/hx/zip/Zip.hpp new file mode 100644 index 000000000..ab3d4f780 --- /dev/null +++ b/include/hx/zip/Zip.hpp @@ -0,0 +1,23 @@ +#pragma once + +namespace hx +{ + namespace zip + { + enum Flush { + None, + Sync, + Full, + Finish, + Block + }; + + struct Result final { + bool done; + int read; + int write; + + Result() = default; + }; + } +} \ No newline at end of file diff --git a/src/hx/libs/zlib/Build.xml b/src/hx/libs/zlib/Build.xml index dd1678ea7..bc7aa93f6 100644 --- a/src/hx/libs/zlib/Build.xml +++ b/src/hx/libs/zlib/Build.xml @@ -16,6 +16,7 @@ +
diff --git a/src/hx/libs/zlib/ZLib.cpp b/src/hx/libs/zlib/ZLib.cpp index a44a92fa3..c4021e3b8 100644 --- a/src/hx/libs/zlib/ZLib.cpp +++ b/src/hx/libs/zlib/ZLib.cpp @@ -2,6 +2,7 @@ #include #include #include +#include /** diff --git a/src/hx/libs/zlib/ZLibCompress.cpp b/src/hx/libs/zlib/ZLibCompress.cpp index a23638b4f..1d54f4bb7 100644 --- a/src/hx/libs/zlib/ZLibCompress.cpp +++ b/src/hx/libs/zlib/ZLibCompress.cpp @@ -1,17 +1,120 @@ #include "ZLibCompress.hpp" -hx::zip::zlib::ZLibCompress::ZLibCompress(z_stream* inHandle, int inFlush) +#include +#include + +hx::zip::Compress hx::zip::Compress_obj::create(int level) { + auto handle = std::make_unique(); + auto error = deflateInit(handle.get(), level); + + if (error != Z_OK) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + return new hx::zip::zlib::ZLibCompress(handle.release()); } -void hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View src, cpp::marshal::View dst) +Array hx::zip::Compress_obj::run(cpp::marshal::View src, int level) { + auto error = 0; + auto handle = std::make_unique(); + + if (Z_OK != (error = deflateInit(handle.get(), level))) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + auto bounds = deflateBound(handle.get(), src.length); + if (bounds > std::numeric_limits::max()) { + hx::Throw(HX_CSTRING("Size Error")); + } + + auto output = Array(bounds, bounds); + auto dst = cpp::marshal::View(output->getBase(), bounds); + + handle->next_in = src.ptr; + handle->next_out = dst.ptr; + handle->avail_in = src.length; + handle->avail_out = dst.length; + + EnterGCFreeZone(); + error = deflate(handle.get(), Z_FINISH); + ExitGCFreeZone(); + + if (Z_STREAM_END != error) { + hx::Throw(HX_CSTRING("Compression failed")); + } + + deflateEnd(handle.get()); + + return output; } -void hx::zip::zlib::ZLibCompress::setFlushMode(int mode) +hx::zip::zlib::ZLibCompress::ZLibCompress(z_stream* inHandle) : handle(inHandle), flush(0) { + _hx_set_finalizer(this, [](Dynamic obj) { reinterpret_cast(obj.mPtr)->close(); }); +} + +hx::zip::Result hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View src, cpp::marshal::View dst) +{ + handle->next_in = src.ptr; + handle->next_out = dst.ptr; + handle->avail_in = src.length; + handle->avail_out = dst.length; + + EnterGCFreeZone(); + auto error = deflate(handle, flush); + ExitGCFreeZone(); + + if (error < 0) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + auto result = Result(); + result.done = error == Z_STREAM_END; + result.write = src.length - handle->avail_in; + result.read = dst.length - handle->avail_out; + + return result; +} + +void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) +{ + switch (mode) + { + case Flush::None: + flush = Z_NO_FLUSH; + break; + + case Flush::Sync: + flush = Z_SYNC_FLUSH; + break; + + case Flush::Full: + flush = Z_FULL_FLUSH; + break; + + case Flush::Finish: + flush = Z_FINISH; + break; + + case Flush::Block: + flush = Z_BLOCK; + break; + } } void hx::zip::zlib::ZLibCompress::close() { + if (nullptr == handle) + { + return; + } + + deflateEnd(handle); + + handle = nullptr; } diff --git a/src/hx/libs/zlib/ZLibCompress.hpp b/src/hx/libs/zlib/ZLibCompress.hpp index 35961af60..b8dedd7e6 100644 --- a/src/hx/libs/zlib/ZLibCompress.hpp +++ b/src/hx/libs/zlib/ZLibCompress.hpp @@ -14,10 +14,10 @@ namespace hx z_stream* handle; int flush; - ZLibCompress(z_stream* inHandle, int inFlush); + ZLibCompress(z_stream* inHandle); - void execute(cpp::marshal::View src, cpp::marshal::View dst) override; - void setFlushMode(int mode) override; + Result execute(cpp::marshal::View src, cpp::marshal::View dst) override; + void setFlushMode(Flush mode) override; void close() override; }; } diff --git a/src/hx/libs/zlib/ZLibUncompress.cpp b/src/hx/libs/zlib/ZLibUncompress.cpp index 07199deec..8003b5109 100644 --- a/src/hx/libs/zlib/ZLibUncompress.cpp +++ b/src/hx/libs/zlib/ZLibUncompress.cpp @@ -1,12 +1,6 @@ #include "ZlibUncompress.hpp" -#include - -int hx::zip::Uncompress_obj::flushNone = Z_NO_FLUSH; -int hx::zip::Uncompress_obj::flushSync = Z_SYNC_FLUSH; -int hx::zip::Uncompress_obj::flushFull = Z_FULL_FLUSH; -int hx::zip::Uncompress_obj::flushFinish = Z_FINISH; -int hx::zip::Uncompress_obj::flushBlock = Z_BLOCK; +#include hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) { @@ -18,19 +12,19 @@ hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) hx::Throw(HX_CSTRING("ZLib Error")); } - return new hx::zip::zlib::ZLibUncompress(handle.release(), windowSize); + return new hx::zip::zlib::ZLibUncompress(handle.release()); } -hx::zip::zlib::ZLibUncompress::ZLibUncompress(z_stream* inHandle, int inFlush) : handle(inHandle), flush(inFlush) +hx::zip::zlib::ZLibUncompress::ZLibUncompress(z_stream* inHandle) : handle(inHandle), flush(0) { _hx_set_finalizer(this, [](Dynamic obj) { reinterpret_cast(obj.mPtr)->close(); }); } -hx::zip::UncompressResult hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::View src, cpp::marshal::View dst) +hx::zip::Result hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::View src, cpp::marshal::View dst) { - handle->next_in = src.ptr; - handle->next_out = dst.ptr; - handle->avail_in = src.length; + handle->next_in = src.ptr; + handle->next_out = dst.ptr; + handle->avail_in = src.length; handle->avail_out = dst.length; EnterGCFreeZone(); @@ -42,7 +36,7 @@ hx::zip::UncompressResult hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::V hx::Throw(HX_CSTRING("ZLib Error")); } - auto result = UncompressResult(); + auto result = Result(); result.done = error == Z_STREAM_END; result.write = src.length - handle->avail_in; result.read = dst.length - handle->avail_out; @@ -50,9 +44,30 @@ hx::zip::UncompressResult hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::V return result; } -void hx::zip::zlib::ZLibUncompress::setFlushMode(int mode) +void hx::zip::zlib::ZLibUncompress::setFlushMode(Flush mode) { - flush = mode; + switch (mode) + { + case Flush::None: + flush = Z_NO_FLUSH; + break; + + case Flush::Sync: + flush = Z_SYNC_FLUSH; + break; + + case Flush::Full: + flush = Z_FULL_FLUSH; + break; + + case Flush::Finish: + flush = Z_FINISH; + break; + + case Flush::Block: + flush = Z_BLOCK; + break; + } } void hx::zip::zlib::ZLibUncompress::close() diff --git a/src/hx/libs/zlib/ZlibUncompress.hpp b/src/hx/libs/zlib/ZlibUncompress.hpp index 34b0069c7..7897337db 100644 --- a/src/hx/libs/zlib/ZlibUncompress.hpp +++ b/src/hx/libs/zlib/ZlibUncompress.hpp @@ -14,10 +14,10 @@ namespace hx z_stream* handle; int flush; - ZLibUncompress(z_stream* inHandle, int inFlush); + ZLibUncompress(z_stream* inHandle); - UncompressResult execute(cpp::marshal::View src, cpp::marshal::View dst) override; - void setFlushMode(int mode) override; + Result execute(cpp::marshal::View src, cpp::marshal::View dst) override; + void setFlushMode(Flush mode) override; void close() override; }; } From f46d5ddf4fe5d0f9581aa7727ee3345121940da8 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 29 Nov 2025 14:32:09 +0000 Subject: [PATCH 61/89] full zip api --- include/hx/zip/Compress.hpp | 6 +- include/hx/zip/Uncompress.hpp | 7 +- include/hx/zip/Zip.hpp | 9 ++ src/hx/libs/zlib/ZLib.cpp | 241 +++++----------------------- src/hx/libs/zlib/ZLibCompress.cpp | 5 + src/hx/libs/zlib/ZLibCompress.hpp | 1 + src/hx/libs/zlib/ZLibUncompress.cpp | 41 +++++ 7 files changed, 102 insertions(+), 208 deletions(-) diff --git a/include/hx/zip/Compress.hpp b/include/hx/zip/Compress.hpp index 37daade1c..432b4440b 100644 --- a/include/hx/zip/Compress.hpp +++ b/include/hx/zip/Compress.hpp @@ -9,14 +9,12 @@ namespace hx { namespace zip { - struct Compress_obj : hx::Object + struct Compress_obj : Zip_obj { static Compress create(int level); static Array run(cpp::marshal::View src, int level); - virtual Result execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; - virtual void setFlushMode(Flush mode) = 0; - virtual void close() = 0; + virtual int getBounds(int length) = 0; }; } } diff --git a/include/hx/zip/Uncompress.hpp b/include/hx/zip/Uncompress.hpp index 305de6401..a2cda2216 100644 --- a/include/hx/zip/Uncompress.hpp +++ b/include/hx/zip/Uncompress.hpp @@ -9,13 +9,10 @@ namespace hx { namespace zip { - struct Uncompress_obj : hx::Object + struct Uncompress_obj : Zip_obj { static Uncompress create(int windowSize); - - virtual Result execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; - virtual void setFlushMode(Flush mode) = 0; - virtual void close() = 0; + static Array run(cpp::marshal::View src, int bufferSize); }; } } diff --git a/include/hx/zip/Zip.hpp b/include/hx/zip/Zip.hpp index ab3d4f780..72c16bf03 100644 --- a/include/hx/zip/Zip.hpp +++ b/include/hx/zip/Zip.hpp @@ -1,5 +1,7 @@ #pragma once +HX_DECLARE_CLASS2(hx, zip, Zip) + namespace hx { namespace zip @@ -19,5 +21,12 @@ namespace hx Result() = default; }; + + struct Zip_obj : hx::Object + { + virtual Result execute(cpp::marshal::View src, cpp::marshal::View dst) = 0; + virtual void setFlushMode(Flush mode) = 0; + virtual void close() = 0; + }; } } \ No newline at end of file diff --git a/src/hx/libs/zlib/ZLib.cpp b/src/hx/libs/zlib/ZLib.cpp index c4021e3b8..0c4d650a0 100644 --- a/src/hx/libs/zlib/ZLib.cpp +++ b/src/hx/libs/zlib/ZLib.cpp @@ -2,7 +2,8 @@ #include #include #include -#include +#include +#include /** @@ -14,177 +15,8 @@ **/ -namespace { - -struct ZipResult -{ - inline ZipResult(bool inOk, bool inDone, int inRead, int inWrite) - : ok(inOk) - , done(inDone) - , read(inRead) - , write(inWrite) { } - bool ok; - bool done; - int read; - int write; -}; - -struct ZStream : public hx::Object -{ - HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdZLib }; - - z_stream *z; - bool isInflate; - int flush; - - void create(bool inIsInflate, int inParam) - { - isInflate = inIsInflate; - flush = Z_NO_FLUSH; - z = (z_stream*)malloc(sizeof(z_stream)); - memset(z,0,sizeof(z_stream)); - int err = 0; - if (!isInflate) - { - if( (err = deflateInit(z,inParam)) != Z_OK ) - { - free(z); - z = 0; - onError(err); - } - } - else - { - if( (err = inflateInit2(z,inParam)) != Z_OK ) - { - free(z); - z = 0; - onError(err); - } - } - - _hx_set_finalizer(this, finalize); - } - - static void finalize(Dynamic obj) - { - ((ZStream *)(obj.mPtr))->destroy(); - } - - void destroy() - { - if (z) - { - if (isInflate) - inflateEnd(z); - else - deflateEnd(z); - free(z); - z = 0; - } - } - - ZipResult deflate(Array src, int srcpos, Array dest, int dstpos) - { - if( srcpos < 0 || dstpos < 0 ) - return ZipResult( 0,0,0,0 ); - - int slen = src->length - srcpos; - int dlen = dest->length - dstpos; - if( slen < 0 || dlen < 0 ) - return ZipResult( 0,0,0,0 ); - - z->next_in = (Bytef*)(&src[srcpos]); - z->next_out = (Bytef*)(&dest[dstpos]); - z->avail_in = slen; - z->avail_out = dlen; - int err = 0; - if( (err = ::deflate(z,flush)) < 0 ) - onError(err); - - z->next_in = 0; - z->next_out = 0; - return ZipResult( true, err == Z_STREAM_END, (int)(slen - z->avail_in), (int)(dlen - z->avail_out) ); - } - - ZipResult inflate(Array src, int srcpos, Array dest, int dstpos) - { - int slen = src->length; - int dlen = dest->length; - - if( srcpos < 0 || dstpos < 0 ) - return ZipResult( 0,0,0,0 ); - slen -= srcpos; - dlen -= dstpos; - if( slen < 0 || dlen < 0 ) - return ZipResult( 0,0,0,0 ); - - z->next_in = (Bytef*)&src[srcpos]; - z->next_out = (Bytef*)&dest[dstpos]; - z->avail_in = slen; - z->avail_out = dlen; - int err = 0; - if( (err = ::inflate(z,flush)) < 0 ) - onError(err); - z->next_in = 0; - z->next_out = 0; - return ZipResult( true, err == Z_STREAM_END, (int)(slen - z->avail_in), (int)(dlen - z->avail_out) ); - } - - int getDeflateBound(int inLength) - { - return deflateBound(z,inLength); - } - - void setFlushMode(String inMode) - { - if( inMode == HX_CSTRING("NO") ) - flush = Z_NO_FLUSH; - else if( inMode==HX_CSTRING("SYNC")) - flush = Z_SYNC_FLUSH; - else if( inMode==HX_CSTRING("FULL")) - flush = Z_FULL_FLUSH; - else if( inMode==HX_CSTRING("FINISH")) - flush = Z_FINISH; - else if( inMode==HX_CSTRING("BLOCK")) - flush = Z_BLOCK; - } - - - void onError(int inCode) - { - String message = HX_CSTRING("ZLib Error : "); - if( z && z->msg ) - message += String(z->msg) + HX_CSTRING("(") + String(inCode) + HX_CSTRING(")"); - else - message += String(inCode); - hx::Throw(message); - } - - -}; - -ZStream *GetDeflateStream(Dynamic inHandle) -{ - ZStream *z = dynamic_cast(inHandle.mPtr); - if (!z || !z->z || z->isInflate) - hx::Throw( HX_CSTRING("ZLib: Not a valid deflate stream")); - return z; -} - - -ZStream *GetInflateStream(Dynamic inHandle) -{ - ZStream *z = dynamic_cast(inHandle.mPtr); - if (!z || !z->z || !z->isInflate) - hx::Throw( HX_CSTRING("ZLib: Not a valid inflate stream")); - return z; -} - -} // end namespace - - - +using namespace hx::zip; +using namespace cpp::marshal; /** deflate_init : level:int -> 'dstream @@ -192,9 +24,7 @@ ZStream *GetInflateStream(Dynamic inHandle) **/ Dynamic _hx_deflate_init(int level) { - ZStream *zStream = new ZStream; - zStream->create(false, level); - return zStream; + return Compress_obj::create(level); } /** @@ -202,11 +32,12 @@ Dynamic _hx_deflate_init(int level) **/ Dynamic _hx_deflate_buffer(Dynamic handle, Array src, int srcPos, Array dest, int destPos) { - ZipResult result = GetDeflateStream(handle)->deflate(src,srcPos,dest,destPos); - if (!result.ok) - return null(); + auto srcView = View(src->getBase(), src->length).slice(srcPos); + auto dstView = View(dest->getBase(), dest->length).slice(destPos); + auto result = handle.StaticCast()->execute(srcView, dstView); - return hx::Anon_obj::Create(3) + return + hx::Anon_obj::Create(3) ->setFixed(0,HX_("write",df,6c,59,d0),result.write) ->setFixed(1,HX_("done",82,f0,6d,42),result.done) ->setFixed(2,HX_("read",56,4b,a7,4b),result.read); @@ -219,12 +50,12 @@ Dynamic _hx_deflate_buffer(Dynamic handle, Array src, int srcPos, **/ int _hx_deflate_bound(Dynamic handle,int length) { - return GetDeflateStream(handle)->getDeflateBound(length); + return handle.StaticCast()->getBounds(length); } void _hx_deflate_end(Dynamic handle) { - GetDeflateStream(handle)->destroy(); + handle.StaticCast()->close(); } @@ -234,11 +65,29 @@ void _hx_deflate_end(Dynamic handle) **/ void _hx_zip_set_flush_mode(Dynamic handle, String flushMode) { - ZStream *zstream = dynamic_cast(handle.mPtr); - if (!zstream || !zstream->z) - hx::Throw( HX_CSTRING("ZLib flush: not a valid stream") ); - - zstream->setFlushMode(flushMode); + Flush flush; + if (flushMode == HX_CSTRING("NO")) + { + flush = Flush::None; + } + if (flushMode == HX_CSTRING("SYNC")) + { + flush = Flush::Sync; + } + if (flushMode == HX_CSTRING("FULL")) + { + flush = Flush::Full; + } + if (flushMode == HX_CSTRING("FINISH")) + { + flush = Flush::Finish; + } + if (flushMode == HX_CSTRING("BLOCK")) + { + flush = Flush::Block; + } + + handle.StaticCast()->setFlushMode(flush); } @@ -250,11 +99,7 @@ void _hx_zip_set_flush_mode(Dynamic handle, String flushMode) **/ Dynamic _hx_inflate_init(Dynamic windowBits) { - int bits = windowBits==null() ? MAX_WBITS : (int)windowBits; - - ZStream *zStream = new ZStream(); - zStream->create(true, bits); - return zStream; + return Uncompress_obj::create(windowBits == null() ? MAX_WBITS : (int)windowBits); } /** @@ -262,11 +107,12 @@ Dynamic _hx_inflate_init(Dynamic windowBits) **/ Dynamic _hx_inflate_buffer(Dynamic handle, Array src, int srcPos, Array dest, int destPos) { - ZipResult result = GetInflateStream(handle)->inflate(src,srcPos,dest,destPos); - if (!result.ok) - return null(); + auto srcView = View(src->getBase(), src->length).slice(srcPos); + auto dstView = View(dest->getBase(), dest->length).slice(destPos); + auto result = handle.StaticCast()->execute(srcView, dstView); - return hx::Anon_obj::Create(3) + return + hx::Anon_obj::Create(3) ->setFixed(0,HX_("write",df,6c,59,d0),result.write) ->setFixed(1,HX_("done",82,f0,6d,42),result.done) ->setFixed(2,HX_("read",56,4b,a7,4b),result.read); @@ -278,8 +124,5 @@ Dynamic _hx_inflate_buffer(Dynamic handle, Array src, int srcPos, **/ void _hx_inflate_end(Dynamic handle) { - GetInflateStream(handle)->destroy(); + handle.StaticCast()->close(); } - - - diff --git a/src/hx/libs/zlib/ZLibCompress.cpp b/src/hx/libs/zlib/ZLibCompress.cpp index 1d54f4bb7..042b634fa 100644 --- a/src/hx/libs/zlib/ZLibCompress.cpp +++ b/src/hx/libs/zlib/ZLibCompress.cpp @@ -107,6 +107,11 @@ void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) } } +int hx::zip::zlib::ZLibCompress::getBounds(const int length) +{ + return static_cast(deflateBound(handle, length)); +} + void hx::zip::zlib::ZLibCompress::close() { if (nullptr == handle) diff --git a/src/hx/libs/zlib/ZLibCompress.hpp b/src/hx/libs/zlib/ZLibCompress.hpp index b8dedd7e6..61e6540da 100644 --- a/src/hx/libs/zlib/ZLibCompress.hpp +++ b/src/hx/libs/zlib/ZLibCompress.hpp @@ -18,6 +18,7 @@ namespace hx Result execute(cpp::marshal::View src, cpp::marshal::View dst) override; void setFlushMode(Flush mode) override; + int getBounds(int length) override; void close() override; }; } diff --git a/src/hx/libs/zlib/ZLibUncompress.cpp b/src/hx/libs/zlib/ZLibUncompress.cpp index 8003b5109..f62039654 100644 --- a/src/hx/libs/zlib/ZLibUncompress.cpp +++ b/src/hx/libs/zlib/ZLibUncompress.cpp @@ -1,6 +1,7 @@ #include "ZlibUncompress.hpp" #include +#include hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) { @@ -15,6 +16,46 @@ hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) return new hx::zip::zlib::ZLibUncompress(handle.release()); } +Array hx::zip::Uncompress_obj::run(cpp::marshal::View src, int bufferSize) +{ + auto handle = std::make_unique(); + auto error = inflateInit2(handle.get(), 15); + + if (error != Z_OK) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + auto buffer = std::vector(bufferSize); + auto output = Array(0, 0); + auto srcCursor = 0; + + while (Z_STREAM_END != error) + { + auto srcView = src.slice(srcCursor); + + handle->next_in = srcView.ptr; + handle->next_out = buffer.data(); + handle->avail_in = srcView.length; + handle->avail_out = buffer.size(); + + EnterGCFreeZone(); + error = inflate(handle.get(), Z_SYNC_FLUSH); + ExitGCFreeZone(); + + if (error < 0) + { + hx::Throw(HX_CSTRING("ZLib Error")); + } + + output->memcpy(output->length, buffer.data(), buffer.size() - handle->avail_out); + + srcCursor += srcView.length - handle->avail_in; + } + + return output; +} + hx::zip::zlib::ZLibUncompress::ZLibUncompress(z_stream* inHandle) : handle(inHandle), flush(0) { _hx_set_finalizer(this, [](Dynamic obj) { reinterpret_cast(obj.mPtr)->close(); }); From a3bb1142a9954b4307098088db79779a9938939a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 29 Nov 2025 17:31:16 +0000 Subject: [PATCH 62/89] move to new folder and flexible build xml import --- include/hx/zip/Zip.hpp | 8 +- src/hx/zip/Build.xml | 26 ++ src/hx/{libs/zlib/ZLib.cpp => zip/Zip.cpp} | 257 ++++++++++--------- src/hx/{libs => zip}/zlib/Build.xml | 89 ++++--- src/hx/{libs => zip}/zlib/ZLibCompress.cpp | 11 +- src/hx/{libs => zip}/zlib/ZLibCompress.hpp | 0 src/hx/{libs => zip}/zlib/ZLibUncompress.cpp | 11 +- src/hx/{libs => zip}/zlib/ZlibUncompress.hpp | 0 8 files changed, 213 insertions(+), 189 deletions(-) create mode 100644 src/hx/zip/Build.xml rename src/hx/{libs/zlib/ZLib.cpp => zip/Zip.cpp} (93%) rename src/hx/{libs => zip}/zlib/Build.xml (96%) rename src/hx/{libs => zip}/zlib/ZLibCompress.cpp (93%) rename src/hx/{libs => zip}/zlib/ZLibCompress.hpp (100%) rename src/hx/{libs => zip}/zlib/ZLibUncompress.cpp (93%) rename src/hx/{libs => zip}/zlib/ZlibUncompress.hpp (100%) diff --git a/include/hx/zip/Zip.hpp b/include/hx/zip/Zip.hpp index 72c16bf03..af92f3829 100644 --- a/include/hx/zip/Zip.hpp +++ b/include/hx/zip/Zip.hpp @@ -15,11 +15,11 @@ namespace hx }; struct Result final { - bool done; - int read; - int write; + const bool done; + const int read; + const int write; - Result() = default; + Result(int inDone, int inRead, int inWrite); }; struct Zip_obj : hx::Object diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml new file mode 100644 index 000000000..c94eae614 --- /dev/null +++ b/src/hx/zip/Build.xml @@ -0,0 +1,26 @@ + + + +
+ + + + +
+ + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/hx/libs/zlib/ZLib.cpp b/src/hx/zip/Zip.cpp similarity index 93% rename from src/hx/libs/zlib/ZLib.cpp rename to src/hx/zip/Zip.cpp index 0c4d650a0..b3e38b33f 100644 --- a/src/hx/libs/zlib/ZLib.cpp +++ b/src/hx/zip/Zip.cpp @@ -1,128 +1,129 @@ -#include -#include -#include -#include -#include -#include - -/** - -

ZLib

-

- Give access to the popular ZLib compression library, used in several file - formats such as ZIP and PNG. -

-
-**/ - -using namespace hx::zip; -using namespace cpp::marshal; - -/** - deflate_init : level:int -> 'dstream - Open a compression stream with the given level of compression -**/ -Dynamic _hx_deflate_init(int level) -{ - return Compress_obj::create(level); -} - -/** - deflate_buffer : 'dstream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int } -**/ -Dynamic _hx_deflate_buffer(Dynamic handle, Array src, int srcPos, Array dest, int destPos) -{ - auto srcView = View(src->getBase(), src->length).slice(srcPos); - auto dstView = View(dest->getBase(), dest->length).slice(destPos); - auto result = handle.StaticCast()->execute(srcView, dstView); - - return - hx::Anon_obj::Create(3) - ->setFixed(0,HX_("write",df,6c,59,d0),result.write) - ->setFixed(1,HX_("done",82,f0,6d,42),result.done) - ->setFixed(2,HX_("read",56,4b,a7,4b),result.read); -} - - -/** - deflate_bound : 'dstream -> n:int -> int - Return the maximum buffer size needed to write [n] bytes -**/ -int _hx_deflate_bound(Dynamic handle,int length) -{ - return handle.StaticCast()->getBounds(length); -} - -void _hx_deflate_end(Dynamic handle) -{ - handle.StaticCast()->close(); -} - - -/** - set_flush_mode : 'stream -> string -> void - Change the flush mode ("NO","SYNC","FULL","FINISH","BLOCK") -**/ -void _hx_zip_set_flush_mode(Dynamic handle, String flushMode) -{ - Flush flush; - if (flushMode == HX_CSTRING("NO")) - { - flush = Flush::None; - } - if (flushMode == HX_CSTRING("SYNC")) - { - flush = Flush::Sync; - } - if (flushMode == HX_CSTRING("FULL")) - { - flush = Flush::Full; - } - if (flushMode == HX_CSTRING("FINISH")) - { - flush = Flush::Finish; - } - if (flushMode == HX_CSTRING("BLOCK")) - { - flush = Flush::Block; - } - - handle.StaticCast()->setFlushMode(flush); -} - - - - -/** - inflate_init : window_size:int? -> 'istream - Open a decompression stream -**/ -Dynamic _hx_inflate_init(Dynamic windowBits) -{ - return Uncompress_obj::create(windowBits == null() ? MAX_WBITS : (int)windowBits); -} - -/** - inflate_buffer : 'istream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int } -**/ -Dynamic _hx_inflate_buffer(Dynamic handle, Array src, int srcPos, Array dest, int destPos) -{ - auto srcView = View(src->getBase(), src->length).slice(srcPos); - auto dstView = View(dest->getBase(), dest->length).slice(destPos); - auto result = handle.StaticCast()->execute(srcView, dstView); - - return - hx::Anon_obj::Create(3) - ->setFixed(0,HX_("write",df,6c,59,d0),result.write) - ->setFixed(1,HX_("done",82,f0,6d,42),result.done) - ->setFixed(2,HX_("read",56,4b,a7,4b),result.read); -} - -/** - inflate_end : 'istream -> void - Close a decompression stream -**/ -void _hx_inflate_end(Dynamic handle) -{ - handle.StaticCast()->close(); -} +#include +#include +#include +#include +#include + +/** + +

ZLib

+

+ Give access to the popular ZLib compression library, used in several file + formats such as ZIP and PNG. +

+
+**/ + +using namespace hx::zip; +using namespace cpp::marshal; + +hx::zip::Result::Result(int inDone, int inRead, int inWrite) : done(inDone), read(inRead), write(inWrite) {} + +/** + deflate_init : level:int -> 'dstream + Open a compression stream with the given level of compression +**/ +Dynamic _hx_deflate_init(int level) +{ + return Compress_obj::create(level); +} + +/** + deflate_buffer : 'dstream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int } +**/ +Dynamic _hx_deflate_buffer(Dynamic handle, Array src, int srcPos, Array dest, int destPos) +{ + auto srcView = View(src->getBase(), src->length).slice(srcPos); + auto dstView = View(dest->getBase(), dest->length).slice(destPos); + auto result = handle.StaticCast()->execute(srcView, dstView); + + return + hx::Anon_obj::Create(3) + ->setFixed(0,HX_("write",df,6c,59,d0),result.write) + ->setFixed(1,HX_("done",82,f0,6d,42),result.done) + ->setFixed(2,HX_("read",56,4b,a7,4b),result.read); +} + + +/** + deflate_bound : 'dstream -> n:int -> int + Return the maximum buffer size needed to write [n] bytes +**/ +int _hx_deflate_bound(Dynamic handle,int length) +{ + return handle.StaticCast()->getBounds(length); +} + +void _hx_deflate_end(Dynamic handle) +{ + handle.StaticCast()->close(); +} + + +/** + set_flush_mode : 'stream -> string -> void + Change the flush mode ("NO","SYNC","FULL","FINISH","BLOCK") +**/ +void _hx_zip_set_flush_mode(Dynamic handle, String flushMode) +{ + Flush flush; + if (flushMode == HX_CSTRING("NO")) + { + flush = Flush::None; + } + if (flushMode == HX_CSTRING("SYNC")) + { + flush = Flush::Sync; + } + if (flushMode == HX_CSTRING("FULL")) + { + flush = Flush::Full; + } + if (flushMode == HX_CSTRING("FINISH")) + { + flush = Flush::Finish; + } + if (flushMode == HX_CSTRING("BLOCK")) + { + flush = Flush::Block; + } + + handle.StaticCast()->setFlushMode(flush); +} + + + + +/** + inflate_init : window_size:int? -> 'istream + Open a decompression stream +**/ +Dynamic _hx_inflate_init(Dynamic windowBits) +{ + return Uncompress_obj::create(windowBits == null() ? 15 : (int)windowBits); +} + +/** + inflate_buffer : 'istream -> src:string -> srcpos:int -> dst:string -> dstpos:int -> { done => bool, read => int, write => int } +**/ +Dynamic _hx_inflate_buffer(Dynamic handle, Array src, int srcPos, Array dest, int destPos) +{ + auto srcView = View(src->getBase(), src->length).slice(srcPos); + auto dstView = View(dest->getBase(), dest->length).slice(destPos); + auto result = handle.StaticCast()->execute(srcView, dstView); + + return + hx::Anon_obj::Create(3) + ->setFixed(0,HX_("write",df,6c,59,d0),result.write) + ->setFixed(1,HX_("done",82,f0,6d,42),result.done) + ->setFixed(2,HX_("read",56,4b,a7,4b),result.read); +} + +/** + inflate_end : 'istream -> void + Close a decompression stream +**/ +void _hx_inflate_end(Dynamic handle) +{ + handle.StaticCast()->close(); +} diff --git a/src/hx/libs/zlib/Build.xml b/src/hx/zip/zlib/Build.xml similarity index 96% rename from src/hx/libs/zlib/Build.xml rename to src/hx/zip/zlib/Build.xml index bc7aa93f6..323dbae6d 100644 --- a/src/hx/libs/zlib/Build.xml +++ b/src/hx/zip/zlib/Build.xml @@ -1,45 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - -
-
- - - - - -
+ + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+
+ + + + + +
diff --git a/src/hx/libs/zlib/ZLibCompress.cpp b/src/hx/zip/zlib/ZLibCompress.cpp similarity index 93% rename from src/hx/libs/zlib/ZLibCompress.cpp rename to src/hx/zip/zlib/ZLibCompress.cpp index 042b634fa..a669e771c 100644 --- a/src/hx/libs/zlib/ZLibCompress.cpp +++ b/src/hx/zip/zlib/ZLibCompress.cpp @@ -73,12 +73,11 @@ hx::zip::Result hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View hx::Throw(HX_CSTRING("ZLib Error")); } - auto result = Result(); - result.done = error == Z_STREAM_END; - result.write = src.length - handle->avail_in; - result.read = dst.length - handle->avail_out; - - return result; + return + Result( + error == Z_STREAM_END, + dst.length - handle->avail_out, + src.length - handle->avail_in); } void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) diff --git a/src/hx/libs/zlib/ZLibCompress.hpp b/src/hx/zip/zlib/ZLibCompress.hpp similarity index 100% rename from src/hx/libs/zlib/ZLibCompress.hpp rename to src/hx/zip/zlib/ZLibCompress.hpp diff --git a/src/hx/libs/zlib/ZLibUncompress.cpp b/src/hx/zip/zlib/ZLibUncompress.cpp similarity index 93% rename from src/hx/libs/zlib/ZLibUncompress.cpp rename to src/hx/zip/zlib/ZLibUncompress.cpp index f62039654..a015dacf0 100644 --- a/src/hx/libs/zlib/ZLibUncompress.cpp +++ b/src/hx/zip/zlib/ZLibUncompress.cpp @@ -77,12 +77,11 @@ hx::zip::Result hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::Viewavail_in; - result.read = dst.length - handle->avail_out; - - return result; + return + Result( + error == Z_STREAM_END, + dst.length - handle->avail_out, + src.length - handle->avail_in); } void hx::zip::zlib::ZLibUncompress::setFlushMode(Flush mode) diff --git a/src/hx/libs/zlib/ZlibUncompress.hpp b/src/hx/zip/zlib/ZlibUncompress.hpp similarity index 100% rename from src/hx/libs/zlib/ZlibUncompress.hpp rename to src/hx/zip/zlib/ZlibUncompress.hpp From 4e7bdb90e8add98213b07aa527645961bcf6b74a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 29 Nov 2025 20:13:06 +0000 Subject: [PATCH 63/89] cstring to view conversion function, and allow null pointers --- include/cpp/marshal/Definitions.inc | 4 ++++ include/cpp/marshal/Marshal.hpp | 12 ++++++++++++ include/cpp/marshal/ValueReference.hpp | 3 +++ 3 files changed, 19 insertions(+) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index 1635aab40..c33eceee2 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -100,6 +100,7 @@ namespace cpp // This allows 'StaticCast' to be used from arrays using Ptr = Dynamic; + ValueReference(); ValueReference(const null& inRHS); ValueReference(const ValueType& inRHS); ValueReference(const Boxed& inRHS); @@ -219,6 +220,9 @@ namespace cpp static const bool isBigEndian = false; #endif + static View asView(const char* cstring); + static View asView(const char16_t* cstring); + static View toCharView(const ::String& string); static int toCharView(const ::String&, View buffer); diff --git a/include/cpp/marshal/Marshal.hpp b/include/cpp/marshal/Marshal.hpp index 8e0c56d51..001cc6909 100644 --- a/include/cpp/marshal/Marshal.hpp +++ b/include/cpp/marshal/Marshal.hpp @@ -1,7 +1,19 @@ #pragma once #include "Definitions.inc" +#include "Exceptions.hpp" #include +#include + +inline cpp::marshal::View cpp::marshal::Marshal::asView(const char* cstring) +{ + return cpp::marshal::View(const_cast(cstring), static_cast(std::char_traits::length(cstring))); +} + +inline cpp::marshal::View cpp::marshal::Marshal::asView(const char16_t* cstring) +{ + return cpp::marshal::View(const_cast(cstring), static_cast(std::char_traits::length(cstring))); +} inline cpp::marshal::View cpp::marshal::Marshal::toCharView(const ::String& string) { diff --git a/include/cpp/marshal/ValueReference.hpp b/include/cpp/marshal/ValueReference.hpp index e2aaec3df..3123ec1ea 100644 --- a/include/cpp/marshal/ValueReference.hpp +++ b/include/cpp/marshal/ValueReference.hpp @@ -21,6 +21,9 @@ inline O* cpp::marshal::ValueReference::FromBoxed(const Boxed& inRHS) return const_cast(&inRHS->value); } +template +inline cpp::marshal::ValueReference::ValueReference() : Super(nullptr) {} + template inline cpp::marshal::ValueReference::ValueReference(const null& inRHS) : Super(inRHS) {} From 427e81cfb9e1665544e4b6b8b1c68f3e5b44e310 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 29 Nov 2025 21:32:05 +0000 Subject: [PATCH 64/89] Add view to pointer conversions --- include/cpp/marshal/Definitions.inc | 4 ++++ include/cpp/marshal/View.hpp | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index c33eceee2..8460ad333 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -210,6 +210,10 @@ namespace cpp bool operator!=(const View& inRHS) const; T& operator[] (int index); + + operator void* (); + operator T* (); + operator Pointer(); }; struct Marshal final diff --git a/include/cpp/marshal/View.hpp b/include/cpp/marshal/View.hpp index 19d09add5..f4dfb05d9 100644 --- a/include/cpp/marshal/View.hpp +++ b/include/cpp/marshal/View.hpp @@ -98,4 +98,22 @@ template inline T& cpp::marshal::View::operator[](int index) { return ptr[index]; +} + +template +inline cpp::marshal::View::operator void* () +{ + return ptr.ptr; +} + +template +inline cpp::marshal::View::operator T* () +{ + return ptr.ptr; +} + +template +inline cpp::marshal::View::operator cpp::Pointer () +{ + return ptr; } \ No newline at end of file From 4e393954efbf643f9cde47c815e80b5377a2be3f Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 30 Nov 2025 22:17:44 +0000 Subject: [PATCH 65/89] View length is now size_t --- include/cpp/marshal/Definitions.inc | 10 +++++----- include/cpp/marshal/Marshal.hpp | 1 - include/cpp/marshal/View.hpp | 8 ++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index 8460ad333..d6af0dac9 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -193,15 +193,15 @@ namespace cpp struct View final { ::cpp::Pointer ptr; - int length; + size_t length; - View(::cpp::Pointer _ptr, int _length); + View(::cpp::Pointer _ptr, size_t _length); void clear(); void fill(T value); bool isEmpty(); - View slice(int index); - View slice(int index, int length); + View slice(size_t index); + View slice(size_t index, size_t length); bool tryCopyTo(const View& destination); template View reinterpret(); int compare(const View& inRHS); @@ -209,7 +209,7 @@ namespace cpp bool operator==(const View& inRHS) const; bool operator!=(const View& inRHS) const; - T& operator[] (int index); + T& operator[] (size_t index); operator void* (); operator T* (); diff --git a/include/cpp/marshal/Marshal.hpp b/include/cpp/marshal/Marshal.hpp index 001cc6909..30afec83b 100644 --- a/include/cpp/marshal/Marshal.hpp +++ b/include/cpp/marshal/Marshal.hpp @@ -1,7 +1,6 @@ #pragma once #include "Definitions.inc" -#include "Exceptions.hpp" #include #include diff --git a/include/cpp/marshal/View.hpp b/include/cpp/marshal/View.hpp index f4dfb05d9..0c3248879 100644 --- a/include/cpp/marshal/View.hpp +++ b/include/cpp/marshal/View.hpp @@ -5,7 +5,7 @@ #include template -inline cpp::marshal::View::View(::cpp::Pointer _ptr, int _length) : ptr(_ptr), length(_length) {} +inline cpp::marshal::View::View(::cpp::Pointer _ptr, size_t _length) : ptr(_ptr), length(_length) {} template inline bool cpp::marshal::View::tryCopyTo(const View& destination) @@ -42,13 +42,13 @@ inline bool cpp::marshal::View::isEmpty() } template -inline cpp::marshal::View cpp::marshal::View::slice(int index) +inline cpp::marshal::View cpp::marshal::View::slice(size_t index) { return View(ptr + index, length - index); } template -inline cpp::marshal::View cpp::marshal::View::slice(int index, int length) +inline cpp::marshal::View cpp::marshal::View::slice(size_t index, size_t length) { return View(ptr + index, length); } @@ -95,7 +95,7 @@ inline bool cpp::marshal::View::operator!=(const View& inRHS) const } template -inline T& cpp::marshal::View::operator[](int index) +inline T& cpp::marshal::View::operator[](size_t index) { return ptr[index]; } From 3d7d9d48123603ba63c5ccfdae0aa8621ddde0a4 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Fri, 5 Dec 2025 18:22:31 +0000 Subject: [PATCH 66/89] Add endian specific read and write marshal functions --- include/cpp/marshal/Definitions.inc | 40 ++++ include/cpp/marshal/Marshal.hpp | 342 ++++++++++++++++++++++++++++ 2 files changed, 382 insertions(+) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index d6af0dac9..87654db3d 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -249,6 +249,26 @@ namespace cpp static float readFloat32(View view); static double readFloat64(View view); + template static ::cpp::Pointer readLittleEndianPointer(View view); + static int16_t readLittleEndianInt16(View view); + static int32_t readLittleEndianInt32(View view); + static int64_t readLittleEndianInt64(View view); + static uint16_t readLittleEndianUInt16(View view); + static uint32_t readLittleEndianUInt32(View view); + static uint64_t readLittleEndianUInt64(View view); + static float readLittleEndianFloat32(View view); + static double readLittleEndianFloat64(View view); + + template static ::cpp::Pointer readBigEndianPointer(View view); + static int16_t readBigEndianInt16(View view); + static int32_t readBigEndianInt32(View view); + static int64_t readBigEndianInt64(View view); + static uint16_t readBigEndianUInt16(View view); + static uint32_t readBigEndianUInt32(View view); + static uint64_t readBigEndianUInt64(View view); + static float readBigEndianFloat32(View view); + static double readBigEndianFloat64(View view); + template static void write(View view, const T& value); template static void writePointer(View view, const Pointer& value); static void writeInt8(View view, const int8_t& value); @@ -261,6 +281,26 @@ namespace cpp static void writeUInt64(View view, const uint64_t& value); static void writeFloat32(View view, const float& value); static void writeFloat64(View view, const double& value); + + template static void writeLittleEndianPointer(View view, const Pointer& value); + static void writeLittleEndianInt16(View view, const int16_t& value); + static void writeLittleEndianInt32(View view, const int32_t& value); + static void writeLittleEndianInt64(View view, const int64_t& value); + static void writeLittleEndianUInt16(View view, const uint16_t& value); + static void writeLittleEndianUInt32(View view, const uint32_t& value); + static void writeLittleEndianUInt64(View view, const uint64_t& value); + static void writeLittleEndianFloat32(View view, const float& value); + static void writeLittleEndianFloat64(View view, const double& value); + + template static void writeBigEndianPointer(View view, const Pointer& value); + static void writeBigEndianInt16(View view, const int16_t& value); + static void writeBigEndianInt32(View view, const int32_t& value); + static void writeBigEndianInt64(View view, const int64_t& value); + static void writeBigEndianUInt16(View view, const uint16_t& value); + static void writeBigEndianUInt32(View view, const uint32_t& value); + static void writeBigEndianUInt64(View view, const uint64_t& value); + static void writeBigEndianFloat32(View view, const float& value); + static void writeBigEndianFloat64(View view, const double& value); }; } } diff --git a/include/cpp/marshal/Marshal.hpp b/include/cpp/marshal/Marshal.hpp index 30afec83b..e4850aedf 100644 --- a/include/cpp/marshal/Marshal.hpp +++ b/include/cpp/marshal/Marshal.hpp @@ -3,6 +3,20 @@ #include "Definitions.inc" #include #include +#include + +namespace +{ + template + T reverse(T val) + { + auto view = cpp::marshal::View(reinterpret_cast(&val), sizeof(T)); + + std::reverse(view.ptr.ptr, view.ptr.ptr + view.length); + + return val; + } +} inline cpp::marshal::View cpp::marshal::Marshal::asView(const char* cstring) { @@ -194,4 +208,332 @@ inline void cpp::marshal::Marshal::writeFloat32(View view, const float& inline void cpp::marshal::Marshal::writeFloat64(View view, const double& value) { write(view, value); +} + +template +inline ::cpp::Pointer cpp::marshal::Marshal::readBigEndianPointer(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readPointer(view); +#else + return reverse(readPointer(view)); +#endif +} + +inline int16_t cpp::marshal::Marshal::readBigEndianInt16(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readInt16(view); +#else + return reverse(readInt16(view)); +#endif +} + +inline int32_t cpp::marshal::Marshal::readBigEndianInt32(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readInt32(view); +#else + return reverse(readInt32(view)); +#endif +} + +inline int64_t cpp::marshal::Marshal::readBigEndianInt64(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readInt64(view); +#else + return reverse(readInt64(view)); +#endif +} + +inline uint16_t cpp::marshal::Marshal::readBigEndianUInt16(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readUInt16(view); +#else + return reverse(readUInt16(view)); +#endif +} + +inline uint32_t cpp::marshal::Marshal::readBigEndianUInt32(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readUInt32(view); +#else + return reverse(readUInt32(view)); +#endif +} + +inline uint64_t cpp::marshal::Marshal::readBigEndianUInt64(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readInt64(view); +#else + return reverse(readUInt64(view)); +#endif +} + +inline float cpp::marshal::Marshal::readBigEndianFloat32(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readFloat32(view); +#else + return reverse(readFloat32(view)); +#endif +} + +inline double cpp::marshal::Marshal::readBigEndianFloat64(View view) +{ +#ifdef HXCPP_BIG_ENDIAN + return readFloat64(view); +#else + return reverse(readFloat64(view)); +#endif +} + +template +inline ::cpp::Pointer cpp::marshal::Marshal::readLittleEndianPointer(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readPointer(view); +#else + return reverse(readPointer(view)); +#endif +} + +inline int16_t cpp::marshal::Marshal::readLittleEndianInt16(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readInt16(view); +#else + return reverse(readInt16(view)); +#endif +} + +inline int32_t cpp::marshal::Marshal::readLittleEndianInt32(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readInt32(view); +#else + return reverse(readInt32(view)); +#endif +} + +inline int64_t cpp::marshal::Marshal::readLittleEndianInt64(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readInt64(view); +#else + return reverse(readInt64(view)); +#endif +} + +inline uint16_t cpp::marshal::Marshal::readLittleEndianUInt16(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readUInt16(view); +#else + return reverse(readUInt16(view)); +#endif +} + +inline uint32_t cpp::marshal::Marshal::readLittleEndianUInt32(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readUInt32(view); +#else + return reverse(readUInt32(view)); +#endif +} + +inline uint64_t cpp::marshal::Marshal::readLittleEndianUInt64(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readInt64(view); +#else + return reverse(readUInt64(view)); +#endif +} + +inline float cpp::marshal::Marshal::readLittleEndianFloat32(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readFloat32(view); +#else + return reverse(readFloat32(view)); +#endif +} + +inline double cpp::marshal::Marshal::readLittleEndianFloat64(View view) +{ +#ifndef HXCPP_BIG_ENDIAN + return readFloat64(view); +#else + return reverse(readFloat64(view)); +#endif +} + +template +inline void cpp::marshal::Marshal::writeLittleEndianPointer(View view, const ::cpp::Pointer& value) +{ +#ifdef HXCPP_BIG_ENDIAN + write(view, reverse(value.ptr)); +#else + write(view, value.ptr); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianInt16(View view, const int16_t& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeInt16(view, reverse(value)); +#else + writeInt16(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianInt32(View view, const int32_t& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeInt32(view, reverse(value)); +#else + writeInt32(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianInt64(View view, const int64_t& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeInt64(view, reverse(value)); +#else + writeInt64(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianUInt16(View view, const uint16_t& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeUInt16(view, reverse(value)); +#else + writeUInt16(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianUInt32(View view, const uint32_t& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeUInt32(view, reverse(value)); +#else + writeUInt32(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianUInt64(View view, const uint64_t& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeUInt16(view, reverse(value)); +#else + writeUInt16(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianFloat32(View view, const float& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeFloat32(view, reverse(value)); +#else + writeFloat32(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeLittleEndianFloat64(View view, const double& value) +{ +#ifdef HXCPP_BIG_ENDIAN + writeFloat64(view, reverse(value)); +#else + writeFloat64(view, value); +#endif +} + +template +inline void cpp::marshal::Marshal::writeBigEndianPointer(View view, const ::cpp::Pointer& value) +{ +#ifndef HXCPP_BIG_ENDIAN + write(view, reverse(value.ptr)); +#else + write(view, value.ptr); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianInt16(View view, const int16_t& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeInt16(view, reverse(value)); +#else + writeInt16(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianInt32(View view, const int32_t& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeInt32(view, reverse(value)); +#else + writeInt32(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianInt64(View view, const int64_t& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeInt64(view, reverse(value)); +#else + writeInt64(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianUInt16(View view, const uint16_t& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeUInt16(view, reverse(value)); +#else + writeUInt16(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianUInt32(View view, const uint32_t& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeUInt32(view, reverse(value)); +#else + writeUInt32(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianUInt64(View view, const uint64_t& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeUInt16(view, reverse(value)); +#else + writeUInt16(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianFloat32(View view, const float& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeFloat32(view, reverse(value)); +#else + writeFloat32(view, value); +#endif +} + +inline void cpp::marshal::Marshal::writeBigEndianFloat64(View view, const double& value) +{ +#ifndef HXCPP_BIG_ENDIAN + writeFloat64(view, reverse(value)); +#else + writeFloat64(view, value); +#endif } \ No newline at end of file From 513330d2506438117f8390b8ab9088a3eb37882c Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 14:38:20 +0000 Subject: [PATCH 67/89] Add OOB checks --- include/cpp/marshal/View.hpp | 39 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/include/cpp/marshal/View.hpp b/include/cpp/marshal/View.hpp index 0c3248879..273da0b97 100644 --- a/include/cpp/marshal/View.hpp +++ b/include/cpp/marshal/View.hpp @@ -42,24 +42,34 @@ inline bool cpp::marshal::View::isEmpty() } template -inline cpp::marshal::View cpp::marshal::View::slice(size_t index) +inline cpp::marshal::View cpp::marshal::View::slice(int64_t index) { + if (index < 0 || index > length) + { + hx::Throw(HX_CSTRING("View OOB")); + } + return View(ptr + index, length - index); } template -inline cpp::marshal::View cpp::marshal::View::slice(size_t index, size_t length) +inline cpp::marshal::View cpp::marshal::View::slice(int64_t inIndex, int64_t inLength) { - return View(ptr + index, length); + if (inIndex < 0 || inLength < 0 || inIndex > length || inIndex + inLength > length) + { + hx::Throw(HX_CSTRING("View OOB")); + } + + return View(ptr + inIndex, inLength); } template template inline cpp::marshal::View cpp::marshal::View::reinterpret() { - auto newPtr = ::cpp::Pointer{ ptr.reinterpret() }; + auto newPtr = ::cpp::Pointer{ ptr.reinterpret() }; auto fromSize = sizeof(T); - auto toSize = sizeof(K); + auto toSize = sizeof(K); if (toSize == fromSize) { @@ -70,7 +80,7 @@ inline cpp::marshal::View cpp::marshal::View::reinterpret() return cpp::marshal::View(newPtr, length * (fromSize / toSize)); } - auto shrink = static_cast(fromSize) / toSize; + auto shrink = static_cast(fromSize) / toSize; auto newLength = static_cast(std::floor(length * shrink)); return cpp::marshal::View(newPtr, newLength); @@ -79,7 +89,15 @@ inline cpp::marshal::View cpp::marshal::View::reinterpret() template inline int cpp::marshal::View::compare(const View& inRHS) { - return std::memcmp(ptr.ptr, inRHS.ptr.ptr, sizeof(T) * length); + auto common = length < inRHS.length ? length : inRHS.length; + auto result = std::memcmp(ptr.ptr, inRHS.ptr.ptr, sizeof(T) * common); + + if (result) + { + return result; + } + + return length - inRHS.length; } template @@ -95,8 +113,13 @@ inline bool cpp::marshal::View::operator!=(const View& inRHS) const } template -inline T& cpp::marshal::View::operator[](size_t index) +inline T& cpp::marshal::View::operator[](int64_t index) { + if (index < 0 || index >= length) + { + hx::Throw(HX_CSTRING("View OOB")); + } + return ptr[index]; } From 2603e8d4a66ae0cd0ac2c557d91059524233965a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 14:38:36 +0000 Subject: [PATCH 68/89] change the public api to use int64_t over size_t --- include/cpp/marshal/Definitions.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/cpp/marshal/Definitions.inc b/include/cpp/marshal/Definitions.inc index 87654db3d..7e70e0eb1 100644 --- a/include/cpp/marshal/Definitions.inc +++ b/include/cpp/marshal/Definitions.inc @@ -200,8 +200,8 @@ namespace cpp void clear(); void fill(T value); bool isEmpty(); - View slice(size_t index); - View slice(size_t index, size_t length); + View slice(int64_t index); + View slice(int64_t index, int64_t length); bool tryCopyTo(const View& destination); template View reinterpret(); int compare(const View& inRHS); @@ -209,7 +209,7 @@ namespace cpp bool operator==(const View& inRHS) const; bool operator!=(const View& inRHS) const; - T& operator[] (size_t index); + T& operator[] (int64_t index); operator void* (); operator T* (); From 14dc9b6d459818a481d7b95fe1a8fe715bdd090d Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 14:39:07 +0000 Subject: [PATCH 69/89] Fix string from view conversions to properly use the view length --- src/String.cpp | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/String.cpp b/src/String.cpp index e612d675f..a3cc73ae3 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -791,18 +791,38 @@ String String::create(const char *inString,int inLength) #if (HXCPP_API_LEVEL>=500) String String::create(const::cpp::marshal::View& buffer) { - return String::create(buffer.ptr.ptr, std::char_traits::length(buffer.ptr.ptr)); + auto start = buffer.ptr.ptr; + auto end = start + buffer.length; + + while (start < end) { + if (*start == false) + { + break; + } + + start++; + } + + return String::create(buffer.ptr.ptr, buffer.length - (end - start)); } String String::create(const cpp::marshal::View& buffer) { - auto cursor = reinterpret_cast(buffer.ptr.ptr); + auto start = reinterpret_cast(buffer.ptr.ptr); + auto end = start + buffer.length; + auto extra = 0; - while (Char16Advance(cursor)) {} + while (start < end) { + if (Char16Advance(start) == false) + { + // set extra to 1 so we don't include the null terminating character in the calculated length. + extra = 1; - auto calculated = cursor - buffer.ptr.ptr - 1; + break; + } + } - return String::create(buffer.ptr.ptr, calculated); + return String::create(buffer.ptr.ptr, buffer.length - (end - start) - extra); } #endif @@ -1559,7 +1579,7 @@ void __hxcpp_string_of_bytes(Array &inBytes,String &outString,int else { const unsigned char *p0 = (const unsigned char *)inBytes->GetBase(); - #ifdef HX_SMART_STRINGS +#ifdef HX_SMART_STRINGS bool hasWChar = false; const unsigned char *p = p0 + pos; for(int i=0;i &inBytes,String &outString,int outString = _hx_utf8_to_utf16(p0+pos,len,true); } else - #endif +#endif outString = String( GCStringDup((const char *)p0+pos, len, 0), len); } } From a401f0700b786f0669a88cc7e0142154ca55303f Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sat, 13 Dec 2025 14:39:47 +0000 Subject: [PATCH 70/89] Add OOB exception tests --- .../native/tests/marshalling/view/TestView.hx | 53 +++++++++++++++++++ .../marshalling/view/TestViewExtensions.hx | 5 -- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/test/native/tests/marshalling/view/TestView.hx b/test/native/tests/marshalling/view/TestView.hx index 2cc078692..8eb6c5555 100644 --- a/test/native/tests/marshalling/view/TestView.hx +++ b/test/native/tests/marshalling/view/TestView.hx @@ -117,6 +117,22 @@ class TestView extends Test { Assert.equals(200, obj.number); } + function test_reading_error() { + final buffer = [ for (i in 0...10) i + 1 ]; + + Assert.raises(() -> final _ = buffer.asView()[-1], String); + Assert.raises(() -> final _ = buffer.asView()[10], String); + Assert.raises(() -> final _ = buffer.asView()[20], String); + } + + function test_writing_error() { + final buffer = [ for (i in 0...10) i + 1 ]; + + Assert.raises(() -> buffer.asView()[-1] = 100, String); + Assert.raises(() -> buffer.asView()[10] = 100, String); + Assert.raises(() -> buffer.asView()[20] = 100, String); + } + function test_slice() { final buffer = [ for (i in 0...10) i + 1 ]; final view = buffer.asView(); @@ -130,6 +146,14 @@ class TestView extends Test { } } + function test_slice_errors() { + final buffer = [ for (i in 0...10) i + 1 ]; + + Assert.raises(() -> buffer.asView().slice(-1), String); + Assert.raises(() -> buffer.asView().slice(100), String); + Assert.isTrue(buffer.asView().slice(10).isEmpty()); + } + function test_slice_with_length() { final buffer = [ for (i in 0...10) i + 1 ]; final view = buffer.asView(); @@ -144,6 +168,17 @@ class TestView extends Test { } } + function test_slice_with_length_errors() { + final buffer = [ for (i in 0...10) i + 1 ]; + + Assert.raises(() -> buffer.asView().slice(-1, 5), String); + Assert.raises(() -> buffer.asView().slice(5, -1), String); + Assert.raises(() -> buffer.asView().slice(1, 100), String); + Assert.raises(() -> buffer.asView().slice(100, 5), String); + Assert.raises(() -> buffer.asView().slice(10, 5), String); + Assert.isTrue(buffer.asView().slice(10, 0).isEmpty()); + } + function test_clear() { final buffer = [ for (_ in 0...10) 8 ]; final view = buffer.asView(); @@ -239,4 +274,22 @@ class TestView extends Test { Assert.equals(7f64, buffer[0]); Assert.equals(26f64, buffer[1]); } + + function test_tryCopyTo() { + final buffer = [ for (i in 0...10) i ]; + final biggerDst = buffer.copy(); + final matchingDst = buffer.copy(); + final smallerDst = buffer.copy(); + + biggerDst.resize(20); + smallerDst.resize(5); + + Assert.isTrue(buffer.asView().tryCopyTo(biggerDst.asView())); + Assert.isTrue(buffer.asView().tryCopyTo(matchingDst.asView())); + Assert.isFalse(buffer.asView().tryCopyTo(smallerDst.asView())); + + Assert.same(buffer, biggerDst.slice(0, 10)); + Assert.same(buffer, matchingDst); + Assert.same(buffer.slice(0, smallerDst.length), smallerDst); + } } diff --git a/test/native/tests/marshalling/view/TestViewExtensions.hx b/test/native/tests/marshalling/view/TestViewExtensions.hx index 667922ff0..271b1e103 100644 --- a/test/native/tests/marshalling/view/TestViewExtensions.hx +++ b/test/native/tests/marshalling/view/TestViewExtensions.hx @@ -5,19 +5,14 @@ import haxe.io.UInt16Array; import haxe.io.UInt32Array; import haxe.io.Int32Array; import haxe.io.Float64Array; -import cpp.Float32; import haxe.io.Float32Array; import haxe.io.ArrayBufferView; import haxe.io.Bytes; import haxe.ds.Vector; -import cpp.Int64; -import cpp.UInt32; -import cpp.Int16; import cpp.Pointer; import cpp.marshal.View; import utest.Test; import utest.Assert; -import tests.marshalling.Point; using cpp.marshal.ViewExtensions; From 43fec7ff0428821f4e7f858aa2ad8a68f54cb851 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 16:16:24 +0000 Subject: [PATCH 71/89] bound check read and write --- include/cpp/marshal/Marshal.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/cpp/marshal/Marshal.hpp b/include/cpp/marshal/Marshal.hpp index e4850aedf..997cf5091 100644 --- a/include/cpp/marshal/Marshal.hpp +++ b/include/cpp/marshal/Marshal.hpp @@ -89,6 +89,11 @@ inline ::String cpp::marshal::Marshal::toString(View buffer) template inline T cpp::marshal::Marshal::read(View view) { + if (view.length < sizeof(T)) + { + hx::Throw(HX_CSTRING("View too small")); + } + return *(reinterpret_cast(view.ptr.ptr)); } @@ -151,6 +156,11 @@ inline double cpp::marshal::Marshal::readFloat64(View view) template inline void cpp::marshal::Marshal::write(View view, const T& value) { + if (view.length < sizeof(T)) + { + hx::Throw(HX_CSTRING("View too small")); + } + std::memcpy(view.ptr, reinterpret_cast(&value), sizeof(T)); } From c836e3a026320214ca03a5cb5fb5189439976300 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 16:16:40 +0000 Subject: [PATCH 72/89] make sure view write index is int64_t --- src/String.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/String.cpp b/src/String.cpp index a3cc73ae3..2215265fa 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -1813,7 +1813,7 @@ bool String::wc_str(::cpp::marshal::View buffer, int* outCharLength) c std::memcpy(buffer.ptr, __w, sizeof(char16_t) * length); - buffer[length] = 0; + buffer[int64_t{ length }] = 0; return true; } @@ -1913,7 +1913,7 @@ bool String::utf8_str(::cpp::marshal::View buffer, int* outByteLength) con std::memcpy(buffer.ptr, __s, sizeof(char) * length); - buffer[length] = 0; + buffer[int64_t{ length }] = 0; return true; } From a18fca8014cd38b10b9c59eb9a8b924ceadb6302 Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sat, 13 Dec 2025 16:50:28 +0000 Subject: [PATCH 73/89] add tests for exceptions when reading or writing to small views --- test/native/tests/marshalling/view/TestMarshal.hx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/native/tests/marshalling/view/TestMarshal.hx b/test/native/tests/marshalling/view/TestMarshal.hx index 2f2e8e7d6..60199b5be 100644 --- a/test/native/tests/marshalling/view/TestMarshal.hx +++ b/test/native/tests/marshalling/view/TestMarshal.hx @@ -24,6 +24,12 @@ class TestMarshal extends Test { Assert.equals(value, storage); } + function test_write_not_enough_space() { + final storage = Bytes.alloc(1); + + Assert.raises(() -> storage.asView().writeInt32(0)); + } + function test_read_int() { final storage = 200; final source = new View(Pointer.addressOf(storage), 1); @@ -31,6 +37,12 @@ class TestMarshal extends Test { Assert.isTrue(storage == source.asBytesView().read()); } + function test_read_not_enough_space() { + final storage = Bytes.alloc(1); + + Assert.raises(() -> storage.asView().readInt32()); + } + function test_write_float() { final storage = 0f64; final source = new View(Pointer.addressOf(storage), 1); From d315b3a018121257ffc94fc2fc10249d07ded540 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 17:25:08 +0000 Subject: [PATCH 74/89] guard including new marshal headers --- include/hxcpp.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/include/hxcpp.h b/include/hxcpp.h index 68824a682..6f7501485 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -351,13 +351,15 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include -#include -#include -#include -#include -#include -#include -#include +#ifdef HXCPP_API_LEVEL>=500 + #include + #include + #include + #include + #include + #include + #include +#endif #include #include #include From fe7ea65b53824f2c1a979e7a4884aa090e70b7db Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 17:53:02 +0000 Subject: [PATCH 75/89] fix dodgy conditional --- include/hxcpp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hxcpp.h b/include/hxcpp.h index 6f7501485..053a153b2 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -351,7 +351,7 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include -#ifdef HXCPP_API_LEVEL>=500 +#if (HXCPP_API_LEVEL>=500) #include #include #include From 3fafc9328922bbb0bf8118e8f8ab9ab5b95b8873 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sat, 13 Dec 2025 23:03:54 +0000 Subject: [PATCH 76/89] Updated zlib implementation --- src/hx/zip/Build.xml | 7 +------ src/hx/zip/zlib/ZLibCompress.cpp | 29 ++++++++++++++++++++++++----- src/hx/zip/zlib/ZLibUncompress.cpp | 22 ++++++++++++++++++---- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml index c94eae614..325ddd01f 100644 --- a/src/hx/zip/Build.xml +++ b/src/hx/zip/Build.xml @@ -2,13 +2,8 @@
- - - - +
- - diff --git a/src/hx/zip/zlib/ZLibCompress.cpp b/src/hx/zip/zlib/ZLibCompress.cpp index a669e771c..05fb932e1 100644 --- a/src/hx/zip/zlib/ZLibCompress.cpp +++ b/src/hx/zip/zlib/ZLibCompress.cpp @@ -3,9 +3,11 @@ #include #include +#define ZLIB_OBJ_CLOSED ::hx::Throw(HX_CSTRING("Compress closed")) + hx::zip::Compress hx::zip::Compress_obj::create(int level) { - auto handle = std::make_unique(); + auto handle = std::unique_ptr(new z_stream()); auto error = deflateInit(handle.get(), level); if (error != Z_OK) @@ -19,7 +21,7 @@ hx::zip::Compress hx::zip::Compress_obj::create(int level) Array hx::zip::Compress_obj::run(cpp::marshal::View src, int level) { auto error = 0; - auto handle = std::make_unique(); + auto handle = std::unique_ptr(new z_stream()); if (Z_OK != (error = deflateInit(handle.get(), level))) { @@ -49,7 +51,7 @@ Array hx::zip::Compress_obj::run(cpp::marshal::View src, int l deflateEnd(handle.get()); - return output; + return output->slice(0, handle->total_out); } hx::zip::zlib::ZLibCompress::ZLibCompress(z_stream* inHandle) : handle(inHandle), flush(0) @@ -59,6 +61,11 @@ hx::zip::zlib::ZLibCompress::ZLibCompress(z_stream* inHandle) : handle(inHandle) hx::zip::Result hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View src, cpp::marshal::View dst) { + if (handle == nullptr) + { + ZLIB_OBJ_CLOSED; + } + handle->next_in = src.ptr; handle->next_out = dst.ptr; handle->avail_in = src.length; @@ -76,12 +83,17 @@ hx::zip::Result hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View return Result( error == Z_STREAM_END, - dst.length - handle->avail_out, - src.length - handle->avail_in); + dst.length - handle->total_in, + src.length - handle->total_out); } void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) { + if (handle == nullptr) + { + ZLIB_OBJ_CLOSED; + } + switch (mode) { case Flush::None: @@ -108,6 +120,11 @@ void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) int hx::zip::zlib::ZLibCompress::getBounds(const int length) { + if (handle == nullptr) + { + ZLIB_OBJ_CLOSED; + } + return static_cast(deflateBound(handle, length)); } @@ -121,4 +138,6 @@ void hx::zip::zlib::ZLibCompress::close() deflateEnd(handle); handle = nullptr; + + _hx_set_finalizer(this, nullptr); } diff --git a/src/hx/zip/zlib/ZLibUncompress.cpp b/src/hx/zip/zlib/ZLibUncompress.cpp index a015dacf0..e2674366c 100644 --- a/src/hx/zip/zlib/ZLibUncompress.cpp +++ b/src/hx/zip/zlib/ZLibUncompress.cpp @@ -3,9 +3,11 @@ #include #include +#define ZLIB_OBJ_CLOSED ::hx::Throw(HX_CSTRING("Compress closed")) + hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) { - auto handle = std::make_unique(); + auto handle = std::unique_ptr(new z_stream()); auto error = inflateInit2(handle.get(), windowSize); if (error != Z_OK) @@ -18,7 +20,7 @@ hx::zip::Uncompress hx::zip::Uncompress_obj::create(int windowSize) Array hx::zip::Uncompress_obj::run(cpp::marshal::View src, int bufferSize) { - auto handle = std::make_unique(); + auto handle = std::unique_ptr(new z_stream()); auto error = inflateInit2(handle.get(), 15); if (error != Z_OK) @@ -63,6 +65,11 @@ hx::zip::zlib::ZLibUncompress::ZLibUncompress(z_stream* inHandle) : handle(inHan hx::zip::Result hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::View src, cpp::marshal::View dst) { + if (handle == nullptr) + { + ZLIB_OBJ_CLOSED; + } + handle->next_in = src.ptr; handle->next_out = dst.ptr; handle->avail_in = src.length; @@ -80,12 +87,17 @@ hx::zip::Result hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::Viewavail_out, - src.length - handle->avail_in); + handle->total_in, + handle->total_out); } void hx::zip::zlib::ZLibUncompress::setFlushMode(Flush mode) { + if (handle == nullptr) + { + ZLIB_OBJ_CLOSED; + } + switch (mode) { case Flush::None: @@ -120,4 +132,6 @@ void hx::zip::zlib::ZLibUncompress::close() inflateEnd(handle); handle = nullptr; + + _hx_set_finalizer(this, nullptr); } From f171e828a93060238fd14812e5fb427f514f5d9a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 10:33:23 +0000 Subject: [PATCH 77/89] header faff to make gcc pch happy --- include/hx/zip/Compress.hpp | 1 - include/hx/zip/Uncompress.hpp | 1 - include/hx/zip/Zip.hpp | 4 ++++ src/hx/zip/zlib/ZLibCompress.cpp | 1 + src/hx/zip/zlib/ZLibCompress.hpp | 1 + src/hx/zip/zlib/ZLibUncompress.cpp | 1 + src/hx/zip/zlib/ZlibUncompress.hpp | 1 + 7 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/hx/zip/Compress.hpp b/include/hx/zip/Compress.hpp index 432b4440b..85a9ef8f3 100644 --- a/include/hx/zip/Compress.hpp +++ b/include/hx/zip/Compress.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include "Zip.hpp" HX_DECLARE_CLASS2(hx, zip, Compress) diff --git a/include/hx/zip/Uncompress.hpp b/include/hx/zip/Uncompress.hpp index a2cda2216..2a67827d2 100644 --- a/include/hx/zip/Uncompress.hpp +++ b/include/hx/zip/Uncompress.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include "Zip.hpp" HX_DECLARE_CLASS2(hx, zip, Uncompress) diff --git a/include/hx/zip/Zip.hpp b/include/hx/zip/Zip.hpp index af92f3829..4b3342f3a 100644 --- a/include/hx/zip/Zip.hpp +++ b/include/hx/zip/Zip.hpp @@ -1,5 +1,9 @@ #pragma once +#ifndef HXCPP_H +#include +#endif + HX_DECLARE_CLASS2(hx, zip, Zip) namespace hx diff --git a/src/hx/zip/zlib/ZLibCompress.cpp b/src/hx/zip/zlib/ZLibCompress.cpp index 05fb932e1..f9d0d5ad7 100644 --- a/src/hx/zip/zlib/ZLibCompress.cpp +++ b/src/hx/zip/zlib/ZLibCompress.cpp @@ -1,3 +1,4 @@ +#include #include "ZLibCompress.hpp" #include diff --git a/src/hx/zip/zlib/ZLibCompress.hpp b/src/hx/zip/zlib/ZLibCompress.hpp index 61e6540da..a77361826 100644 --- a/src/hx/zip/zlib/ZLibCompress.hpp +++ b/src/hx/zip/zlib/ZLibCompress.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include diff --git a/src/hx/zip/zlib/ZLibUncompress.cpp b/src/hx/zip/zlib/ZLibUncompress.cpp index e2674366c..c212332dd 100644 --- a/src/hx/zip/zlib/ZLibUncompress.cpp +++ b/src/hx/zip/zlib/ZLibUncompress.cpp @@ -1,3 +1,4 @@ +#include #include "ZlibUncompress.hpp" #include diff --git a/src/hx/zip/zlib/ZlibUncompress.hpp b/src/hx/zip/zlib/ZlibUncompress.hpp index 7897337db..65f51d557 100644 --- a/src/hx/zip/zlib/ZlibUncompress.hpp +++ b/src/hx/zip/zlib/ZlibUncompress.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include From ad7606bb0f353f999919d5cf9856aaa94e2e75e6 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 11:17:34 +0000 Subject: [PATCH 78/89] Support haxe 4 with new implementation --- include/hxString.h | 4 ---- include/hxcpp.h | 16 +++++++--------- src/String.cpp | 6 ------ src/hx/libs/zlib/Build.xml | 7 +++++++ src/hx/zip/zlib/ZLibCompress.cpp | 4 ++-- 5 files changed, 16 insertions(+), 21 deletions(-) create mode 100644 src/hx/libs/zlib/Build.xml diff --git a/include/hxString.h b/include/hxString.h index 280a8abba..e6cdf745e 100644 --- a/include/hxString.h +++ b/include/hxString.h @@ -46,10 +46,8 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES String static String create(const char16_t *inPtr,int inLen=-1); static String create(const char *inPtr,int inLen=-1); -#if (HXCPP_API_LEVEL>=500) static String create(const ::cpp::marshal::View& buffer); static String create(const ::cpp::marshal::View& buffer); -#endif // Uses non-gc memory and wont ever be collected static ::String createPermanent(const char *inUtf8, int inLen); @@ -173,10 +171,8 @@ class HXCPP_EXTERN_CLASS_ATTRIBUTES String const wchar_t *wchar_str(hx::IStringAlloc *inBuffer = 0) const; const char16_t *wc_str(hx::IStringAlloc *inBuffer = 0, int *outCharLength = 0) const; -#if (HXCPP_API_LEVEL >= 500) bool wc_str(::cpp::marshal::View buffer, int* outCharLength = nullptr) const; bool utf8_str(::cpp::marshal::View buffer, int* outByteLength = nullptr) const; -#endif const char *__CStr() const { return utf8_str(); }; const wchar_t *__WCStr() const { return wchar_str(0); } diff --git a/include/hxcpp.h b/include/hxcpp.h index 053a153b2..68824a682 100755 --- a/include/hxcpp.h +++ b/include/hxcpp.h @@ -351,15 +351,13 @@ typedef PropertyAccessMode PropertyAccess; #endif #include #include -#if (HXCPP_API_LEVEL>=500) - #include - #include - #include - #include - #include - #include - #include -#endif +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/String.cpp b/src/String.cpp index 280c8cdd4..fedef3873 100644 --- a/src/String.cpp +++ b/src/String.cpp @@ -788,7 +788,6 @@ String String::create(const char *inString,int inLength) return String(s,len); } -#if (HXCPP_API_LEVEL>=500) String String::create(const::cpp::marshal::View& buffer) { auto start = buffer.ptr.ptr; @@ -824,7 +823,6 @@ String String::create(const cpp::marshal::View& buffer) return String::create(buffer.ptr.ptr, buffer.length - (end - start) - extra); } -#endif String::String(const Dynamic &inRHS) { @@ -1794,8 +1792,6 @@ const char16_t * String::wc_str(hx::IStringAlloc *inBuffer, int *outCharLength) return str; } -#if (HXCPP_API_LEVEL >= 500) - bool String::wc_str(::cpp::marshal::View buffer, int* outCharLength) const { #ifdef HX_SMART_STRINGS @@ -1918,8 +1914,6 @@ bool String::utf8_str(::cpp::marshal::View buffer, int* outByteLength) con return true; } -#endif - const wchar_t * String::wchar_str(hx::IStringAlloc *inBuffer) const { if (!__s) diff --git a/src/hx/libs/zlib/Build.xml b/src/hx/libs/zlib/Build.xml new file mode 100644 index 000000000..ab0b3ee41 --- /dev/null +++ b/src/hx/libs/zlib/Build.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/hx/zip/zlib/ZLibCompress.cpp b/src/hx/zip/zlib/ZLibCompress.cpp index f9d0d5ad7..4abf9fb0c 100644 --- a/src/hx/zip/zlib/ZLibCompress.cpp +++ b/src/hx/zip/zlib/ZLibCompress.cpp @@ -84,8 +84,8 @@ hx::zip::Result hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View return Result( error == Z_STREAM_END, - dst.length - handle->total_in, - src.length - handle->total_out); + handle->total_in, + handle->total_out); } void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) From 8eeba87017f4aeef09571511f75598eaad1b99b0 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 11:30:18 +0000 Subject: [PATCH 79/89] no longer throwing on multiple close calls --- test/std/Test.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/std/Test.hx b/test/std/Test.hx index e505926da..4923bfce3 100644 --- a/test/std/Test.hx +++ b/test/std/Test.hx @@ -147,7 +147,7 @@ class Test extends utest.Test v("compressed size " + compressed.length ); v("try closing too many times..."); - Assert.exception(() -> compress.close(), String, null, "Zlib closed without throwing error"); + compress.close(); var decompressed = Uncompress.run(compressed); v("decompressed size:" + decompressed.length + "/" + bytes.length); From 0d611e88e448c03083dfef88f8fdb73aa69944bd Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 12:30:58 +0000 Subject: [PATCH 80/89] Give different file names to avoid cache issues --- src/hx/zip/Build.xml | 2 +- src/hx/zip/zlib/Build.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml index 325ddd01f..d6fdf1518 100644 --- a/src/hx/zip/Build.xml +++ b/src/hx/zip/Build.xml @@ -7,7 +7,7 @@ - + diff --git a/src/hx/zip/zlib/Build.xml b/src/hx/zip/zlib/Build.xml index 323dbae6d..97238c317 100644 --- a/src/hx/zip/zlib/Build.xml +++ b/src/hx/zip/zlib/Build.xml @@ -4,7 +4,7 @@ - + From 0a80434aba50ca98410ad5e25f088758df609afd Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 12:50:08 +0000 Subject: [PATCH 81/89] Fix old string value --- src/hx/zip/Build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml index d6fdf1518..c8d6df640 100644 --- a/src/hx/zip/Build.xml +++ b/src/hx/zip/Build.xml @@ -16,6 +16,6 @@ - + \ No newline at end of file From 36d829ffc34b4f65dad6666d34659f9996bab6fd Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 13:08:43 +0000 Subject: [PATCH 82/89] Another old string --- src/hx/zip/zlib/Build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hx/zip/zlib/Build.xml b/src/hx/zip/zlib/Build.xml index 97238c317..7d58ee735 100644 --- a/src/hx/zip/zlib/Build.xml +++ b/src/hx/zip/zlib/Build.xml @@ -38,7 +38,7 @@ - + From bc21f5e1f4b44bb1706cc436ba876c2ba419263f Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 13:56:55 +0000 Subject: [PATCH 83/89] static cast to int to avoid dynamic conversion of unsupported type --- src/hx/zip/zlib/ZLibCompress.cpp | 6 +++--- src/hx/zip/zlib/ZLibUncompress.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hx/zip/zlib/ZLibCompress.cpp b/src/hx/zip/zlib/ZLibCompress.cpp index 4abf9fb0c..1d11148ac 100644 --- a/src/hx/zip/zlib/ZLibCompress.cpp +++ b/src/hx/zip/zlib/ZLibCompress.cpp @@ -52,7 +52,7 @@ Array hx::zip::Compress_obj::run(cpp::marshal::View src, int l deflateEnd(handle.get()); - return output->slice(0, handle->total_out); + return output->slice(0, static_cast(handle->total_out)); } hx::zip::zlib::ZLibCompress::ZLibCompress(z_stream* inHandle) : handle(inHandle), flush(0) @@ -84,8 +84,8 @@ hx::zip::Result hx::zip::zlib::ZLibCompress::execute(cpp::marshal::View return Result( error == Z_STREAM_END, - handle->total_in, - handle->total_out); + static_cast(handle->total_in), + static_cast(handle->total_out)); } void hx::zip::zlib::ZLibCompress::setFlushMode(Flush mode) diff --git a/src/hx/zip/zlib/ZLibUncompress.cpp b/src/hx/zip/zlib/ZLibUncompress.cpp index c212332dd..9b88216d4 100644 --- a/src/hx/zip/zlib/ZLibUncompress.cpp +++ b/src/hx/zip/zlib/ZLibUncompress.cpp @@ -88,8 +88,8 @@ hx::zip::Result hx::zip::zlib::ZLibUncompress::execute(cpp::marshal::Viewtotal_in, - handle->total_out); + static_cast(handle->total_in), + static_cast(handle->total_out)); } void hx::zip::zlib::ZLibUncompress::setFlushMode(Flush mode) From 9deca1dbbb8f8062ba7da3475741186eb9ac7f9b Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 13:58:11 +0000 Subject: [PATCH 84/89] true instead of 1 for asLibrary value --- src/hx/zip/Build.xml | 2 +- src/hx/zip/zlib/Build.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml index c8d6df640..d60e849bf 100644 --- a/src/hx/zip/Build.xml +++ b/src/hx/zip/Build.xml @@ -10,7 +10,7 @@ - + diff --git a/src/hx/zip/zlib/Build.xml b/src/hx/zip/zlib/Build.xml index 7d58ee735..428132a2e 100644 --- a/src/hx/zip/zlib/Build.xml +++ b/src/hx/zip/zlib/Build.xml @@ -7,7 +7,7 @@ - + From 9b8536fcfa9ab058aa7e36a94eb84ec8dc1524ba Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 16:19:18 +0000 Subject: [PATCH 85/89] some build xml tweaks --- src/hx/zip/Build.xml | 5 ++- src/hx/zip/zlib/Build.xml | 88 +++++++++++++++++++++------------------ toolchain/haxe-target.xml | 3 ++ 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml index d60e849bf..2b7671eb8 100644 --- a/src/hx/zip/Build.xml +++ b/src/hx/zip/Build.xml @@ -7,10 +7,11 @@ - + + + - diff --git a/src/hx/zip/zlib/Build.xml b/src/hx/zip/zlib/Build.xml index 428132a2e..ef589f58d 100644 --- a/src/hx/zip/zlib/Build.xml +++ b/src/hx/zip/zlib/Build.xml @@ -1,44 +1,52 @@ - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - -
-
- - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/toolchain/haxe-target.xml b/toolchain/haxe-target.xml index a5aa5ea5d..8d7362e12 100644 --- a/toolchain/haxe-target.xml +++ b/toolchain/haxe-target.xml @@ -69,6 +69,9 @@ + + +
From 8207f7cd5007a52cdaef6fc3951561a5d19e8468 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 16:48:11 +0000 Subject: [PATCH 86/89] Make sure this_dir is used before Zip.cpp --- src/hx/zip/Build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hx/zip/Build.xml b/src/hx/zip/Build.xml index 2b7671eb8..0cf31265b 100644 --- a/src/hx/zip/Build.xml +++ b/src/hx/zip/Build.xml @@ -13,7 +13,7 @@ - + From bd15de5e00fc6db489e3662d23026a93970a39c6 Mon Sep 17 00:00:00 2001 From: Aidan63 Date: Sun, 14 Dec 2025 16:52:36 +0000 Subject: [PATCH 87/89] case sensitive --- src/hx/zip/zlib/{ZlibUncompress.hpp => ZLibUncompress.hpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/hx/zip/zlib/{ZlibUncompress.hpp => ZLibUncompress.hpp} (100%) diff --git a/src/hx/zip/zlib/ZlibUncompress.hpp b/src/hx/zip/zlib/ZLibUncompress.hpp similarity index 100% rename from src/hx/zip/zlib/ZlibUncompress.hpp rename to src/hx/zip/zlib/ZLibUncompress.hpp From 6d1b3283c3c5859dd5aa4dea5346a05e09fc437d Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 17:36:38 +0000 Subject: [PATCH 88/89] Fix case sensitivity in include --- src/hx/zip/zlib/ZLibUncompress.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hx/zip/zlib/ZLibUncompress.cpp b/src/hx/zip/zlib/ZLibUncompress.cpp index 9b88216d4..0ddc93706 100644 --- a/src/hx/zip/zlib/ZLibUncompress.cpp +++ b/src/hx/zip/zlib/ZLibUncompress.cpp @@ -1,5 +1,5 @@ #include -#include "ZlibUncompress.hpp" +#include "ZLibUncompress.hpp" #include #include From 5868d6bba04762b64f994d192bf470d2f4efdefe Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 14 Dec 2025 19:50:10 +0000 Subject: [PATCH 89/89] flip around files order --- src/hx/zip/zlib/Build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hx/zip/zlib/Build.xml b/src/hx/zip/zlib/Build.xml index ef589f58d..5cf210ed6 100644 --- a/src/hx/zip/zlib/Build.xml +++ b/src/hx/zip/zlib/Build.xml @@ -45,8 +45,8 @@ - +