Foreign function callbacks now receive a ModuleAndName parameter too.

This commit breaks the ARM64 version, I will fix it next.

Lots going on here. DynafuncMaker got updated to store strings
to back the ModuleAndName objects that get hardcoded in the
assembly glue function.
ModuleAndName is not a typedef to a tuple anymore, because I
discovered that tuples suck. They get always pushed on the stack
when passed as parameter, instead the new implementation gets
passed into 2 registers being it a standard layout type.

dhandy::bt::string got updated so it can be used as a literal
value for non-type template parameters, which allowed for a
really easy to use `wren::MN<>` helper. Code now fully requires
c++20.
This commit is contained in:
King_DuckZ 2022-05-17 01:00:00 +02:00
commit eadd25b827
16 changed files with 247 additions and 53 deletions

View file

@ -130,7 +130,7 @@ namespace wren {
detail::static_assert_all_packs_are_unique<Args...>();
foreign_class_t ret;
ret.allocate = [](VM& vm) {
ret.allocate = [](VM& vm, ModuleAndName mn) {
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
const auto result = detail::ForeignClassHelper<T, Args...>::construct(vm, vm.slot_count() - 1, mem);

View file

@ -61,7 +61,7 @@ namespace wren {
constexpr auto from = last_whatever + (last_whatever == fname_len ? 0 : 1);
constexpr auto len = detail::find_token_end(fname + from, fname_len - from);
constexpr dhandy::bt::string<len> retval{fname + from};
constexpr dhandy::bt::string<len> retval{fname + from, 0};
return retval;
//#elif defined(_MSC_VER)
//void __cdecl guess_class_name<class MyTest>(void)

View file

@ -3,6 +3,7 @@ include_files = [
'error_type.hpp',
'guess_class_name.hpp',
'has_method.hpp',
'module_and_name.hpp',
'setters_getters.hpp',
'string_bt.hpp',
'StringCRC32.hpp',

View file

@ -0,0 +1,98 @@
/* Copyright 2020-2022, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Wrenpp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with wrenpp. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "string_bt.hpp"
#include <string_view>
#include <cstdint>
namespace wren {
namespace detail {
template <dhandy::bt::string S>
struct ModuleAndNameStaticStorage {
static constexpr const auto value = S;
};
} //unnamed namespace
//Non-owning, lightweight class for storing a module nome/class name pair.
//They are stored as consecutive strings within a single buffer with a
//null-char in-between and at the end so that each name is null-terminated
//and can be used with C APIs.
//Keep the size small, ideally within 2 registers size. Altering this might
//require changes to the assembly source files for DynafuncMaker.
//When passed as a parameter by value, objects of ModuleAndName fit into
//2 registers on 64 bit architectures. This is important because objects
//of this class get hardcoded in the dynamic functions that DynafuncMaker
//spits out.
class ModuleAndName {
public:
constexpr ModuleAndName (const char* base, std::uint32_t hash, std::size_t mod_name_len, std::size_t class_name_len);
constexpr const char* module_name_char() const noexcept { return m_base; }
constexpr const char* class_name_char() const noexcept { return m_base + 1 + m_mod_name_len; }
constexpr std::size_t module_name_len() const noexcept { return m_mod_name_len; }
constexpr std::size_t class_name_len() const noexcept { return m_class_name_len; }
constexpr std::string_view module_name() const noexcept { return {module_name_char(), m_mod_name_len}; }
constexpr std::string_view class_name() const noexcept { return {class_name_char(), m_class_name_len}; }
constexpr const char* buffer_address() const noexcept { return m_base; }
private:
const char* m_base;
std::uint32_t m_hash;
std::uint16_t m_mod_name_len;
std::uint16_t m_class_name_len;
};
union RawAccessModuleAndName {
constexpr RawAccessModuleAndName (ModuleAndName mn) :
module_and_name(mn)
{ }
ModuleAndName module_and_name;
struct {
void* string;
void* data;
} raw;
static_assert(sizeof(raw) == sizeof(module_and_name));
};
constexpr ModuleAndName::ModuleAndName (const char* base, std::uint32_t hash, std::size_t mod_name_len, std::size_t class_name_len) :
m_base(base),
m_hash(hash),
m_mod_name_len(mod_name_len),
m_class_name_len(class_name_len)
{}
template <dhandy::bt::string S1, dhandy::bt::string S2>
constexpr ModuleAndName make_module_and_name() {
using dhandy::bt::string;
constexpr const char* data = detail::ModuleAndNameStaticStorage<S1 + string("\0") + S2>::value.data();
constexpr std::uint16_t s1_len = static_cast<std::uint16_t>(S1.size());
constexpr std::uint16_t s2_len = static_cast<std::uint16_t>(S2.size());
constexpr std::uint32_t hash = 0; //not implemented yet
return ModuleAndName{data, hash, s1_len, s2_len};
}
//short-hand alias for make_module_and_name
template <dhandy::bt::string S1, dhandy::bt::string S2>
constexpr ModuleAndName MN = make_module_and_name<S1, S2>();
} //namespace wren

View file

@ -41,7 +41,11 @@ namespace dhandy {
friend constexpr bool implem::eq<S, Ch> (const string<S, Ch>&, const string<S, Ch>&);
public:
using value_type = Ch;
constexpr string ( const value_type* parString );
constexpr string ( const string& other ) = default;
constexpr string ( const value_type (&parString)[S] );
//overload for pointers, int is only for overload disambiguation
constexpr string ( const value_type* parString, int );
constexpr std::size_t size ( void ) const { return S - 1; }
template <std::size_t S2>
@ -52,18 +56,26 @@ namespace dhandy {
template <std::size_t S2> constexpr bool operator== (const string<S2, Ch>&) const { return false; }
template <typename... Args>
requires (std::is_same_v<Args, typename string<S, Ch>::value_type> && ...)
constexpr string ( Args... );
constexpr const value_type (&data_arr() const)[S] { return m_data; }
constexpr const value_type* data() const { return m_data; }
private:
//can't have any private members but from below this point please
//consider everything as private
//private:
template <std::size_t... I>
constexpr string ( std::index_sequence<I...>, const value_type* parString );
const value_type m_data[S];
};
template <std::size_t S, typename Ch>
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
}
namespace implem {
template <std::size_t S, std::size_t S2, std::size_t... I>
constexpr string<S + S2 - 1> concat ( std::index_sequence<I...>, const string<S>& parLeft, const string<S2>& parRight ) {
@ -85,13 +97,20 @@ namespace dhandy {
}
template <std::size_t S, typename Ch>
inline constexpr string<S, Ch>::string (const value_type* parString) :
inline constexpr string<S, Ch>::string (const value_type (&parString)[S]) :
string(std::make_index_sequence<S>(), parString)
{
}
template <std::size_t S, typename Ch>
inline constexpr string<S, Ch>::string (const value_type* parString, int) :
string(std::make_index_sequence<S>(), parString)
{
}
template <std::size_t S, typename Ch>
template <typename... Args>
requires (std::is_same_v<Args, typename string<S, Ch>::value_type> && ...)
inline constexpr string<S, Ch>::string (Args... parArgs) :
m_data{parArgs...}
{
@ -109,16 +128,6 @@ namespace dhandy {
return parStream;
}
template <std::size_t S, typename Ch>
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
}
template <std::size_t S, typename Ch>
constexpr string<S, Ch> make_string (const Ch (&parData)[S]) {
return string<S>(parData);
}
template <std::size_t S, typename Ch>
constexpr bool string<S, Ch>::operator== (const string<S, Ch>& other) const {
return implem::eq(*this, other);
@ -127,7 +136,7 @@ namespace dhandy {
template <std::size_t S, typename Ch>
template <std::size_t Start, std::size_t Len>
constexpr auto string<S, Ch>::substr() const {
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1)) + make_string("");
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1), 0) + string("");
}
} //namespace bt
} //namespace dhandy

View file

@ -70,6 +70,7 @@ namespace wren {
template <std::size_t Count, std::size_t... Indices>
class StringsInVectorImplem<Count, std::index_sequence<Indices...>> : detail::StringsInVectorBase<Indices>... {
typedef detail::StringsInVectorWordRange WordRange;
template <typename... Strings> friend std::vector<char> strings_to_vector(const Strings&...);
public:
template <typename... Strings>
StringsInVectorImplem (const Strings&... strings);
@ -133,4 +134,10 @@ namespace wren {
template <std::size_t Count>
using StringsInVector = StringsInVectorImplem<Count, decltype(std::make_index_sequence<Count>())>;
template <typename... Strings>
inline std::vector<char> strings_to_vector (const Strings&... strings) {
StringsInVector<sizeof...(Strings)> siv{strings...};
return siv.m_memory;
}
} //namespace wren

View file

@ -17,16 +17,15 @@
#pragma once
#include "module_and_name.hpp"
#include <string_view>
#include <tuple>
namespace wren {
class VM;
typedef std::tuple<const char*, const char*> ModuleAndName;
typedef std::string_view wren_string_t;
typedef void(*finalizer_t)(void*);
typedef void(*foreign_method_t)(VM&);
typedef void(*foreign_method_t)(VM&, ModuleAndName);
struct foreign_class_t {
foreign_method_t allocate;

View file

@ -36,16 +36,16 @@ namespace wren {
R call (VM& vm, const Handle& object, const Handle& method, const Args&... args);
template <typename R, typename... Args>
R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args);
R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args);
template <typename R, std::size_t N, typename... Args>
R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args);
template <typename R, std::size_t N, typename... Args>
R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args);
R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args);
template <typename T, typename... Args>
T* make_wren_object(VM& vm, const ModuleAndName& mn, Args&&... args);
T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
#if defined(WRENPP_WITH_NAME_GUESSING)
template <typename T, typename... Args>
@ -56,9 +56,9 @@ namespace wren {
foreign_method_t make_method_bindable();
void interpret (VM& vm, const std::string& module_name, const std::string& script);
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot);
void variable(VM& vm, ModuleAndName mod_and_name, int slot);
void variable(VM& vm, const Handle& handle, int slot);
void variable_ensure_slot(VM& vm, const ModuleAndName& mod_and_name, int slot);
void variable_ensure_slot(VM& vm, ModuleAndName mod_and_name, int slot);
void variable_ensure_slot(VM& vm, const Handle& handle, int slot);
namespace detail {
@ -97,7 +97,7 @@ namespace wren {
public:
static foreign_method_t make() {
return [](VM& vm) {
return [](VM& vm, ModuleAndName) {
if constexpr (std::is_same_v<R, void>) {
call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
}
@ -113,7 +113,7 @@ namespace wren {
template <auto V> struct MakeMethodBindable;
template <typename T, void(T::*Method)(VM&)> struct MakeMethodBindable<Method> {
static foreign_method_t make() {
return [](VM& vm) {
return [](VM& vm, ModuleAndName) {
T* obj = foreign<T>(vm, 0);
(obj->*Method)(vm);
};
@ -139,7 +139,7 @@ namespace wren {
}
template <typename R, typename... Args>
inline R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args) {
inline R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args) {
vm.ensure_slots(sizeof...(args) + 1);
variable(vm, object, 0);
Handle obj_handle = vm.slot_handle(0);
@ -148,11 +148,13 @@ namespace wren {
template <typename R, std::size_t N, typename... Args>
inline R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args) {
using dhandy::bt::string;
const constexpr char dummy_name_buff[N] = {0};
const constexpr auto params = dhandy::bt::string<N, char>(dummy_name_buff) +
dhandy::bt::make_string("(") +
((static_cast<void>(args), dhandy::bt::make_string(",_")) + ... + dhandy::bt::make_string("")).template substr<1>() +
dhandy::bt::make_string(")");
const constexpr auto params = string<N, char>(dummy_name_buff) +
string("(") +
((static_cast<void>(args), string(",_")) + ... + string("")).template substr<1>() +
string(")");
;
char cat_buff[params.size() + 1];
std::copy(method, method + N - 1, cat_buff);
@ -161,7 +163,7 @@ namespace wren {
}
template <typename R, std::size_t N, typename... Args>
inline R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args) {
inline R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args) {
vm.ensure_slots(sizeof...(args) + 1);
variable(vm, object, 0);
Handle obj_handle = vm.slot_handle(0);
@ -169,7 +171,7 @@ namespace wren {
}
template <typename T, typename... Args>
inline T* make_wren_object(VM& vm, const ModuleAndName& mn, Args&&... args) {
inline T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
variable(vm, mn, 0);
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
T* const obj = new(mem) T{std::forward<Args>(args)...};