Skip to content

Commit

Permalink
Merge Usertypes to v0.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Clemapfel authored Mar 6, 2022
2 parents 0eb6708 + 9d0a4fc commit d9c7a19
Show file tree
Hide file tree
Showing 23 changed files with 1,429 additions and 98 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
/libjluna_c_adapter.so
/.src/include_julia.inl
/.benchmark/results/
/docs/bckp.txt
23 changes: 22 additions & 1 deletion .src/exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <sstream>
#include <vector>
#include <iostream>

namespace jluna
{
Expand Down Expand Up @@ -55,9 +56,29 @@ namespace jluna
jl_eval_string("return jluna.exception_handler.get_last_exception()"),
jl_to_string(jl_eval_string("return jluna.exception_handler.get_last_message()"))
);
return;
}
}

Any* safe_eval(const char* str)
{
jluna::throw_if_uninitialized();

static jl_function_t* safe_call = jl_find_function("jluna.exception_handler", "safe_call");

jl_gc_pause;
auto* result = jl_call1(safe_call, jl_quote(str));
if (jl_exception_occurred() or jl_unbox_bool(jl_eval_string("jluna.exception_handler.has_exception_occurred()")))
{
std::cerr << "exception in jluna::State::safe_eval for expression:\n\"" << str << "\"\n" << std::endl;
forward_last_exception();
}
jl_gc_unpause;
return result;
}

Any* operator""_eval(const char* str, size_t _)
{
return safe_eval(str);
}
}

1 change: 1 addition & 0 deletions .src/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ namespace jluna::State::detail
UndefInitializer_t = Type(unroll("Core.UndefInitializer"));
Union_t = Type(unroll("Core.Union"));
UnionAll_t = Type(unroll("Core.UnionAll"));
UnionEmpty_t = Type(unroll("Union{}"));
Unsigned_t = Type(unroll("Core.Unsigned"));
VecElement_t = Type(unroll("Core.VecElement"));
WeakRef_t = Type(unroll("Core.WeakRef"));
Expand Down
4 changes: 2 additions & 2 deletions .src/state.inl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace jluna::State
return detail::create_or_assign(name, (jl_value_t*) jl_symbol(value.c_str()));
}

template<IsNumerical T>
template<IsPrimitive T>
Proxy new_named_complex(const std::string& name, T real, T imag)
{
return detail::create_or_assign(name, box<std::complex<T>>(std::complex<T>(real, imag)));
Expand Down Expand Up @@ -236,7 +236,7 @@ namespace jluna::State
return Proxy((jl_value_t*) jl_symbol(value.c_str()));
}

template<IsNumerical T>
template<IsPrimitive T>
Proxy new_unnamed_complex(T real, T imag)
{
return Proxy(box<std::complex<T>>(std::complex<T>(real, imag)));
Expand Down
2 changes: 1 addition & 1 deletion .src/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace jluna
Type::Type() = default;

Type::Type(jl_datatype_t* value)
: Proxy((jl_value_t*) value, value->name->name)
: Proxy((jl_value_t*) value, (value->name == NULL ? jl_symbol("Union{}") : value->name->name))
{}

Type::Type(Proxy* owner)
Expand Down
5 changes: 2 additions & 3 deletions .src/unbox.inl
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,15 @@ namespace jluna
return out;
}

template<typename T, typename T1, typename T2, std::enable_if_t<std::is_same_v<T, std::pair<T1, T2>>, bool>>
template<IsPair T>
T unbox(Any* value)
{
jl_gc_pause;

auto* first = jl_get_nth_field(value, 0);
auto* second = jl_get_nth_field(value, 1);

auto res = std::pair<T1, T2>(unbox<T1>(first), unbox<T2>(second));
auto res = T(unbox<typename T::first_type>(first), unbox<typename T::second_type>(second));
jl_gc_unpause;

return res;
Expand Down Expand Up @@ -240,7 +240,6 @@ namespace jluna
template<Is<Type> T>
T unbox(Any*);


template<IsTuple T>
T unbox(Any* value)
{
Expand Down
137 changes: 137 additions & 0 deletions .src/usertype.inl
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//
// Copyright 2022 Clemens Cords
// Created on 25.02.22 by clem ([email protected])
//

#include <include/exceptions.hpp>

namespace jluna
{
template<typename T>
struct to_julia_type<Usertype<T>>
{
static inline const std::string type_name = usertype_enabled<T>::name;
};


template<typename T>
void Usertype<T>::initialize()
{
throw_if_uninitialized();
_name = std::make_unique<Symbol>(get_name());
}

template<typename T>
template<typename Field_t>
void Usertype<T>::add_property(
const std::string& name,
std::function<Field_t(T&)> box_get,
std::function<void(T&, Field_t)> unbox_set)
{
if (_name.get() == nullptr)
initialize();

auto symbol = Symbol(name);

if (_mapping.find(name) == _mapping.end())
_fieldnames_in_order.push_back(symbol);

_mapping.insert({symbol, {
[box_get](T& instance) -> Any* {
return jluna::box<Field_t>(box_get(instance));
},
[unbox_set](T& instance, Any* value) -> void {
unbox_set(instance, jluna::unbox<Field_t>(value));
},
Type((jl_datatype_t*) jl_eval_string(to_julia_type<Field_t>::type_name.c_str()))
}});
}

template<typename T>
std::string Usertype<T>::get_name()
{
return usertype_enabled<T>::name;
}

template<typename T>
bool Usertype<T>::is_enabled()
{
return usertype_enabled<T>::value;
}

template<typename T>
void Usertype<T>::implement(Module module)
{
if (_name.get() == nullptr)
initialize();

jl_gc_pause;
static jl_function_t* implement = jl_find_function("jluna", "implement");
static jl_function_t* new_proxy = jl_find_function("jluna", "new_proxy");
static jl_function_t* setfield = jl_get_function(jl_base_module, "setindex!");

auto default_instance = T();
auto* template_proxy = jluna::safe_call(new_proxy, _name->operator Any*());

for (auto& field_name : _fieldnames_in_order)
jluna::safe_call(setfield, template_proxy, std::get<0>(_mapping.at(field_name))(default_instance), field_name);

_type = std::make_unique<Type>((jl_datatype_t*) jluna::safe_call(implement, template_proxy));
_implemented = true;
jl_gc_unpause;
}

template<typename T>
bool Usertype<T>::is_implemented()
{
return _implemented;
}

template<typename T>
Any* Usertype<T>::box(T& in)
{
if (not _implemented)
implement();

jl_gc_pause;
static jl_function_t* setfield = jl_get_function(jl_base_module, "setfield!");

Any* out = jl_call0(_type->operator Any*());

for (auto& pair : _mapping)
jluna::safe_call(setfield, out, pair.first, std::get<0>(pair.second)(in));

jl_gc_unpause;
return out;
}

template<typename T>
T Usertype<T>::unbox(Any* in)
{
if (not _implemented)
implement();

jl_gc_pause;
static jl_function_t* getfield = jl_get_function(jl_base_module, "getfield");

auto out = T();

for (auto& pair : _mapping)
std::get<1>(pair.second)(out, jluna::safe_call(getfield, in, pair.first));

jl_gc_unpause;
return out;
}

template<IsUsertype T>
T unbox(Any* in)
{
return Usertype<T>::unbox(in);
}

template<IsUsertype T>
Any* box(T in)
{
return Usertype<T>::box(in);
}
}
72 changes: 67 additions & 5 deletions .test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,17 @@
#include <.src/c_adapter.hpp>
#include <include/julia_extension.hpp>
#include <include/exceptions.hpp>
#include <include/concepts.hpp>

using namespace jluna;
using namespace jluna::detail;

struct NonJuliaType
{
std::vector<size_t> _field;
};
set_usertype_enabled(NonJuliaType);

int main()
{
State::initialize();
Expand All @@ -22,7 +30,6 @@ int main()
});
});


Test::test("jl_find_function", [](){

auto* expected = jl_get_function(jl_base_module, "println");
Expand All @@ -43,6 +50,12 @@ int main()
});
});

Test::test("safe_eval", [](){
Test::assert_that_throws<JuliaException>([]() {
safe_eval("throw(ErrorException(\"abc\"))");
});
});

auto test_box_unbox = []<typename T>(const std::string type_name, T value)
{
Test::test("box/unbox " + type_name , [value]() {
Expand Down Expand Up @@ -892,17 +905,17 @@ int main()

type = Type::construct_from<std::vector<int>>();
});

auto test_type = []<typename T>(Type& a, T b) {

std::string name = "Type Constant: ";
name += jl_to_string((Any*) a);

Test::test(name, [&](){
return a.operator jl_datatype_t*() == reinterpret_cast<jl_datatype_t*>(b);
});
};

test_type(AbstractArray_t, jl_abstractarray_type);
test_type(AbstractChar_t, jl_eval_string("return AbstractChar"));
test_type(AbstractFloat_t, jl_eval_string("return AbstractFloat"));
Expand Down Expand Up @@ -1081,6 +1094,55 @@ int main()
}
});

Test::test("Usertype: enable", [](){

Test::assert_that(Usertype<NonJuliaType>::get_name() == "NonJuliaType");
Test::assert_that(Usertype<NonJuliaType>::is_enabled());
});

Test::test("Usertype: add property", [](){

Usertype<NonJuliaType>::add_property<std::vector<size_t>>(
"_field",
[](NonJuliaType& in) -> std::vector<size_t> {
return in._field;
}
);

Usertype<NonJuliaType>::add_property<std::vector<size_t>>(
"_field",
[](NonJuliaType& in) -> std::vector<size_t> {
return in._field;
},
[](NonJuliaType& out, std::vector<size_t> in) -> void{
out._field = in;
}
);
});

Test::test("Usertype: implement", [](){
Usertype<NonJuliaType>::implement();
Usertype<NonJuliaType>::implement();

Test::assert_that(Usertype<NonJuliaType>::is_implemented());
});

Test::test("Usertype: box/unbox", [](){
auto instance = NonJuliaType{{123, 34556, 12321}};
auto sentinel = GCSentinel();

auto* res01 = Usertype<NonJuliaType>::box(instance);
auto* res02 = box<NonJuliaType>(instance);

Test::assert_that(jl_is_equal(res01, res02));

auto backres01 = Usertype<NonJuliaType>::unbox(res01);
auto backres02 = unbox<NonJuliaType>(res02);

Test::assert_that(backres01._field.size() == backres02._field.size());
});


Test::conclude();
}

Expand Down
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.16)
project(jluna)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_BUILD_TYPE Debug)

# compiler support
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "12.0.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2b -lstdc++")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL "10.0.0")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fconcepts")
else()
Expand Down Expand Up @@ -114,6 +114,11 @@ add_library(jluna SHARED

include/generator_expression.hpp
.src/generator_expression.cpp

include/usertype.hpp
.src/usertype.inl

include/gc_sentinel.hpp
)

set_target_properties(jluna PROPERTIES
Expand Down
Loading

0 comments on commit d9c7a19

Please sign in to comment.