Compare commits
4 commits
master
...
python_mod
Author | SHA1 | Date | |
---|---|---|---|
86ae68dd50 | |||
dd259ef5bb | |||
ce6f67422f | |||
33b74fc7e4 |
68 changed files with 878 additions and 3284 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
tags
|
||||
compile_commands.json
|
||||
subprojects/wren/
|
||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -0,0 +1,3 @@
|
|||
[submodule "subprojects/wren/wren"]
|
||||
path = subprojects/wren/wren
|
||||
url = https://github.com/wren-lang/wren.git
|
143
README.md
143
README.md
|
@ -5,8 +5,6 @@ library. It aims to package all the features accessible through the C API in a
|
|||
modern C++ interface that is easy to use, while keeping the overhead to a
|
||||
minimum.
|
||||
|
||||
* [Current state](#current-state)
|
||||
* [Philosophy](#philosophy)
|
||||
* [Building](#building)
|
||||
* [Wrenpp](#wrenpp)
|
||||
* [Wren only](#wren-only)
|
||||
|
@ -15,29 +13,6 @@ minimum.
|
|||
* [C++](#c)
|
||||
* [Header files](#header-files)
|
||||
* [Initialisation](#initialisation)
|
||||
* [Foreign functions](#foreign-functions)
|
||||
* [Implementation](#implementation)
|
||||
|
||||
## Current state ##
|
||||
|
||||
The library is functional and provides access to most of the features of Wren.
|
||||
Some are better tested than others. There are no known memory leaks. Please
|
||||
keep in mind this is an early version and more testing and work will be needed.
|
||||
|
||||
## Philosophy ##
|
||||
|
||||
The overall principle behind this wrapper is to be feature rich while also
|
||||
being lightweight and allowing fine-grained control for users who need it.
|
||||
|
||||
By design, wrenpp hides the Wren C API entirely, but all functions (considered
|
||||
"low level" relative to this wrapper) are still accessible through the `VM`
|
||||
class. If the function you need is not available there it's probably just
|
||||
missing and adding it should be a trivial task.
|
||||
|
||||
Wrenpp provides you with convenience functions in `vm_fun.hpp` that are built
|
||||
on top of the `VM` class and make basic use of Wren simpler. You're still free
|
||||
to "mix & match" higher level functions with lower level ones, and you can
|
||||
decide to not use portions of the wrapper entirely.
|
||||
|
||||
## Building ##
|
||||
|
||||
|
@ -64,12 +39,6 @@ The build scripts understand the following options (double check in
|
|||
[random](http://wren.io/modules/random/) support
|
||||
5. `wren_with_meta` set to true to compile Wren with
|
||||
[meta](http://wren.io/modules/meta/) support
|
||||
6. `wrenpp_with_name_guessing` enable class name guessing in c++ code. It
|
||||
currently affects only example code and header files, not the library
|
||||
itself. It controls the `WRENPP_WITH_NAME_GUESSING` preprocessor symbol.
|
||||
When it's defined, you will have access to better error reporting and extra
|
||||
functions, such as a `make_wren_object()` overload that doesn't require you
|
||||
to specify a string class name.
|
||||
|
||||
Note that some example projects require random support in Wren, without which
|
||||
they will crash. If you want to run examples or you are getting "Address
|
||||
|
@ -117,19 +86,6 @@ executable('my_project',
|
|||
)
|
||||
```
|
||||
|
||||
And the matching wrenpp.wrap file for your project (remember to update the
|
||||
revision SHA and the dependency name):
|
||||
|
||||
```
|
||||
[wrap-git]
|
||||
url = https://alarmpi.no-ip.org/gitan/King_DuckZ/wrenpp.git
|
||||
revision = ebca413c0a3e885ac1901bd555e127476c40b057
|
||||
|
||||
[provide]
|
||||
wrenpp = wrenpp_dep
|
||||
dependency_names = wrenpp-0.2.0
|
||||
```
|
||||
|
||||
This will make Wrenpp build as part of your project with Wren's optional random
|
||||
module enabled.
|
||||
|
||||
|
@ -143,11 +99,19 @@ wrenpp_dep = dependency('wrenpp', version: '>=0.1.0',
|
|||
)
|
||||
```
|
||||
|
||||
Note that when you use Wrenpp as a subproject, Wrenpp's subproject Wren will
|
||||
become a sub-subproject of your project. This is how Meson works and it simply
|
||||
means that in your top level source directory you will have to run this command
|
||||
before you will be able to compile (Meson should detect and print this as
|
||||
well):
|
||||
|
||||
```
|
||||
meson wrap promote subprojects/wrenpp/subprojects/wren
|
||||
```
|
||||
|
||||
### C++ ###
|
||||
|
||||
For working examples refer to the source files in the `examples/` directory.
|
||||
"Greet" is the simplest example, while "math_vector" is showing off more
|
||||
features.
|
||||
|
||||
#### Header files ####
|
||||
|
||||
|
@ -164,8 +128,8 @@ at least. A description of all the relevant header files follows:
|
|||
* `def_configuration.hpp` The `DefConfiguration` struct extends the bare
|
||||
`Configuration` struct by providing an implementation for `write_fn`,
|
||||
`error_fn` and `reallocate_fn`. They are implemented in terms of `std::cout`,
|
||||
`std::cerr` and `std::realloc`/`std::free` respectively. You can safely ignore
|
||||
this header if this is not suitable for your project.
|
||||
`std::cerr` and `new[]`/`delete[]` respectively. You can safely ignore this
|
||||
header if this is not suitable for your project.
|
||||
|
||||
Other header files are intended for Wrenpp's use and you shouldn't need to use
|
||||
them. You are free to use them in your project if you think the code inside is
|
||||
|
@ -191,87 +155,4 @@ int main() {
|
|||
}
|
||||
```
|
||||
|
||||
#### Foreign functions ####
|
||||
|
||||
You have two options to register foreign functions with wrenpp: the easiest one
|
||||
is to just use the callback manager available through the `VM` object:
|
||||
|
||||
```
|
||||
#include <wrenpp/vm.hpp>
|
||||
#include <wrenpp/def_configuration.hpp>
|
||||
#include <wrenpp/callback_manager.hpp> //necessary if you want to use the callback manager
|
||||
|
||||
int main() {
|
||||
wren::DefConfiguration config;
|
||||
wren::VM vm(&config, nullptr);
|
||||
|
||||
vm.callback_manager()
|
||||
.add_callback(true, "your_module", "YourClass", "your_method(_,_)", &your_method);
|
||||
|
||||
vm.interpret("main", your_fun_script_here);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The current implementation available in `DefConfiguration` registers a callback
|
||||
to Wren that looks up a `std::unordered_map` for the correct c++ function and
|
||||
then forwards the call to it. This should be good enough for most cases,
|
||||
however you are free to provide your own callback for wren by writing your own
|
||||
Configuration class. Wrenpp tries to not impose you any particular helper code,
|
||||
in fact if you don't wish to use the `CallbackManager` returned by
|
||||
`vm.callback_manager()` then you don't even need to include the relative header
|
||||
file! There will still be a `std::unordered_map` in memory (because that's
|
||||
owned by `vm`) but it will never be used.
|
||||
|
||||
The second method requires you to provide the full Wren foreign functions
|
||||
callback:
|
||||
|
||||
```
|
||||
#include <wrenpp/vm.hpp>
|
||||
#include <wrenpp/def_configuration.hpp>
|
||||
|
||||
class MyConf : public wren::DefConfiguration {
|
||||
public:
|
||||
//This is the callback that Wren will call, refer to the C API documentation
|
||||
//for more details.
|
||||
wren::foreign_method_t foreign_method_fn(
|
||||
wren::VM* vm,
|
||||
std::string_view module,
|
||||
std::string_view class_name,
|
||||
bool is_static,
|
||||
std::string_view signature
|
||||
) {
|
||||
if (module == "your_module" and class_name == "YourClass") {
|
||||
if (is_static and signature == "your_method(_,_)")
|
||||
return &your_method;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
MyConf config;
|
||||
wren::VM vm(&config, nullptr);
|
||||
|
||||
vm.interpret("main", your_fun_script_here);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
The above code is very close to what you'd do with the C API. If you need, you
|
||||
can even pass a user data pointer to the `VM` constructor (`nullptr` in this
|
||||
snippet) and retrieve it later from within `foreign_method_fn()` via
|
||||
`vm.void_user_data()` or `vm.user_data()`. You're unlikely to need it as, as
|
||||
you can see, `foreign_method_fn()` is not static and so you can have some state
|
||||
stored in your `MyConf` object, however you still get the chance to use the
|
||||
C-like user data mechanism if you wish to.
|
||||
|
||||
Note that for the above to work the `foreign_method_fn()` method in `MyConf`
|
||||
must be named exactly like that, and the signature must match (except for the
|
||||
`static` and `const` keywords). Ideally the code above should alse be
|
||||
`noexcept` as there will be C code in the call stack when that method is
|
||||
invoked.
|
||||
|
||||
## Implementation ##
|
||||
|
||||
*Work in progress*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -17,8 +17,6 @@
|
|||
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "wrenpp/vm_fun.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
|
@ -69,7 +67,7 @@ System.print("You have %(cale.appointment_count()) appointment(s)")
|
|||
}
|
||||
}
|
||||
|
||||
static void today (wren::VM& vm, wren::ModuleAndName) {
|
||||
static void today (wren::VM& vm) {
|
||||
vm.set_slot_string(0, today_unique_str().get());
|
||||
}
|
||||
|
||||
|
@ -99,36 +97,54 @@ System.print("You have %(cale.appointment_count()) appointment(s)")
|
|||
|
||||
class MyConf : public wren::DefConfiguration {
|
||||
public:
|
||||
char* load_module_fn(wren::VM* vm, std::string_view module_name) {
|
||||
if (module_name == "calendar") {
|
||||
char* load_module_fn(wren::VM* vm, const char* module_name) {
|
||||
if (std::string_view{module_name} == "calendar") {
|
||||
constexpr const std::size_t buff_sz = sizeof(g_calendar_src);
|
||||
char* const buff = new char[buff_sz];
|
||||
char* const buff = static_cast<char*>(MyConf::reallocate_fn(nullptr, buff_sz));
|
||||
std::copy(g_calendar_src, g_calendar_src + buff_sz / sizeof(g_calendar_src[0]), buff);
|
||||
return buff;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void load_module_complete_fn(wren::VM*, std::string_view, char* buffer) {
|
||||
delete[] buffer;
|
||||
wren::foreign_method_t foreign_method_fn(wren::VM* vm, const char* m, const char* c, bool is_static, const char* s) {
|
||||
std::string_view module(m);
|
||||
std::string_view class_name(c);
|
||||
std::string_view signature(s);
|
||||
|
||||
if (module == "calendar" and class_name == "Calendar") {
|
||||
if (is_static and signature == "today()")
|
||||
return &Calendar::today;
|
||||
else if (not is_static and signature == "add_appointment(_)")
|
||||
return wren::make_method_bindable<&Calendar::add_appointment>();
|
||||
else if (not is_static and signature == "appointment_count()")
|
||||
return wren::make_method_bindable<&Calendar::appointment_count>();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
wren::foreign_class_t foreign_class_fn(wren::VM* vm, const char* m, const char* c) {
|
||||
std::string_view module(m);
|
||||
std::string_view class_name(c);
|
||||
|
||||
if (module == "calendar" and class_name == "Calendar") {
|
||||
return wren::make_foreign_class<Calendar>();
|
||||
}
|
||||
else {
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
}
|
||||
};
|
||||
} //unnamed namespace
|
||||
|
||||
int main() {
|
||||
using wren::MN;
|
||||
typedef wren::ModuleAndName MN;
|
||||
|
||||
MyConf conf;
|
||||
wren::VM vm(&conf, nullptr);
|
||||
vm.callback_manager()
|
||||
.add_callback(true, "calendar", "Calendar", "today()", [](){return &Calendar::today;})
|
||||
.add_callback(false, "calendar", "Calendar", "add_appointment(_)", wren::make_function_bindable<&Calendar::add_appointment>)
|
||||
.add_callback(false, "calendar", "Calendar", "appointment_count()", wren::make_function_bindable<&Calendar::appointment_count>);
|
||||
vm.class_manager().add_class_maker("calendar", "Calendar", wren::make_foreign_class<Calendar>);
|
||||
|
||||
vm.interpret("main", g_test_script);
|
||||
|
||||
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN<"main", "cale">)).data();
|
||||
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN{"main", "cale"}));
|
||||
cale->print_appointments();
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -1,219 +0,0 @@
|
|||
/* Copyright 2020-2024, 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/vm_fun.hpp"
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
constexpr char g_module_a[] =
|
||||
"foreign class ClassA {" R"script(
|
||||
construct new(msg) {
|
||||
System.print("Wren ClassA constructed")
|
||||
}
|
||||
|
||||
foreign say_hi()
|
||||
}
|
||||
)script";
|
||||
|
||||
constexpr char g_module_b[] = ""
|
||||
R"script(
|
||||
import "module_a" for ClassA
|
||||
|
||||
foreign class ClassB {
|
||||
construct new(nickname) {
|
||||
System.print("Wren ClassB constructed")
|
||||
}
|
||||
|
||||
do_action(obj_a, times) {
|
||||
System.print("Wren ClassB is doing its action %(times) times...")
|
||||
for (z in 1..times) {
|
||||
obj_a.say_hi()
|
||||
}
|
||||
greeting_message("John", "Doe", "\\(O.O)/")
|
||||
}
|
||||
|
||||
foreign greeting_message(first_name, family_name, emoji)
|
||||
foreign set_obj_c (obj)
|
||||
foreign get_obj_c()
|
||||
}
|
||||
)script";
|
||||
|
||||
constexpr char g_module_c[] =
|
||||
"foreign class ClassC {" R"script(
|
||||
construct new (msg) {}
|
||||
foreign print_message()
|
||||
}
|
||||
)script";
|
||||
|
||||
//This is several examples in one:
|
||||
//1. instantiate ClassA in Wren and pass it to do_action() which is a
|
||||
// non-foreign method in wren
|
||||
//2. instantiate ClassA in C++, have C++ invoke the non-foreign method
|
||||
// do_action() on the object obj_b from the previous execution and pass the
|
||||
// C++ instance of ClassA to it
|
||||
//3. instantiate ClassB in C++, have C++ invoke the non-foreign method
|
||||
// do_action() on it and pass the same ClassA instance from the previous
|
||||
// step to it
|
||||
//4. show how to return a pre-existing instance of ClassC from ClassB both in
|
||||
// C++ and Wren
|
||||
constexpr char g_script[] = ""
|
||||
R"script(
|
||||
import "module_a" for ClassA
|
||||
import "module_b" for ClassB
|
||||
import "module_c" for ClassC
|
||||
|
||||
var obj_b = ClassB.new("TheWren")
|
||||
obj_b.do_action(ClassA.new("instanciated from script"), 2)
|
||||
obj_b.greeting_message("Jane", "Doe", "ʕ·͡ᴥ·ʔ")
|
||||
|
||||
var obj_c = ClassC.new("Message of ClassC object instantiated in Wren")
|
||||
obj_b.set_obj_c(obj_c)
|
||||
obj_b.get_obj_c().print_message()
|
||||
)script";
|
||||
|
||||
class MyWrenConfig : public wren::DefConfiguration {
|
||||
public:
|
||||
char* load_module_fn (wren::VM* vm, std::string_view module_name) {
|
||||
if (module_name == "module_a")
|
||||
return copied(g_module_a, sizeof(g_module_a));
|
||||
else if (module_name == "module_b")
|
||||
return copied(g_module_b, sizeof(g_module_b));
|
||||
else if (module_name == "module_c")
|
||||
return copied(g_module_c, sizeof(g_module_c));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void load_module_complete_fn (wren::VM* vm, std::string_view module_name, char* buff) {
|
||||
static_cast<void>(vm);
|
||||
static_cast<void>(module_name);
|
||||
delete[] buff;
|
||||
}
|
||||
|
||||
private:
|
||||
char* copied (const char* source, std::size_t len) {
|
||||
char* const buff = new char[len];
|
||||
std::copy(source, source + len / sizeof(source[0]), buff);
|
||||
return buff;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassA {
|
||||
explicit ClassA (std::string msg) : m_message(msg) {
|
||||
std::cout << "C++ ClassA constructed\n";
|
||||
}
|
||||
ClassA (const ClassA&) = delete;
|
||||
ClassA (ClassA&&) = delete;
|
||||
|
||||
void say_hi() {
|
||||
std::cout << "C++ ClassA says \"" << m_message << "\"!\n";
|
||||
}
|
||||
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
class ClassC;
|
||||
|
||||
class ClassB {
|
||||
public:
|
||||
explicit ClassB (std::string nickname) : m_nickname(nickname) {
|
||||
std::cout << "C++ ClassB constructed\n";
|
||||
}
|
||||
|
||||
ClassB (const ClassB&) = delete;
|
||||
ClassB (ClassB&&) = delete;
|
||||
|
||||
void greeting_message (
|
||||
std::string_view first_name,
|
||||
const char* family_name,
|
||||
const std::string& emoji
|
||||
) {
|
||||
std::cout << "C++ ClassB says \"hello " << first_name << " '" <<
|
||||
m_nickname << "' " << family_name << "\" " << emoji << '\n';
|
||||
}
|
||||
|
||||
void set_obj_c (wren::ForeignObject<ClassC> obj) {
|
||||
m_obj_c = std::move(obj);
|
||||
}
|
||||
wren::ForeignObject<ClassC>* get_obj_c() { return &m_obj_c; }
|
||||
|
||||
private:
|
||||
std::string m_nickname;
|
||||
wren::ForeignObject<ClassC> m_obj_c;
|
||||
};
|
||||
|
||||
class ClassC {
|
||||
public:
|
||||
ClassC (std::string msg) : m_message(msg) {}
|
||||
void print_message() const { std::cout << m_message << '\n'; }
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
};
|
||||
} //unnamed namespace
|
||||
|
||||
int main() {
|
||||
using wren::make_function_bindable;
|
||||
using wren::make_foreign_class;
|
||||
using wren::make_wren_object;
|
||||
|
||||
//We need a custom one to deal with custom module loading for
|
||||
//module_a and module_b
|
||||
MyWrenConfig config;
|
||||
wren::VM vm(&config, nullptr);
|
||||
|
||||
|
||||
vm.callback_manager()
|
||||
.add_callback(false, "module_a", "ClassA", "say_hi()", make_function_bindable<&ClassA::say_hi>)
|
||||
.add_callback(false, "module_b", "ClassB", "greeting_message(_,_,_)", make_function_bindable<&ClassB::greeting_message>)
|
||||
.add_callback(false, "module_b", "ClassB", "set_obj_c(_)", make_function_bindable<&ClassB::set_obj_c>)
|
||||
.add_callback(false, "module_b", "ClassB", "get_obj_c()", make_function_bindable<&ClassB::get_obj_c>)
|
||||
.add_callback(false, "module_c", "ClassC", "print_message()", make_function_bindable<&ClassC::print_message>)
|
||||
;
|
||||
vm.class_manager()
|
||||
.add_class_maker("module_b", "ClassB", make_foreign_class<ClassB, std::string>)
|
||||
.add_class_maker("module_a", "ClassA", make_foreign_class<ClassA, std::string>)
|
||||
.add_class_maker("module_c", "ClassC", make_foreign_class<ClassC, std::string>)
|
||||
;
|
||||
|
||||
//Example 1: invoke obj_b.do_action() from Wren passing an obj_a that's
|
||||
//also instantiated from within the Wren script
|
||||
vm.interpret("main", g_script);
|
||||
|
||||
//Example 2: invoke obj_b.do_action() from C++ passing a new obj_a which
|
||||
//is instantiated from C++
|
||||
wren::ForeignObject<ClassA> obj_a = make_wren_object<ClassA>(vm, wren::MN<"module_a", "ClassA">, "instantiated from c++");
|
||||
wren::call<void>(vm, wren::MN<"main", "obj_b">, "do_action", obj_a, 3);
|
||||
|
||||
//Example 3: invoke obj_b.do_action() from C++, where obj_b is also
|
||||
//instantiated from C++, and pass the C++ obj_a instance to it
|
||||
auto obj_b = make_wren_object<ClassB>(vm, wren::MN<"module_b", "ClassB">, "TheCpp");
|
||||
wren::call<void>(vm, obj_b, "do_action", obj_a, 4);
|
||||
|
||||
//Example 4: set obj_c on obj_c and query it back
|
||||
wren::ForeignObject<ClassC> obj_c = make_wren_object<ClassC>(vm, wren::MN<"module_c", "ClassC">, "Message of ClassC object instantiated in C++");
|
||||
obj_b.object().set_obj_c(std::move(obj_c));
|
||||
obj_b.object().get_obj_c()->object().print_message();
|
||||
|
||||
std::cout << "Quitting in 1 sec" << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
return 0;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
executable('cpp_calls',
|
||||
'main.cpp',
|
||||
dependencies: wrenpp_dep,
|
||||
install: false,
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -17,7 +17,6 @@
|
|||
|
||||
#include "wrenpp/vm_fun.hpp"
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
@ -37,17 +36,50 @@ namespace {
|
|||
std::uniform_int_distribution<int> distrib;
|
||||
};
|
||||
|
||||
void user_input(wren::VM& vm, wren::ModuleAndName) {
|
||||
void user_input(wren::VM& vm) {
|
||||
std::string retval;
|
||||
std::cin >> retval;
|
||||
set(vm, 0, retval);
|
||||
}
|
||||
|
||||
void random_num(wren::VM& vm, wren::ModuleAndName) {
|
||||
void random_num(wren::VM& vm) {
|
||||
auto* const cust_data = vm.user_data<CustomData>();
|
||||
set(vm, 0, cust_data->distrib(cust_data->generator));
|
||||
}
|
||||
|
||||
class MyConfig : public wren::DefConfiguration {
|
||||
public:
|
||||
wren::foreign_method_t foreign_method_fn (
|
||||
wren::VM* vm,
|
||||
const char* module_ptr,
|
||||
const char* class_name_ptr,
|
||||
bool is_static,
|
||||
const char* signature_ptr
|
||||
) {
|
||||
std::string_view module(module_ptr);
|
||||
std::string_view class_name(class_name_ptr);
|
||||
std::string_view signature(signature_ptr);
|
||||
//std::cout << "requested: \"" << module << "\" \"" <<
|
||||
// class_name << "\" \"" << signature << "\" static: " <<
|
||||
// std::boolalpha << is_static << '\n';
|
||||
|
||||
if ("main" == module) {
|
||||
if ("Game" == class_name) {
|
||||
if ("user_input()" == signature and is_static)
|
||||
return &user_input;
|
||||
else if ("random()" == signature and is_static)
|
||||
return &random_num;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//char* load_module_fn (wren::VM* vm, const char* name) {
|
||||
// std::cout << "asked to load module \"" << name << "\"\n";
|
||||
// return nullptr;
|
||||
//}
|
||||
};
|
||||
|
||||
std::string load_file (const std::string& path) {
|
||||
std::ifstream ifs(path);
|
||||
ifs >> std::noskipws;
|
||||
|
@ -63,13 +95,10 @@ int main() {
|
|||
std::random_device rand_dev;
|
||||
CustomData custom_data(rand_dev());
|
||||
|
||||
wren::DefConfiguration config;
|
||||
MyConfig config;
|
||||
wren::VM vm(&config, &custom_data);
|
||||
vm.callback_manager().add_callback(true, "main", "Game", "user_input()", [](){return &user_input;})
|
||||
.add_callback(true, "main", "Game", "random()", [](){return &random_num;});
|
||||
|
||||
interpret(vm, "main", load_file("main.wren"));
|
||||
wren::call<void>(vm, wren::MN<"main", "the_game">, "play_game");
|
||||
wren::call<void>(vm, {"main", "the_game"}, "play_game");
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
return 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2024, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -17,11 +17,9 @@
|
|||
|
||||
#include "wrenpp/vm_fun.hpp"
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(__GNU_LIBRARY__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2)
|
||||
# define HasSecureGetenv
|
||||
|
@ -57,19 +55,39 @@ const char* raw_fetch_env (const char* name) noexcept {
|
|||
return val_ptr;
|
||||
}
|
||||
|
||||
void user_get_env (wren::VM& vm, wren::ModuleAndName) {
|
||||
void user_get_env (wren::VM& vm) {
|
||||
set(vm, 0, raw_fetch_env(wren::get<const char*>(vm, 1)));
|
||||
}
|
||||
|
||||
class MyConfig : public wren::DefConfiguration {
|
||||
public:
|
||||
wren::foreign_method_t foreign_method_fn (
|
||||
wren::VM* vm,
|
||||
const char* module_ptr,
|
||||
const char* class_name_ptr,
|
||||
bool is_static,
|
||||
const char* signature_ptr
|
||||
) {
|
||||
//std::cout << "VM " << vm << " requested foreign method " << class_name << "::" << signature << " in module " << module << "\n";
|
||||
std::string_view module(module_ptr);
|
||||
std::string_view class_name(class_name_ptr);
|
||||
std::string_view signature(signature_ptr);
|
||||
if ("User" == class_name and "main" == module and "get_env(_)" == signature)
|
||||
return &user_get_env;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
} //unnamed namespace
|
||||
|
||||
int main() {
|
||||
wren::DefConfiguration config;
|
||||
wren::VM vm(&config, nullptr);
|
||||
vm.callback_manager().add_callback(true, "main", "User", "get_env(_)", [](){return &user_get_env;});
|
||||
//typedef wren::ModuleAndName MN;
|
||||
|
||||
MyConfig config;
|
||||
wren::VM vm(&config, nullptr);
|
||||
vm.interpret("main", g_script);
|
||||
|
||||
wren::call<void>(vm, wren::MN<"main", "the_user">, "greet");
|
||||
wren::call<void>(vm, {"main", "the_user"}, "greet");
|
||||
|
||||
std::cout << "Quitting in 1 sec" << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "wrenpp/vm_fun.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
constexpr std::string_view g_math_vector_src{
|
||||
"foreign class MathVector {" R"script(
|
||||
construct new() {}
|
||||
construct new(value) {}
|
||||
construct new(x, y, z) {}
|
||||
|
||||
foreign x
|
||||
foreign y
|
||||
foreign z
|
||||
|
||||
foreign x=(value)
|
||||
foreign y=(value)
|
||||
foreign z=(value)
|
||||
|
||||
foreign static base_x()
|
||||
}
|
||||
)script"};
|
||||
|
||||
constexpr const char g_test_script[] =
|
||||
R"script(import "math_vector" for MathVector
|
||||
var vec1 = MathVector.new(15.0)
|
||||
var vec2 = MathVector.new(10.0, 20.0, 30.0)
|
||||
var vec3 = MathVector.new()
|
||||
System.print("vec1 constructed from single value: <%(vec1.x), %(vec1.y), %(vec1.z)>")
|
||||
System.print("vec2 constructed from three values: <%(vec2.x), %(vec2.y), %(vec2.z)>")
|
||||
System.print("vec3 default constructed: <%(vec3.x), %(vec3.y), %(vec3.z)>")
|
||||
|
||||
vec3.x = 3.5
|
||||
vec3.y = vec2.x / vec2.z
|
||||
vec3.z = vec1.x + vec2.y / 4.0
|
||||
System.print("vec3 modified by scripting: <%(vec3.x), %(vec3.y), %(vec3.z)>")
|
||||
|
||||
var vec_base_x = MathVector.base_x()
|
||||
System.print("vec_base_x modified by scripting: <%(vec_base_x.x), %(vec_base_x.y), %(vec_base_x.z)>")
|
||||
|
||||
)script";
|
||||
|
||||
template <typename T>
|
||||
class Vector {
|
||||
public:
|
||||
Vector() = default;
|
||||
explicit Vector (T value) :
|
||||
m_x(value), m_y(value), m_z(value)
|
||||
{}
|
||||
Vector (T x, T y, T z) :
|
||||
m_x(x), m_y(y), m_z(z)
|
||||
{}
|
||||
~Vector() noexcept = default;
|
||||
|
||||
T x() const { return m_x; }
|
||||
T y() const { return m_y; }
|
||||
T z() const { return m_z; }
|
||||
void set_x(T x) { m_x = x; }
|
||||
void set_y(T y) { m_y = y; }
|
||||
void set_z(T z) { m_z = z; }
|
||||
|
||||
static Vector base_x() { return {1.0, 0.0, 0.0}; }
|
||||
|
||||
private:
|
||||
T m_x{}, m_y{}, m_z{};
|
||||
};
|
||||
|
||||
class MyConf : public wren::DefConfiguration {
|
||||
public:
|
||||
char* load_module_fn(wren::VM* vm, std::string_view module_name) {
|
||||
if (module_name == "math_vector") {
|
||||
constexpr const std::size_t buff_sz = g_math_vector_src.size() + 1;
|
||||
char* const buff = new char[buff_sz];
|
||||
std::copy(g_math_vector_src.cbegin(), g_math_vector_src.cend(), buff);
|
||||
buff[buff_sz - 1] = '\0';
|
||||
return buff;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void load_module_complete_fn(wren::VM*, std::string_view, char* buffer) {
|
||||
delete[] buffer;
|
||||
}
|
||||
};
|
||||
} //unnamed namespace
|
||||
|
||||
int main() {
|
||||
using wren::make_function_bindable;
|
||||
using wren::make_foreign_class;
|
||||
using wren::ConstructorParameters;
|
||||
|
||||
MyConf conf;
|
||||
wren::VM vm(&conf, nullptr);
|
||||
vm.callback_manager()
|
||||
.add_callback(false, "math_vector", "MathVector", "x=(_)", make_function_bindable<&Vector<double>::set_x>)
|
||||
.add_callback(false, "math_vector", "MathVector", "y=(_)", make_function_bindable<&Vector<double>::set_y>)
|
||||
.add_callback(false, "math_vector", "MathVector", "z=(_)", make_function_bindable<&Vector<double>::set_z>)
|
||||
.add_callback(false, "math_vector", "MathVector", "x", make_function_bindable<&Vector<double>::x>)
|
||||
.add_callback(false, "math_vector", "MathVector", "y", make_function_bindable<&Vector<double>::y>)
|
||||
.add_callback(false, "math_vector", "MathVector", "z", make_function_bindable<&Vector<double>::z>)
|
||||
.add_callback(true, "math_vector", "MathVector", "base_x()", make_function_bindable<&Vector<double>::base_x>);
|
||||
|
||||
vm.class_manager()
|
||||
.add_class_maker("math_vector", "MathVector", make_foreign_class<Vector<double>,
|
||||
double, //single value constructor
|
||||
ConstructorParameters<double, double, double>, //x,y,z constructor
|
||||
ConstructorParameters<> //default constructor
|
||||
>);
|
||||
|
||||
vm.interpret("main", g_test_script);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
executable('math_vector',
|
||||
'main.cpp',
|
||||
dependencies: wrenpp_dep,
|
||||
install: false,
|
||||
)
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
subdir('dieroll')
|
||||
subdir('greet')
|
||||
subdir('calendar')
|
||||
subdir('math_vector')
|
||||
subdir('cpp_calls')
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
subdir('wrenpp')
|
148
include/wrenpp/StringCRC32.hpp
Normal file
148
include/wrenpp/StringCRC32.hpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
#ifndef id42C91D2875AE4E56BA61051619B58C03
|
||||
#define id42C91D2875AE4E56BA61051619B58C03
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace duckcore {
|
||||
class StringCRC32 {
|
||||
struct FnvHashBase {
|
||||
[[gnu::pure]] [[gnu::always_inline]]
|
||||
static uint32_t Calculate ( const char parChar, uint32_t parCrc );
|
||||
};
|
||||
|
||||
//Update step: crc_32_tab[(crc ^ ch) & 0xff] ^ (crc >> 8)
|
||||
template <uint32_t N, uint32_t I>
|
||||
struct FnvHash : private FnvHashBase {
|
||||
[[gnu::always_inline]]
|
||||
static uint32_t Calculate ( const char (&str)[N], uint32_t crc ) {
|
||||
const uint32_t prevcrc = FnvHash<N, I-1>::Calculate(str, crc);
|
||||
return FnvHashBase::Calculate(str[I-1], prevcrc);
|
||||
}
|
||||
};
|
||||
template <unsigned int N>
|
||||
struct FnvHash<N, 1> : private FnvHashBase {
|
||||
[[gnu::always_inline]]
|
||||
static uint32_t Calculate ( const char (&str)[N], uint32_t crc ) {
|
||||
return FnvHashBase::Calculate(str[0], crc);
|
||||
}
|
||||
};
|
||||
|
||||
class ConstCharWrapper {
|
||||
public:
|
||||
ConstCharWrapper ( const char* parStr ) : str(parStr) { }
|
||||
const char* const str;
|
||||
};
|
||||
public:
|
||||
|
||||
StringCRC32 ( ConstCharWrapper parStr );
|
||||
|
||||
template <unsigned int N>
|
||||
[[gnu::always_inline]]
|
||||
StringCRC32 ( const char (&str)[N] ) :
|
||||
m_hash(~FnvHash<N, N>::Calculate(str, 0xffffffff))
|
||||
{
|
||||
}
|
||||
|
||||
operator uint32_t ( void ) const { return m_hash; }
|
||||
|
||||
private:
|
||||
uint32_t m_hash;
|
||||
|
||||
private:
|
||||
//This is meant to represent a list of bits that are set to 1
|
||||
template <int N, typename T>
|
||||
struct BitArray {
|
||||
enum { value = N };
|
||||
typedef T Next;
|
||||
};
|
||||
//Polynomial from zlib: {0,1,2,4,5,7,8,10,11,12,16,22,23,26} or 0xedb88320UL
|
||||
// for (int poly = 0, n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
|
||||
// poly |= (z_crc_t)1 << (31 - p[n]);
|
||||
typedef BitArray<0, BitArray<1, BitArray<2, BitArray<4, BitArray<5,
|
||||
BitArray<7, BitArray<8, BitArray<10, BitArray<11, BitArray<12,
|
||||
BitArray<16, BitArray<22, BitArray<23,
|
||||
BitArray<26, nullptr_t> > > > > > > > > > > > > > PolynomialBits;
|
||||
template <typename P, int M>
|
||||
struct MakePolynomial {
|
||||
enum { value = (1 << (M - P::value)) bitor MakePolynomial<typename P::Next, M>::value };
|
||||
};
|
||||
template <int M>
|
||||
struct MakePolynomial<nullptr_t, M> {
|
||||
enum { value = 0 };
|
||||
};
|
||||
|
||||
//CRC32 algorithm from zlib:
|
||||
// for (int n = 0; n < 256; n++) {
|
||||
// c = n;
|
||||
// for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1;
|
||||
// crc_table[n] = c;
|
||||
// }
|
||||
template <int C, int S=8, uint32_t P=static_cast<uint32_t>(MakePolynomial<PolynomialBits, 31>::value)>
|
||||
struct TableLookup {
|
||||
static_assert(S > 1);
|
||||
enum {
|
||||
poly = P,
|
||||
value = TableLookup<TableLookup<C, S-1, poly>::value, 1, poly>::value
|
||||
};
|
||||
};
|
||||
template <int C, uint32_t P>
|
||||
struct TableLookup<C, 1, P> {
|
||||
enum {
|
||||
poly = P,
|
||||
value = ((C & 1) == 1 ? poly ^ (static_cast<uint32_t>(C) >> 1) : static_cast<uint32_t>(C) >> 1)
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
inline uint32_t StringCRC32::FnvHashBase::Calculate (const char parChar, uint32_t parCrc) {
|
||||
static const uint32_t crc_32_tab[256] = { /* CRC polynomial 0xedb88320 */
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
return crc_32_tab[(parCrc ^ parChar) & 0xff] ^ (parCrc >> 8);
|
||||
}
|
||||
} //namespace duckcore
|
||||
|
||||
#endif
|
|
@ -1,126 +0,0 @@
|
|||
/* 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 "detail/wren_types.hpp"
|
||||
#include "detail/strings_in_vector.hpp"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
|
||||
namespace wren::detail {
|
||||
class FullSignatureOwning;
|
||||
} //namespace wren::detail
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<wren::detail::FullSignatureOwning> {
|
||||
std::size_t operator() (const wren::detail::FullSignatureOwning& key) const;
|
||||
};
|
||||
};
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
class FullSignatureBase {
|
||||
public:
|
||||
FullSignatureBase (const FullSignatureBase& other) :
|
||||
m_module_hash(other.m_module_hash),
|
||||
m_class_name_hash(other.m_class_name_hash),
|
||||
m_signature_hash(other.m_signature_hash)
|
||||
{ }
|
||||
|
||||
std::size_t module_hash() const { return m_module_hash; }
|
||||
std::size_t class_hash() const { return m_class_name_hash; }
|
||||
std::size_t signature_hash() const { return m_signature_hash; }
|
||||
|
||||
protected:
|
||||
FullSignatureBase (std::size_t module_hash_v, std::size_t class_hash_v, std::size_t signature_hash_v) :
|
||||
m_module_hash(module_hash_v),
|
||||
m_class_name_hash(class_hash_v),
|
||||
m_signature_hash(signature_hash_v)
|
||||
{ }
|
||||
|
||||
private:
|
||||
std::size_t m_module_hash;
|
||||
std::size_t m_class_name_hash;
|
||||
std::size_t m_signature_hash;
|
||||
};
|
||||
|
||||
class FullSignatureOwning : public FullSignatureBase, private StringsInVector<3> {
|
||||
public:
|
||||
FullSignatureOwning (std::string_view module_name, std::string_view class_name, std::string_view signature);
|
||||
|
||||
std::string_view module_name() const { return as_string_view<0>(); }
|
||||
std::string_view class_name() const { return as_string_view<1>(); }
|
||||
std::string_view signature() const { return as_string_view<2>(); }
|
||||
};
|
||||
|
||||
//Temp because it's only supposed to be used to store temporaries
|
||||
//It will contain a dangling reference if the FullSignatureOwning object
|
||||
//used to initialise an object of this class gets destroyed
|
||||
class TempFullSignature : public FullSignatureBase {
|
||||
public:
|
||||
TempFullSignature (const FullSignatureOwning& mn);
|
||||
TempFullSignature (std::string_view module_name, std::string_view class_name, std::string_view signature);
|
||||
|
||||
std::string_view module_name() const { return m_module_name; }
|
||||
std::string_view class_name() const { return m_class_name; }
|
||||
std::string_view signature() const { return m_signature; }
|
||||
|
||||
private:
|
||||
std::string_view m_module_name;
|
||||
std::string_view m_class_name;
|
||||
std::string_view m_signature;
|
||||
};
|
||||
|
||||
struct FullSignatureEqual {
|
||||
using is_transparent = std::true_type;
|
||||
bool operator()(TempFullSignature left, TempFullSignature right) const;
|
||||
};
|
||||
|
||||
struct FullSignatureHash {
|
||||
using is_transparent = std::true_type;
|
||||
std::size_t operator()(TempFullSignature value) const;
|
||||
};
|
||||
} //namespace detail
|
||||
|
||||
class CallbackManager {
|
||||
typedef std::unordered_map<detail::FullSignatureOwning, foreign_method_t, detail::FullSignatureHash, detail::FullSignatureEqual> MethodMap;
|
||||
public:
|
||||
CallbackManager();
|
||||
~CallbackManager() noexcept;
|
||||
|
||||
CallbackManager& add_callback (
|
||||
bool is_static,
|
||||
std::string_view module_name,
|
||||
std::string_view class_name,
|
||||
std::string_view signature,
|
||||
std::function<foreign_method_t()> make_cb
|
||||
);
|
||||
foreign_method_t callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature) const;
|
||||
|
||||
private:
|
||||
MethodMap* method_map (bool is_static) noexcept;
|
||||
const MethodMap* method_map (bool is_static) const noexcept;
|
||||
|
||||
MethodMap m_static_methods;
|
||||
MethodMap m_normal_methods;
|
||||
};
|
||||
} //namespace wren
|
|
@ -1,151 +0,0 @@
|
|||
/* 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 "detail/wren_types.hpp"
|
||||
#include "detail/strings_in_vector.hpp"
|
||||
#include "detail/construct_foreign_class.hpp"
|
||||
#include "detail/wren_class_name_from_type.hpp"
|
||||
#include "detail/type_id.hpp"
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
class ClassNameBase {
|
||||
public:
|
||||
ClassNameBase (const std::string_view& module_name, const std::string_view& class_name);
|
||||
ClassNameBase (const ClassNameBase& other) = default;
|
||||
|
||||
std::size_t module_hash() const noexcept { return m_module_hash; }
|
||||
std::size_t class_hash() const noexcept { return m_class_name_hash; }
|
||||
|
||||
bool operator== (const ClassNameBase& other) const;
|
||||
|
||||
private:
|
||||
std::size_t m_module_hash;
|
||||
std::size_t m_class_name_hash;
|
||||
};
|
||||
|
||||
class ClassNameOwning : StringsInVector<2>, public ClassNameBase {
|
||||
public:
|
||||
ClassNameOwning (const std::string_view& module_name, const std::string_view& class_name);
|
||||
|
||||
std::string_view module_name() const { return this->as_string_view<0>(); }
|
||||
std::string_view class_name() const { return this->as_string_view<1>(); }
|
||||
operator ModuleAndName() const;
|
||||
|
||||
using StringsInVector<2>::operator<;
|
||||
bool operator== (const ClassNameOwning& other) const;
|
||||
};
|
||||
|
||||
class TempClassName : public ClassNameBase {
|
||||
public:
|
||||
TempClassName (std::string_view module_name, std::string_view class_name);
|
||||
TempClassName (const ClassNameOwning& model);
|
||||
bool operator== (const TempClassName& other) const;
|
||||
|
||||
std::string_view module_name() const { return m_module_name; }
|
||||
std::string_view class_name() const { return m_class_name; }
|
||||
|
||||
private:
|
||||
std::string_view m_module_name, m_class_name;
|
||||
};
|
||||
|
||||
struct ClassNameEqual {
|
||||
using is_transparent = std::true_type;
|
||||
bool operator()(TempClassName left, TempClassName right) const;
|
||||
};
|
||||
|
||||
struct ClassNameHash {
|
||||
using is_transparent = std::true_type;
|
||||
std::size_t operator()(TempClassName value) const;
|
||||
};
|
||||
|
||||
class TypeIDHash {
|
||||
public:
|
||||
std::size_t operator()(TypeID tid) const;
|
||||
};
|
||||
|
||||
define_has_typedef(class_type, ClassType);
|
||||
} //namespace detail
|
||||
|
||||
//Customisation point - specialise for your own types if needed
|
||||
template <typename T>
|
||||
struct ClassMakerTraits {
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct ClassMakerTraits<detail::MakeForeignClass<T, Args...>> {
|
||||
typedef T class_type;
|
||||
};
|
||||
|
||||
class ClassManager {
|
||||
typedef std::function<foreign_class_t()> make_foreign_class_t;
|
||||
typedef std::unordered_map<detail::ClassNameOwning, make_foreign_class_t, detail::ClassNameHash, detail::ClassNameEqual> ClassMap;
|
||||
typedef std::unordered_map<TypeID, const detail::ClassNameOwning*, detail::TypeIDHash> TypeMap;
|
||||
public:
|
||||
ClassManager();
|
||||
~ClassManager() noexcept;
|
||||
|
||||
template <typename F>
|
||||
ClassManager& add_class_maker (std::string module_name, std::string_view class_name, F&& maker);
|
||||
foreign_class_t make_class(std::string_view module_name, std::string_view class_name);
|
||||
ModuleAndName wren_class_name_from_hash(TypeID hash) const;
|
||||
template <typename T>
|
||||
ModuleAndName wren_class_name_from_type() const;
|
||||
|
||||
private:
|
||||
ClassMap::const_iterator add_class_maker_implem (
|
||||
std::string_view module_name,
|
||||
std::string_view class_name,
|
||||
make_foreign_class_t
|
||||
);
|
||||
|
||||
void add_type (TypeID hash, const detail::ClassNameOwning* name);
|
||||
|
||||
ClassMap m_classes;
|
||||
TypeMap m_types; //refers to memory in m_classes
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
inline ClassManager& ClassManager::add_class_maker (std::string module_name, std::string_view class_name, F&& maker) {
|
||||
typedef ClassMakerTraits<std::decay_t<F>> MakerTraits;
|
||||
|
||||
auto it_new = this->add_class_maker_implem(module_name, class_name, std::forward<F>(maker));
|
||||
|
||||
//See if we can deduce the class type that maker is supposed to work
|
||||
//with. This is not guaranteed to be an existing piece of info because
|
||||
//user code can provide their own function that doesn't use any actual
|
||||
//c++ class, just normal functions.
|
||||
if constexpr (detail::HasClassTypeTypedef<MakerTraits>::value) {
|
||||
const auto& owning_name = it_new->first;
|
||||
this->add_type(type_id<typename MakerTraits::class_type>(), &owning_name);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ModuleAndName ClassManager::wren_class_name_from_type() const {
|
||||
return detail::wren_class_name_from_type<T>(*this);
|
||||
}
|
||||
} //namespace wren
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -18,16 +18,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "configuration.hpp"
|
||||
#include "detail/wren_types.hpp"
|
||||
#include "detail/error_type.hpp"
|
||||
#include "error_type.hpp"
|
||||
|
||||
namespace wren {
|
||||
class VM;
|
||||
|
||||
typedef void(*foreign_method_t)(VM&);
|
||||
|
||||
class DefConfiguration : public Configuration {
|
||||
public:
|
||||
static void write_fn (VM*, wren_string_t text);
|
||||
static void error_fn (VM*, ErrorType, wren_string_t module_name, int line, wren_string_t msg);
|
||||
static void write_fn (VM*, const char* text);
|
||||
static void error_fn (VM*, ErrorType, const char* module, int line, const char* msg);
|
||||
static void* reallocate_fn(void* ptr, std::size_t size);
|
||||
static foreign_method_t foreign_method_fn (VM* vm, wren_string_t module_name, wren_string_t class_name, bool is_static, wren_string_t signature);
|
||||
static foreign_class_t foreign_class_fn (wren::VM* vm, std::string_view module_name, std::string_view class_name);
|
||||
};
|
||||
} //namespace wren
|
||||
|
|
|
@ -1,175 +0,0 @@
|
|||
/* Copyright 2020-2024, 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 "../vm.hpp"
|
||||
#include "setters_getters.hpp"
|
||||
#if defined(WRENPP_WITH_NAME_GUESSING)
|
||||
# include "guess_class_name.hpp"
|
||||
#endif
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
namespace wren {
|
||||
template <typename... Args> struct ConstructorParameters { };
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename... Args, int... Indices>
|
||||
inline void construct_single (
|
||||
std::integer_sequence<int, Indices...>,
|
||||
VM& vm,
|
||||
void* memory
|
||||
) {
|
||||
new(memory) T{get<Args>(vm, Indices + 1)...};
|
||||
}
|
||||
|
||||
struct ConstructResult {
|
||||
std::uint16_t parameter_count;
|
||||
bool success;
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct ForeignClassHelper;
|
||||
|
||||
template <typename T, typename... PackArgs, typename... Args>
|
||||
struct ForeignClassHelper<T, ConstructorParameters<PackArgs...>, Args...> {
|
||||
static ConstructResult construct (VM& vm, int cardinality, void* memory) {
|
||||
using std::make_integer_sequence;
|
||||
|
||||
//search by number of parameters.
|
||||
//once we find a ConstructorParameters that contains the right
|
||||
//number of types we invoke construct_single() with those types.
|
||||
constexpr int pack_size = static_cast<int>(sizeof...(PackArgs));
|
||||
if (pack_size == cardinality) {
|
||||
construct_single<T, PackArgs...>(make_integer_sequence<int, pack_size>{}, vm, memory);
|
||||
return ConstructResult{pack_size, true};
|
||||
}
|
||||
else {
|
||||
return ForeignClassHelper<T, Args...>::construct(vm, cardinality, memory);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename LoneArg, typename... Args>
|
||||
struct ForeignClassHelper<T, LoneArg, Args...> {
|
||||
static ConstructResult construct (VM& vm, int cardinality, void* memory) {
|
||||
using std::make_integer_sequence;
|
||||
|
||||
if (1 == cardinality) {
|
||||
construct_single<T, LoneArg>(make_integer_sequence<int, 1>{}, vm, memory);
|
||||
return ConstructResult{1, true};
|
||||
}
|
||||
else {
|
||||
if constexpr (sizeof...(Args) > 0) {
|
||||
return ForeignClassHelper<T, Args...>::construct(vm, cardinality, memory);
|
||||
}
|
||||
else {
|
||||
return ConstructResult{0, false};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ForeignParamHelper {
|
||||
static constexpr std::size_t argument_count = 1;
|
||||
};
|
||||
|
||||
template <template <typename...> class Pack, typename... PackArgs>
|
||||
struct ForeignParamHelper<Pack<PackArgs...>> {
|
||||
static constexpr std::size_t argument_count = sizeof...(PackArgs);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ForeignClassHelper<T> {
|
||||
static ConstructResult construct (VM& vm, int cardinality, void* memory) {
|
||||
using std::make_integer_sequence;
|
||||
|
||||
if (cardinality == 0) {
|
||||
construct_single<T>(make_integer_sequence<int, 0>{}, vm, memory);
|
||||
return ConstructResult{0, true};
|
||||
}
|
||||
else {
|
||||
return ConstructResult{static_cast<std::uint16_t>(cardinality), false};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t Search, std::size_t... Values>
|
||||
struct AssertIfDuplicateValues {
|
||||
static_assert(sizeof...(Values) == 0, "Code bug?");
|
||||
};
|
||||
|
||||
template <std::size_t Search, std::size_t Value, std::size_t... Values>
|
||||
struct AssertIfDuplicateValues<Search, Value, Values...> : AssertIfDuplicateValues<Search, Values...>, AssertIfDuplicateValues<Value, Values...> {
|
||||
static_assert(Search != Value, "Constructor overloads with the same argument counts are not currently allowed");
|
||||
static constexpr std::size_t value = 1;
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
constexpr void static_assert_all_packs_are_unique() {
|
||||
//If more than one arg (ctor overload) is given, check they are unique
|
||||
if constexpr (sizeof...(Args) > 1) {
|
||||
constexpr auto dummy = AssertIfDuplicateValues<ForeignParamHelper<Args>::argument_count...>::value;
|
||||
static_assert(dummy == 1); //always true
|
||||
}
|
||||
}
|
||||
|
||||
//This is named from the perspective of the user - they say
|
||||
//MakeForeignClass<X> and it will "produce" object of type X. In
|
||||
//reality it produces a functor that does that, and it's that functor
|
||||
//that gets registered into wren, so from the library perspective it
|
||||
//should be called MakeForeignClassMaker
|
||||
template <typename T, typename... Args>
|
||||
class MakeForeignClass {
|
||||
public:
|
||||
MakeForeignClass() = default;
|
||||
|
||||
foreign_class_t operator()() const {
|
||||
detail::static_assert_all_packs_are_unique<Args...>();
|
||||
|
||||
foreign_class_t ret;
|
||||
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);
|
||||
if (not result.success) {
|
||||
abort_fiber_with_error(vm, 1,
|
||||
std::string{"No registered c++ constructor "} +
|
||||
#if defined(WRENPP_WITH_NAME_GUESSING)
|
||||
"for class " + guess_class_name<T>() + " " +
|
||||
#endif
|
||||
"takes " + std::to_string(result.parameter_count) +
|
||||
" parameter" + (result.parameter_count == 1 ? "" : "s")
|
||||
);
|
||||
}
|
||||
};
|
||||
ret.finalize = [](void* mem) {
|
||||
const auto cale = static_cast<T*>(mem);
|
||||
cale->~T();
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
} //namespace detail
|
||||
|
||||
template <typename T, typename... Args>
|
||||
constexpr detail::MakeForeignClass<T, Args...> make_foreign_class;
|
||||
} //namespace wren
|
|
@ -1,97 +0,0 @@
|
|||
/* 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 <cstdint>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
[[gnu::const]]
|
||||
std::uint32_t runtime_crc32c (const char* data, std::size_t size, std::uint32_t crc);
|
||||
|
||||
constexpr std::uint32_t g_castagnoli_polynomial = 0x1EDC6F41;
|
||||
|
||||
[[gnu::const]]
|
||||
constexpr std::uint8_t reverse (std::uint8_t b) {
|
||||
//see https://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
|
||||
return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
|
||||
}
|
||||
|
||||
[[gnu::const]]
|
||||
constexpr std::uint32_t reverse (std::uint32_t val) {
|
||||
return (reverse(static_cast<std::uint8_t>(val & 0xff)) << 24) |
|
||||
(reverse(static_cast<std::uint8_t>(val >> 8 & 0xff)) << 16) |
|
||||
(reverse(static_cast<std::uint8_t>(val >> 16 & 0xff)) << 8) |
|
||||
reverse(static_cast<std::uint8_t>(val >> 24 & 0xff));
|
||||
}
|
||||
|
||||
consteval std::uint32_t calc_table_entry (std::uint32_t index, std::uint32_t polynomial) {
|
||||
polynomial = reverse(polynomial);
|
||||
auto c = static_cast<std::uint_fast32_t>(index);
|
||||
for (std::uint_fast32_t k = 0; k < 8; ++k) {
|
||||
c = (c >> 1) ^ ((c & 0x1u) ? polynomial : 0);
|
||||
}
|
||||
return static_cast<std::uint32_t>(c);
|
||||
}
|
||||
|
||||
template <std::uint32_t Polynomial, typename T>
|
||||
struct PolynomialTableBase;
|
||||
|
||||
template <std::uint32_t Polynomial, std::uint32_t... Indices>
|
||||
struct PolynomialTableBase<Polynomial, std::integer_sequence<std::uint32_t, Indices...>> {
|
||||
static constexpr std::size_t table_size = sizeof...(Indices);
|
||||
static constexpr std::uint32_t table[table_size] = {calc_table_entry(Indices, Polynomial)...};
|
||||
};
|
||||
|
||||
template <std::uint32_t Polynomial>
|
||||
struct PolynomialTable : public PolynomialTableBase<Polynomial, decltype(std::make_integer_sequence<std::uint32_t, 256>{})> {
|
||||
};
|
||||
|
||||
template <std::uint32_t Polynomial>
|
||||
constexpr inline auto g_polynomial_table = PolynomialTable<Polynomial>::table;
|
||||
|
||||
template <std::uint32_t Polynomial, std::uint32_t XorIn=0xffffffff, std::uint32_t XorOut=XorIn>
|
||||
constexpr std::uint32_t crc32 (const char* data, std::size_t len, std::uint32_t crc) noexcept {
|
||||
//static_assert(g_polynomial_table<Polynomial>[0b10000000] == Polynomial);
|
||||
crc ^= XorIn;
|
||||
for (std::size_t z = 0; z < len; ++z) {
|
||||
crc = g_polynomial_table<Polynomial>[(crc ^ static_cast<unsigned char>(data[z])) & 0xff] ^ (crc >> 8);
|
||||
}
|
||||
return crc ^ XorOut;
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
[[gnu::const]]
|
||||
constexpr std::uint32_t crc32c (const char* data, std::size_t size) {
|
||||
if (not std::is_constant_evaluated()) {
|
||||
return detail::runtime_crc32c(data, size, 0);
|
||||
}
|
||||
else {
|
||||
return detail::crc32<detail::g_castagnoli_polynomial>(data, size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
[[gnu::const]]
|
||||
constexpr std::uint32_t crc32c (const T (&data)[N]) {
|
||||
return crc32c(static_cast<const char*>(data), N * sizeof(T));
|
||||
}
|
||||
} //namespace wren
|
|
@ -1,42 +0,0 @@
|
|||
/* Copyright 2020-2024, 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 <type_traits>
|
||||
|
||||
namespace wren::detail {
|
||||
|
||||
//Dereferences the given parameter if necessary, always returning an optionally
|
||||
//cv-qualified ref
|
||||
template <typename T>
|
||||
struct DerefIFN {
|
||||
static typename std::remove_reference<T>::type& deref (
|
||||
typename std::remove_reference<T>::type& param
|
||||
) {
|
||||
return param;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DerefIFN<T*> {
|
||||
static T& deref (T* param) { return *param; }
|
||||
};
|
||||
|
||||
//Add specialisations for std::unique_ptr & co?
|
||||
|
||||
} //namespace wren::detail
|
|
@ -1,97 +0,0 @@
|
|||
/* Copyright 2020-2024, 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 "wrenpp/handle.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace wren {
|
||||
|
||||
class VM;
|
||||
|
||||
//This is meant to be a short lived object representing a still-in-a-slot
|
||||
//foreign object. Upon casting it to ForeignObject it will create a handle to
|
||||
//the data in given slot
|
||||
template <typename T>
|
||||
class TempForeignObject {
|
||||
public:
|
||||
TempForeignObject (VM* vm, T* object, int slot_num) :
|
||||
m_vm(vm),
|
||||
m_data(object),
|
||||
m_slot_num(slot_num)
|
||||
{ }
|
||||
|
||||
VM* vm() const { return m_vm; }
|
||||
T* data() const { return m_data; }
|
||||
int slot_num() const { return m_slot_num; }
|
||||
|
||||
private:
|
||||
VM* m_vm;
|
||||
T* m_data;
|
||||
int m_slot_num;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ForeignObject {
|
||||
public:
|
||||
ForeignObject() = default;
|
||||
ForeignObject (std::nullptr_t) : ForeignObject() {}
|
||||
ForeignObject (T* obj, Handle&& handle);
|
||||
ForeignObject (ForeignObject&&) = default;
|
||||
ForeignObject (const TempForeignObject<T>& temp_object);
|
||||
~ForeignObject() noexcept = default;
|
||||
|
||||
ForeignObject& operator= (ForeignObject&&) = default;
|
||||
bool operator!= (std::nullptr_t) const { return nullptr != m_object; }
|
||||
bool operator== (std::nullptr_t) const { return nullptr == m_object; }
|
||||
|
||||
void set_to_slot (int num);
|
||||
T& object() { return *m_object; }
|
||||
const T& object() const { return *m_object; }
|
||||
Handle& handle() { return m_handle; }
|
||||
const Handle& handle() const { return m_handle; }
|
||||
bool is_valid() const { return nullptr != m_object; }
|
||||
|
||||
operator T&() { return object(); }
|
||||
operator const T&() const { return object(); }
|
||||
operator Handle&() { return handle(); }
|
||||
operator const Handle&() const { return handle(); }
|
||||
|
||||
private:
|
||||
Handle m_handle;
|
||||
T* m_object{nullptr};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline ForeignObject<T>::ForeignObject (T* obj, Handle&& handle) :
|
||||
m_handle(std::move(handle)),
|
||||
m_object(obj)
|
||||
{ }
|
||||
|
||||
template <typename T>
|
||||
inline ForeignObject<T>::ForeignObject (const TempForeignObject<T>& temp_object) :
|
||||
m_handle(temp_object.vm(), temp_object.slot_num()),
|
||||
m_object(temp_object.data())
|
||||
{ }
|
||||
|
||||
template <typename T>
|
||||
inline void ForeignObject<T>::set_to_slot (int num) {
|
||||
m_handle.set_to_slot(num);
|
||||
}
|
||||
|
||||
} //namespace wren
|
|
@ -1,82 +0,0 @@
|
|||
/* 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 <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
consteval std::size_t find_last (const char* str, std::size_t len, char c) {
|
||||
for (std::size_t z = len; z > 0; --z) {
|
||||
if (str[z - 1] == c)
|
||||
return z - 1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
consteval std::size_t find_token_end (const char* str, std::size_t len) {
|
||||
for (std::size_t z = 0; z < len; ++z) {
|
||||
const bool is_lower = str[z] >= 'a' and str[z] <= 'z';
|
||||
const bool is_upper = str[z] >= 'A' and str[z] <= 'Z';
|
||||
const bool is_num = str[z] >= '0' and str[z] <= '9';
|
||||
const bool is_special = str[z] == '_' or str[z] == ':';
|
||||
if (not (is_lower or is_upper or is_num or is_special))
|
||||
return z;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
consteval auto guess_class_name_impl() {
|
||||
#if defined(__GNUC__)
|
||||
constexpr auto fname = __PRETTY_FUNCTION__;
|
||||
constexpr auto fname_len = sizeof(__PRETTY_FUNCTION__) / sizeof(__PRETTY_FUNCTION__[0]) - 1;
|
||||
static_assert(fname_len > 0);
|
||||
|
||||
# if defined(__clang__)
|
||||
//clang: void figure_out_name() [T = MyTest]
|
||||
# else
|
||||
//gcc: void figure_out_name() [with T = MyTest]
|
||||
# endif
|
||||
constexpr auto last_colon = detail::find_last(fname, fname_len, ':');
|
||||
constexpr auto last_space = detail::find_last(fname, fname_len, ' ');
|
||||
constexpr auto last_whatever = (last_colon == fname_len ? last_space : last_colon);
|
||||
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+1> retval{fname + from, 0};
|
||||
return retval;
|
||||
//#elif defined(_MSC_VER)
|
||||
//void __cdecl guess_class_name<class MyTest>(void)
|
||||
//__FUNCSIG__
|
||||
#else
|
||||
# error "Unsupported compiler"
|
||||
#endif
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
template <typename T, std::size_t S=detail::guess_class_name_impl<T>().size()>
|
||||
constexpr dhandy::bt::string g_guessed_class_name = {detail::guess_class_name_impl<T>()};
|
||||
|
||||
template <typename T>
|
||||
constexpr const char* guess_class_name() {
|
||||
return g_guessed_class_name<T>.data();
|
||||
}
|
||||
} //namespace wren
|
|
@ -1,41 +0,0 @@
|
|||
/* Copyright 2020-2024, 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 "deref_ifn.hpp"
|
||||
|
||||
namespace wren::detail {
|
||||
|
||||
template <typename T, typename TRaw>
|
||||
struct IsKindOfHandleHelper {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
template <typename TRaw>
|
||||
struct IsKindOfHandleHelper<Handle, TRaw> {
|
||||
static constexpr bool value = true;
|
||||
static void set_to_slot (int slot_num, TRaw obj) {DerefIFN<TRaw>::deref(obj).set_to_slot(slot_num);}
|
||||
};
|
||||
template <typename U, typename TRaw>
|
||||
struct IsKindOfHandleHelper<ForeignObject<U>, TRaw> {
|
||||
static constexpr bool value = true;
|
||||
static void set_to_slot (int slot_num, TRaw obj) {DerefIFN<TRaw>::deref(obj).set_to_slot(slot_num);}
|
||||
};
|
||||
template <typename T>
|
||||
using IsKindOfHandle = IsKindOfHandleHelper<typename std::remove_pointer<typename std::remove_cvref<T>::type>::type, T>;
|
||||
|
||||
} //namespace wren::detail
|
|
@ -1,18 +0,0 @@
|
|||
include_files = [
|
||||
'construct_foreign_class.hpp',
|
||||
'crc32.hpp',
|
||||
'error_type.hpp',
|
||||
'guess_class_name.hpp',
|
||||
'has_method.hpp',
|
||||
'module_and_name.hpp',
|
||||
'setters_getters.hpp',
|
||||
'string_bt.hpp',
|
||||
'strings_in_vector.hpp',
|
||||
'type_id.hpp',
|
||||
'wren_class_name_from_type.hpp',
|
||||
'wren_types.hpp',
|
||||
]
|
||||
|
||||
if not meson.is_subproject()
|
||||
install_headers(include_files)
|
||||
endif
|
|
@ -1,168 +0,0 @@
|
|||
/* 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 "crc32.hpp"
|
||||
#include <string_view>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wren {
|
||||
typedef decltype(crc32c(nullptr, 0)) ModuleAndNameHashType;
|
||||
class ModuleAndName;
|
||||
|
||||
namespace detail {
|
||||
template <dhandy::bt::string Str>
|
||||
struct ModuleAndNameStaticStorage {
|
||||
static constexpr dhandy::bt::string value = Str;
|
||||
};
|
||||
|
||||
[[gnu::const]]
|
||||
bool deep_equal (const ModuleAndName& a, const ModuleAndName& b) noexcept;
|
||||
} //unnamed namespace
|
||||
|
||||
//Non-owning, lightweight class for storing a module name + generic name
|
||||
//pair. It holds a hash value too, which is currently only meaningful for
|
||||
//module name/class name pairs that are mapped to a c++ class.
|
||||
//Names 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 {
|
||||
friend bool detail::deep_equal(const ModuleAndName&, const ModuleAndName&) noexcept;
|
||||
template <dhandy::bt::string S1, dhandy::bt::string S2>
|
||||
friend consteval ModuleAndName make_module_and_name() noexcept;
|
||||
public:
|
||||
constexpr ModuleAndName();
|
||||
constexpr ModuleAndName (const char* base, std::size_t mod_name_len, std::size_t class_name_len);
|
||||
|
||||
constexpr bool operator==(const ModuleAndName& other) const noexcept;
|
||||
constexpr bool operator!=(const ModuleAndName& other) const noexcept;
|
||||
constexpr bool deep_equal(const ModuleAndName& other) const noexcept;
|
||||
|
||||
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:
|
||||
constexpr ModuleAndName (const char* base, ModuleAndNameHashType hash, std::size_t mod_name_len, std::size_t class_name_len);
|
||||
|
||||
constexpr std::size_t raw_buffer_size() const noexcept;
|
||||
|
||||
const char* m_base;
|
||||
ModuleAndNameHashType m_hash;
|
||||
std::uint16_t m_mod_name_len;
|
||||
std::uint16_t m_class_name_len;
|
||||
|
||||
static_assert(
|
||||
sizeof(m_hash) <= sizeof(std::uint32_t),
|
||||
"Hash type is too large, review this struct or change it back to uint32_t"
|
||||
);
|
||||
};
|
||||
|
||||
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() :
|
||||
ModuleAndName(nullptr, 0, 0, 0)
|
||||
{}
|
||||
|
||||
constexpr ModuleAndName::ModuleAndName (const char* base, std::size_t mod_name_len, std::size_t class_name_len) :
|
||||
ModuleAndName(base, crc32c(base, mod_name_len + class_name_len + 2), mod_name_len, class_name_len)
|
||||
{}
|
||||
|
||||
constexpr ModuleAndName::ModuleAndName (const char* base, ModuleAndNameHashType 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)
|
||||
{}
|
||||
|
||||
constexpr bool ModuleAndName::operator==(const ModuleAndName& other) const noexcept {
|
||||
const bool retval = (this->m_hash == other.m_hash and deep_equal(other));
|
||||
return retval;
|
||||
}
|
||||
|
||||
constexpr bool ModuleAndName::operator!=(const ModuleAndName& other) const noexcept {
|
||||
return not this->operator==(other);
|
||||
}
|
||||
|
||||
constexpr bool ModuleAndName::deep_equal(const ModuleAndName& other) const noexcept {
|
||||
if (not std::is_constant_evaluated()) {
|
||||
return detail::deep_equal(*this, other);
|
||||
}
|
||||
else {
|
||||
if (this->raw_buffer_size() != other.raw_buffer_size())
|
||||
return false;
|
||||
for (std::size_t z = 0; z < raw_buffer_size(); ++z) {
|
||||
if (this->m_base[z] != other.m_base[z])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr std::size_t ModuleAndName::raw_buffer_size() const noexcept {
|
||||
return m_mod_name_len + m_class_name_len + 2;
|
||||
}
|
||||
|
||||
template <dhandy::bt::string S1, dhandy::bt::string S2>
|
||||
consteval ModuleAndName make_module_and_name() noexcept {
|
||||
using dhandy::bt::string;
|
||||
using detail::ModuleAndNameStaticStorage;
|
||||
constexpr string null_char{"\0"};
|
||||
using StaticStorage = ModuleAndNameStaticStorage<S1 + null_char + S2>;
|
||||
|
||||
constexpr const char* data = StaticStorage::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 ModuleAndNameHashType hash = crc32c(
|
||||
StaticStorage::value.data(),
|
||||
StaticStorage::value.size()
|
||||
);
|
||||
|
||||
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
|
|
@ -1,189 +0,0 @@
|
|||
/* Copyright 2020-2024, 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 "../vm.hpp"
|
||||
#include "../handle.hpp"
|
||||
#include "foreign_object.hpp"
|
||||
#include "module_and_name.hpp"
|
||||
#include "is_kindof_handle.hpp"
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
template <typename T> struct GetTypeToRetType;
|
||||
template <typename T> using GetTypeToRetType_t = typename GetTypeToRetType<T>::type;
|
||||
|
||||
template <typename T> struct TType { typedef T type; };
|
||||
|
||||
template<typename T>struct GetTypeToRetType{
|
||||
static_assert(not std::is_fundamental_v<T>, "User type expected");
|
||||
static_assert(not std::is_pointer_v<T>, "Unexpected pointer type");
|
||||
typedef TempForeignObject< std::remove_cv_t<T> > type;
|
||||
};
|
||||
template<typename T>struct GetTypeToRetType<ForeignObject<T>> {
|
||||
//This doesn't make much sense, essentially you're asking wrenpp to
|
||||
//give you a foreign object by vm/slot when you already have its
|
||||
//handle
|
||||
};
|
||||
template<typename T>struct GetTypeToRetType<TempForeignObject<T>> : TType<TempForeignObject<T>>{};
|
||||
template<>struct GetTypeToRetType<const char*> : TType<const char*>{};
|
||||
template<>struct GetTypeToRetType<double> : TType<double>{};
|
||||
template<>struct GetTypeToRetType<bool> : TType<bool>{};
|
||||
template<>struct GetTypeToRetType<std::pair<const char*,int>> : TType<std::pair<const char*,int>> {};
|
||||
template<>struct GetTypeToRetType<int> : TType<int>{};
|
||||
template<>struct GetTypeToRetType<std::size_t> : TType<std::size_t>{};
|
||||
template<>struct GetTypeToRetType<std::string> : TType<std::string>{};
|
||||
template<>struct GetTypeToRetType<std::string_view> : TType<std::string_view>{};
|
||||
template<>struct GetTypeToRetType<std::vector<char>> : TType<std::vector<char>>{};
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename T>
|
||||
concept ConstCharTuple =
|
||||
std::same_as<std::decay_t<T>, Handle> or
|
||||
std::same_as<std::decay_t<T>, ModuleAndName>;
|
||||
#endif
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename... Outs, int... Indices, ConstCharTuple... Params>
|
||||
#else
|
||||
template <typename... Outs, int... Indices, typename... Params>
|
||||
#endif
|
||||
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables_impl (
|
||||
VM& vm,
|
||||
std::integer_sequence<int, Indices...>,
|
||||
Params&&... modules_names
|
||||
) {
|
||||
if constexpr (sizeof...(Outs) == 0) {
|
||||
return {};
|
||||
}
|
||||
else {
|
||||
static_assert(sizeof...(Params) == sizeof...(Outs), "Expected a module/name pair per requested output");
|
||||
static_assert(sizeof...(Outs) == sizeof...(Indices), "Mismatching index count");
|
||||
|
||||
vm.ensure_slots(sizeof...(Params));
|
||||
(variable(vm, modules_names, Indices), ...);
|
||||
return std::tuple<detail::GetTypeToRetType_t<Outs>...>(get<Outs>(vm, Indices)...);
|
||||
}
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
void set (VM& vm, int slot_num, const char* value);
|
||||
void set (VM& vm, int slot_num, double value);
|
||||
void set (VM& vm, int slot_num, bool value);
|
||||
void set (VM& vm, int slot_num, std::nullptr_t);
|
||||
void set (VM& vm, int slot_num, const char* bytes, std::size_t length);
|
||||
void set (VM& vm, int slot_num, const std::string& value);
|
||||
void set (VM& vm, int slot_num, std::string_view value);
|
||||
void set (VM& vm, int slot_num, const std::vector<char>& value);
|
||||
void set (VM& vm, int slot_num, const char* beg, const char* end);
|
||||
void set (VM& vm, int slot_num, int value);
|
||||
void set (VM& vm, int slot_num, std::size_t value);
|
||||
void set (VM& vm, int slot_num, const Handle& handle);
|
||||
void set (VM& vm, int slot_num, const ModuleAndName& name);
|
||||
std::string_view slot_string_view (VM& vm, int slot_num);
|
||||
template <typename T> detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num);
|
||||
template <typename T> T* foreign (VM& vm, int slot_num);
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename... Outs, detail::ConstCharTuple... Params>
|
||||
#else
|
||||
template <typename... Outs, typename... Params>
|
||||
#endif
|
||||
std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names);
|
||||
|
||||
inline void set (VM& vm, int slot_num, const char* value) {
|
||||
vm.set_slot_string(slot_num, value);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, double value) {
|
||||
vm.set_slot_double(slot_num, value);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, bool value) {
|
||||
vm.set_slot_bool(slot_num, value);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, std::nullptr_t) {
|
||||
vm.set_slot_null(slot_num);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const char* bytes, std::size_t length) {
|
||||
vm.set_slot_bytes(slot_num, bytes, length);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const std::string& value) {
|
||||
vm.set_slot_string(slot_num, value.c_str());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, std::string_view value) {
|
||||
vm.set_slot_bytes(slot_num, value.data(), value.size());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const std::vector<char>& value) {
|
||||
vm.set_slot_bytes(slot_num, value.data(), value.size());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, int value) {
|
||||
vm.set_slot_double(slot_num, static_cast<double>(value));
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, std::size_t value) {
|
||||
vm.set_slot_double(slot_num, static_cast<double>(value));
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const Handle& handle) {
|
||||
vm.set_slot_handle(handle, slot_num);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const ModuleAndName& name) {
|
||||
vm.variable_or_throw(name.module_name_char(), name.class_name_char(), slot_num);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* foreign (VM& vm, int slot_num) {
|
||||
T* obj = static_cast<T*>(vm.slot_foreign(slot_num));
|
||||
return obj;
|
||||
}
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename... Outs, detail::ConstCharTuple... Params>
|
||||
#else
|
||||
template <typename... Outs, typename... Params>
|
||||
#endif
|
||||
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names) {
|
||||
return detail::variables_impl<Outs...>(vm, std::make_integer_sequence<int, sizeof...(Outs)>(), std::forward<Params>(modules_names)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num) {
|
||||
return {&vm, foreign<T>(vm, slot_num), slot_num};
|
||||
}
|
||||
|
||||
template<> const char* get<const char*> (VM& vm, int slot_num);
|
||||
template<> double get<double> (VM& vm, int slot_num);
|
||||
template<> bool get<bool> (VM& vm, int slot_num);
|
||||
template<> std::pair<const char*, int> get<std::pair<const char*,int>> (VM& vm, int slot_num);
|
||||
template<> int get<int> (VM& vm, int slot_num);
|
||||
template<> std::size_t get<std::size_t> (VM& vm, int slot_num);
|
||||
template<> std::string get<std::string> (VM& vm, int slot_num);
|
||||
template<> std::string_view get<std::string_view> (VM& vm, int slot_num);
|
||||
template<> std::vector<char> get<std::vector<char>> (VM& vm, int slot_num);
|
||||
} //namespace wren
|
|
@ -1,157 +0,0 @@
|
|||
/* 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 <vector>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
template <std::size_t Num>
|
||||
struct StringsInVectorBase;
|
||||
|
||||
struct StringsInVectorWordRange {
|
||||
std::size_t start, length;
|
||||
};
|
||||
|
||||
template <std::size_t Num>
|
||||
struct StringsInVectorBase {
|
||||
explicit StringsInVectorBase (StringsInVectorWordRange range) :
|
||||
m_word_range(range)
|
||||
{ }
|
||||
|
||||
StringsInVectorWordRange m_word_range;
|
||||
};
|
||||
|
||||
template <std::size_t Index, typename String, typename... Strings>
|
||||
[[gnu::pure]]
|
||||
std::size_t string_offset_at_index (const String& string, const Strings&... strings) {
|
||||
static_assert(Index < sizeof...(Strings) + 1, "Index out of range");
|
||||
|
||||
if constexpr (not Index) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return std::string_view{string}.size() + string_offset_at_index<Index - 1>(strings...);
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_zero (char& value) {
|
||||
value = '\0';
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
template <std::size_t Count, typename IndexSeq>
|
||||
class StringsInVectorImplem;
|
||||
|
||||
//It's a class that stores a series of strings in a vector, consecutively
|
||||
//and interleaved by a null char. Objects of this class are safe to move
|
||||
//and copy, move doesn't invalidate previously obtained string_views
|
||||
//and strings_views are guaranteed to be null-terminated, so the result
|
||||
//of data() is safe to pass to C functions.
|
||||
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);
|
||||
|
||||
template <std::size_t Index>
|
||||
std::string_view as_string_view() const;
|
||||
|
||||
bool operator== (const StringsInVectorImplem& other) const;
|
||||
bool operator< (const StringsInVectorImplem& other) const;
|
||||
|
||||
protected:
|
||||
const char* raw_buffer() const;
|
||||
std::size_t raw_buffer_size() const;
|
||||
|
||||
private:
|
||||
std::vector<char> m_memory;
|
||||
};
|
||||
|
||||
template <std::size_t Count, std::size_t... Indices>
|
||||
template <typename... Strings>
|
||||
inline StringsInVectorImplem<Count, std::index_sequence<Indices...>>::StringsInVectorImplem(const Strings&... strings) :
|
||||
detail::StringsInVectorBase<Indices>(WordRange{detail::string_offset_at_index<Indices>(strings...) + Indices, std::string_view{strings}.size()})...
|
||||
{
|
||||
using detail::string_offset_at_index;
|
||||
using detail::set_zero;
|
||||
|
||||
const std::size_t buffer_size = (std::string_view{strings}.size() + ...) + sizeof...(Indices);
|
||||
m_memory.resize(buffer_size);
|
||||
(std::copy(
|
||||
std::string_view{strings}.cbegin(),
|
||||
std::string_view{strings}.cend(),
|
||||
m_memory.begin() + string_offset_at_index<Indices>(strings...) + Indices
|
||||
), ...);
|
||||
|
||||
//zero out the byte after each string
|
||||
(set_zero(m_memory[string_offset_at_index<Indices>(strings...) + Indices + std::string_view(strings).size()]), ...);
|
||||
}
|
||||
|
||||
template <std::size_t Count, std::size_t... Indices>
|
||||
template <std::size_t Index>
|
||||
inline std::string_view StringsInVectorImplem<Count, std::index_sequence<Indices...>>::as_string_view() const {
|
||||
static_assert(Index < Count, "Index out of range");
|
||||
const auto& word_range = detail::StringsInVectorBase<Index>::m_word_range;
|
||||
assert(m_memory.size() >= word_range.start + word_range.length + 1);
|
||||
|
||||
std::string_view retval{
|
||||
m_memory.data() + word_range.start,
|
||||
word_range.length
|
||||
};
|
||||
assert(*(retval.data() + retval.length()) == '\0');
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <std::size_t Count, std::size_t... Indices>
|
||||
inline bool StringsInVectorImplem<Count, std::index_sequence<Indices...>>::operator== (const StringsInVectorImplem& other) const {
|
||||
return this->m_memory == other.m_memory;
|
||||
}
|
||||
|
||||
template <std::size_t Count, std::size_t... Indices>
|
||||
inline bool StringsInVectorImplem<Count, std::index_sequence<Indices...>>::operator< (const StringsInVectorImplem& other) const {
|
||||
std::string_view this_memory{m_memory.data(), m_memory.size()};
|
||||
std::string_view other_memory{other.m_memory.data(), other.m_memory.size()};
|
||||
return this_memory < other_memory;
|
||||
}
|
||||
|
||||
template <std::size_t Count, std::size_t... Indices>
|
||||
inline const char* StringsInVectorImplem<Count, std::index_sequence<Indices...>>::raw_buffer() const {
|
||||
return m_memory.data();
|
||||
}
|
||||
|
||||
template <std::size_t Count, std::size_t... Indices>
|
||||
inline std::size_t StringsInVectorImplem<Count, std::index_sequence<Indices...>>::raw_buffer_size() const {
|
||||
return m_memory.size();
|
||||
}
|
||||
|
||||
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
|
|
@ -1,65 +0,0 @@
|
|||
/* 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 <cstdint>
|
||||
|
||||
namespace wren {
|
||||
//from:
|
||||
//https://codereview.stackexchange.com/questions/48594/unique-type-id-no-rtti
|
||||
class TypeID {
|
||||
using sig = TypeID();
|
||||
|
||||
sig* m_id;
|
||||
constexpr TypeID(sig* id) : m_id{id} {}
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
friend constexpr TypeID type_id();
|
||||
|
||||
TypeID (const TypeID&) = default;
|
||||
TypeID (TypeID&&) = default;
|
||||
~TypeID() noexcept = default;
|
||||
TypeID& operator= (const TypeID&) = default;
|
||||
TypeID& operator= (TypeID&&) = default;
|
||||
|
||||
constexpr bool operator==(TypeID other) const noexcept;
|
||||
constexpr bool operator!=(TypeID other) const noexcept;
|
||||
constexpr bool operator<(TypeID other) const noexcept;
|
||||
constexpr std::uintptr_t id() const noexcept;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr TypeID type_id() { return &type_id<T>; }
|
||||
|
||||
constexpr bool TypeID::operator==(TypeID other) const noexcept {
|
||||
return id() == other.id();
|
||||
}
|
||||
|
||||
constexpr bool TypeID::operator!=(TypeID other) const noexcept {
|
||||
return id() != other.id();
|
||||
}
|
||||
|
||||
constexpr bool TypeID::operator<(TypeID other) const noexcept {
|
||||
return id() < other.id();
|
||||
}
|
||||
|
||||
constexpr std::uintptr_t TypeID::id() const noexcept {
|
||||
return reinterpret_cast<std::uintptr_t>(m_id);
|
||||
}
|
||||
} //namespace wren
|
|
@ -1,44 +0,0 @@
|
|||
/* 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 "module_and_name.hpp"
|
||||
#include "type_id.hpp"
|
||||
#include "crc32.hpp"
|
||||
#include <utility>
|
||||
#include <string_view>
|
||||
|
||||
namespace wren {
|
||||
class VM;
|
||||
|
||||
namespace detail {
|
||||
//Just an utility function to call a method on the class manager in vm
|
||||
//and return its return value without including the header for the
|
||||
//class manager. Useful in inline functions in header files where
|
||||
//including class_manager.hpp would propagate it everywhere.
|
||||
ModuleAndName fetch_class_name_from_manager (
|
||||
const VM& vm,
|
||||
TypeID hash
|
||||
);
|
||||
|
||||
template <typename T>
|
||||
inline ModuleAndName wren_class_name_from_type (const VM& vm) {
|
||||
return fetch_class_name_from_manager(vm, type_id<T>());
|
||||
}
|
||||
} //namespace detail
|
||||
} //namespace wren
|
|
@ -1,34 +0,0 @@
|
|||
/* 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 "module_and_name.hpp"
|
||||
#include <string_view>
|
||||
|
||||
namespace wren {
|
||||
class VM;
|
||||
|
||||
typedef std::string_view wren_string_t;
|
||||
typedef void(*finalizer_t)(void*);
|
||||
typedef void(*foreign_method_t)(VM&, ModuleAndName);
|
||||
|
||||
struct foreign_class_t {
|
||||
foreign_method_t allocate;
|
||||
finalizer_t finalize;
|
||||
};
|
||||
} //namespace wren
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2024, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -27,7 +27,6 @@ namespace wren {
|
|||
Handle() noexcept;
|
||||
Handle (const Handle&) = delete;
|
||||
Handle (Handle&& other) noexcept;
|
||||
Handle (VM* vm, int slot_num);
|
||||
Handle (VM* vm, WrenHandle* handle) noexcept :
|
||||
m_handle(handle),
|
||||
m_vm(vm)
|
||||
|
@ -43,8 +42,6 @@ namespace wren {
|
|||
operator WrenHandle*() const { return m_handle; }
|
||||
operator bool() const { return nullptr != m_handle; }
|
||||
|
||||
void set_to_slot (int num);
|
||||
|
||||
private:
|
||||
WrenHandle* m_handle;
|
||||
VM* m_vm;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -66,17 +66,5 @@
|
|||
}; \
|
||||
}
|
||||
|
||||
#define define_has_typedef(typedef_name,pretty_name) \
|
||||
template <typename T> \
|
||||
struct Has ## pretty_name ## Typedef { \
|
||||
private: \
|
||||
struct TrueType { int a[2]; }; \
|
||||
typedef int FalseType; \
|
||||
template <typename C> static TrueType has_typedef ( const typename C::typedef_name* ); \
|
||||
template <typename C> static FalseType has_typedef ( ... ); \
|
||||
public: \
|
||||
enum { value = sizeof(has_typedef<T>(nullptr)) == sizeof(TrueType) }; \
|
||||
}
|
||||
|
||||
namespace wren {
|
||||
} //namespace wren
|
|
@ -1,15 +0,0 @@
|
|||
include_files = [
|
||||
'callback_manager.hpp',
|
||||
'class_manager.hpp',
|
||||
'configuration.hpp',
|
||||
'def_configuration.hpp',
|
||||
'handle.hpp',
|
||||
'vm_fun.hpp',
|
||||
'vm.hpp',
|
||||
]
|
||||
|
||||
if not meson.is_subproject()
|
||||
install_headers(include_files)
|
||||
endif
|
||||
|
||||
subdir('detail')
|
|
@ -18,13 +18,9 @@
|
|||
#ifndef id170B0E6C34D14EBA9B92A35977BDBFB3
|
||||
#define id170B0E6C34D14EBA9B92A35977BDBFB3
|
||||
|
||||
//#define PRINTABLE_STRING_BT
|
||||
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
#if defined(PRINTABLE_STRING_BT)
|
||||
# include <iostream>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace dhandy {
|
||||
|
@ -32,10 +28,8 @@ namespace dhandy {
|
|||
template <std::size_t S, typename Ch=char>
|
||||
class string;
|
||||
|
||||
#if defined(PRINTABLE_STRING_BT)
|
||||
template <std::size_t S, typename Ch>
|
||||
std::basic_ostream<Ch>& operator<< ( std::basic_ostream<Ch>& parStream, const string<S, Ch>& parString );
|
||||
#endif
|
||||
|
||||
namespace implem {
|
||||
template <std::size_t S, typename Ch> constexpr bool eq (const string<S, Ch>& l, const string<S, Ch>& r);
|
||||
|
@ -43,17 +37,11 @@ namespace dhandy {
|
|||
|
||||
template <std::size_t S, typename Ch>
|
||||
class string {
|
||||
#if defined(PRINTABLE_STRING_BT)
|
||||
friend std::ostream& operator<< <>( std::ostream& parStream, const string<S>& parString );
|
||||
#endif
|
||||
friend constexpr bool implem::eq<S, Ch> (const string<S, Ch>&, const string<S, Ch>&);
|
||||
public:
|
||||
using value_type = Ch;
|
||||
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 string ( const value_type* parString );
|
||||
|
||||
constexpr std::size_t size ( void ) const { return S - 1; }
|
||||
template <std::size_t S2>
|
||||
|
@ -64,26 +52,18 @@ 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, Ch> && ...)
|
||||
constexpr string ( Args... );
|
||||
|
||||
constexpr const value_type (&data_arr() const)[S] { return m_data; }
|
||||
constexpr const value_type* data() const { return m_data; }
|
||||
|
||||
//can't have any private members but from below this point please
|
||||
//consider everything as private
|
||||
//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 ) {
|
||||
|
@ -105,21 +85,14 @@ namespace dhandy {
|
|||
}
|
||||
|
||||
template <std::size_t S, typename Ch>
|
||||
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) :
|
||||
inline constexpr string<S, Ch>::string (const value_type* parString) :
|
||||
string(std::make_index_sequence<S>(), parString)
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t S, typename Ch>
|
||||
template <typename... Args>
|
||||
requires (std::is_same_v<Args, Ch> && ...)
|
||||
constexpr inline string<S, Ch>::string (Args... parArgs) :
|
||||
inline constexpr string<S, Ch>::string (Args... parArgs) :
|
||||
m_data{parArgs...}
|
||||
{
|
||||
}
|
||||
|
@ -130,13 +103,21 @@ namespace dhandy {
|
|||
return implem::concat(std::make_index_sequence<S + S2 - 1>(), string<S>(m_data), parOther);
|
||||
}
|
||||
|
||||
#if defined(PRINTABLE_STRING_BT)
|
||||
template <std::size_t S, typename Ch>
|
||||
inline std::ostream& operator<< (std::ostream& parStream, const string<S, Ch>& parString) {
|
||||
parStream << parString.m_data;
|
||||
return parStream;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 {
|
||||
|
@ -146,7 +127,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), 0) + string<1, Ch>({Ch{}});
|
||||
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1)) + make_string("");
|
||||
}
|
||||
} //namespace bt
|
||||
} //namespace dhandy
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -17,11 +17,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "detail/has_method.hpp"
|
||||
#include "detail/error_type.hpp"
|
||||
#include "detail/type_id.hpp"
|
||||
#include "detail/wren_types.hpp"
|
||||
#include "has_method.hpp"
|
||||
#include "error_type.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "StringCRC32.hpp"
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
@ -35,23 +34,28 @@ namespace wren {
|
|||
class Configuration;
|
||||
class VM;
|
||||
class DynafuncMaker;
|
||||
class CallbackManager;
|
||||
class ClassManager;
|
||||
|
||||
typedef void(*foreign_method_t)(VM&);
|
||||
typedef void(*finalizer_t)(void*);
|
||||
|
||||
struct foreign_class_t {
|
||||
foreign_method_t allocate;
|
||||
finalizer_t finalize;
|
||||
};
|
||||
|
||||
enum class SlotType {
|
||||
Bool, Num, Foreign, List, Null, String, Unknown, Map
|
||||
Bool, Num, Foreign, List, Null, String, Unknown
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct Callbacks {
|
||||
void (*write_fn)(Configuration&, VM*, wren_string_t) {nullptr};
|
||||
void (*error_fn)(Configuration&, VM*, ErrorType, wren_string_t, int, wren_string_t) {nullptr};
|
||||
void (*write_fn)(Configuration&, VM*, const char*) {nullptr};
|
||||
void (*error_fn)(Configuration&, VM*, ErrorType, const char*, int, const char*) {nullptr};
|
||||
void* (*reallocate_fn)(void*, std::size_t) {nullptr};
|
||||
const char* (*resolve_module_fn)(Configuration&, VM*, wren_string_t, wren_string_t) {nullptr};
|
||||
char* (*load_module_fn)(Configuration&, VM*, wren_string_t) {nullptr};
|
||||
foreign_method_t (*foreign_method_fn)(Configuration&, VM*, wren_string_t, wren_string_t, bool, wren_string_t) {nullptr};
|
||||
foreign_class_t (*foreign_class_fn)(Configuration&, VM*, wren_string_t, wren_string_t) {nullptr};
|
||||
void (*load_module_complete_fn)(Configuration&, VM*, wren_string_t, char*) {nullptr};
|
||||
const char* (*resolve_module_fn)(Configuration&, VM*, const char*, const char*) {nullptr};
|
||||
char* (*load_module_fn)(Configuration&, VM*, const char*) {nullptr};
|
||||
foreign_method_t (*foreign_method_fn)(Configuration&, VM*, const char*, const char*, bool, const char*) {nullptr};
|
||||
foreign_class_t (*foreign_class_fn)(Configuration&, VM*, const char*, const char*) {nullptr};
|
||||
|
||||
Configuration* config_obj {nullptr};
|
||||
VM* owner {nullptr};
|
||||
|
@ -74,8 +78,7 @@ namespace wren {
|
|||
void release_handle (Handle& handle) noexcept;
|
||||
void ensure_slots(int num_slots);
|
||||
int slot_count();
|
||||
void variable(const char* module, const char* name, int slot) noexcept;
|
||||
void variable_or_throw(const char* module, const char* name, int slot);
|
||||
void variable(const char* module, const char* name, int slot);
|
||||
void set_slot_handle(const Handle& handle, int slot);
|
||||
SlotType slot_type(int slot_num);
|
||||
Handle slot_handle(int slot_num);
|
||||
|
@ -99,42 +102,32 @@ namespace wren {
|
|||
template <typename U> U* user_data();
|
||||
template <typename U> void set_user_data (U* user_data);
|
||||
void set_user_data (std::nullptr_t);
|
||||
bool has_user_data() const noexcept;
|
||||
bool has_module (const char* module) const noexcept;
|
||||
bool has_variable (const char* module, const char* name) const noexcept;
|
||||
|
||||
void abort_fiber(int slot_num);
|
||||
bool has_user_data() const;
|
||||
|
||||
std::size_t dynafunc_byte_size() const;
|
||||
void reset (Configuration* conf);
|
||||
|
||||
CallbackManager& callback_manager();
|
||||
const CallbackManager& callback_manager() const;
|
||||
ClassManager& class_manager();
|
||||
const ClassManager& class_manager() const;
|
||||
|
||||
private:
|
||||
struct LocalData;
|
||||
|
||||
VM (Configuration* conf, const detail::Callbacks&, void* user_data, TypeID user_data_type);
|
||||
VM (Configuration* conf, const detail::Callbacks&, void* user_data, std::uint32_t user_data_type);
|
||||
DynafuncMaker* dynafunc_maker();
|
||||
TypeID user_data_type() const;
|
||||
std::uint32_t user_data_type() const;
|
||||
void* void_user_data();
|
||||
void set_user_data (void* user_data, TypeID user_data_type);
|
||||
void set_user_data (void* user_data, std::uint32_t user_data_type);
|
||||
template <typename T> detail::Callbacks to_callbacks (T& conf);
|
||||
|
||||
std::unique_ptr<LocalData> m_local;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
define_method_info(write_fn, write, void, VM*, wren_string_t);
|
||||
define_method_info(error_fn, error, void, VM*, ErrorType, wren_string_t, int, wren_string_t);
|
||||
define_method_info(write_fn, write, void, VM*, const char*);
|
||||
define_method_info(error_fn, error, void, VM*, ErrorType, const char*, int, const char*);
|
||||
define_method_info(reallocate_fn, reallocate, void*, void*, std::size_t);
|
||||
define_method_info(resolve_module_fn, resolve_module, wren_string_t, wren_string_t, wren_string_t);
|
||||
define_method_info(load_module_fn, load_module, char*, VM*, wren_string_t);
|
||||
define_method_info(foreign_method_fn, foreign_method, foreign_method_t, VM*, wren_string_t, wren_string_t, bool, wren_string_t);
|
||||
define_method_info(foreign_class_fn, foreign_class, foreign_class_t, VM*, wren_string_t, wren_string_t);
|
||||
define_method_info(load_module_complete_fn, load_module_complete, void, VM*, wren_string_t, char*);
|
||||
define_method_info(resolve_module_fn, resolve_module, const char*, const char*, const char*);
|
||||
define_method_info(load_module_fn, load_module, char*, VM*, const char*);
|
||||
define_method_info(foreign_method_fn, foreign_method, foreign_method_t, VM*, const char*, const char*, bool, const char*);
|
||||
define_method_info(foreign_class_fn, foreign_class, foreign_class_t, VM*, const char*, const char*);
|
||||
|
||||
template <typename T, typename F> struct AnyFunctionWrap;
|
||||
template <typename T, typename R, typename... Args>
|
||||
|
@ -151,6 +144,12 @@ namespace wren {
|
|||
return (*M)(args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
[[gnu::const]]
|
||||
inline constexpr std::uint32_t type_id() {
|
||||
return duckcore::StringCRC32(__PRETTY_FUNCTION__);
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
template <typename T>
|
||||
|
@ -184,15 +183,12 @@ namespace wren {
|
|||
if constexpr (detail::method_foreign_class::exists<T>::value)
|
||||
ret.foreign_class_fn = &detail::AnyFunctionWrap<T, decltype(&T::foreign_class_fn)>::template call<&T::foreign_class_fn>;
|
||||
|
||||
if constexpr (detail::method_load_module_complete::exists<T>::value)
|
||||
ret.load_module_complete_fn = &detail::AnyFunctionWrap<T, decltype(&T::load_module_complete_fn)>::template call<&T::load_module_complete_fn>;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
inline U* VM::user_data() {
|
||||
if (user_data_type() != type_id<U>()) {
|
||||
if (user_data_type() != detail::type_id<U>()) {
|
||||
throw std::runtime_error("Wrong user data type requested");
|
||||
}
|
||||
return reinterpret_cast<U*>(void_user_data());
|
||||
|
@ -200,7 +196,7 @@ namespace wren {
|
|||
|
||||
template <typename U>
|
||||
inline void VM::set_user_data (U* user_data) {
|
||||
set_user_data(reinterpret_cast<void*>(user_data), type_id<U>());
|
||||
set_user_data(reinterpret_cast<void*>(user_data), detail::type_id<U>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -209,7 +205,7 @@ namespace wren {
|
|||
static_cast<Configuration*>(conf),
|
||||
to_callbacks(*conf),
|
||||
nullptr,
|
||||
type_id<std::nullptr_t>()
|
||||
detail::type_id<std::nullptr_t>()
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -220,7 +216,7 @@ namespace wren {
|
|||
static_cast<Configuration*>(conf),
|
||||
to_callbacks(*conf),
|
||||
reinterpret_cast<void*>(user_data),
|
||||
type_id<U>()
|
||||
detail::type_id<U>()
|
||||
)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2024, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -18,165 +18,234 @@
|
|||
#pragma once
|
||||
|
||||
#include "vm.hpp"
|
||||
#include "detail/string_bt.hpp"
|
||||
#if defined(WRENPP_WITH_NAME_GUESSING)
|
||||
# include "detail/guess_class_name.hpp"
|
||||
#endif
|
||||
#include "detail/wren_types.hpp"
|
||||
#include "detail/construct_foreign_class.hpp"
|
||||
#include "detail/setters_getters.hpp"
|
||||
#include "detail/wren_class_name_from_type.hpp"
|
||||
#include "detail/is_kindof_handle.hpp"
|
||||
#include "detail/foreign_object.hpp"
|
||||
#include "string_bt.hpp"
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace wren {
|
||||
typedef std::tuple<const char*, const char*> ModuleAndName;
|
||||
|
||||
namespace detail {
|
||||
template <typename T> struct GetTypeToRetType;
|
||||
template <typename T> using GetTypeToRetType_t = typename GetTypeToRetType<T>::type;
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename T>
|
||||
concept ConstCharTuple = requires {
|
||||
std::same_as<std::remove_cv_t<T>, Handle> or
|
||||
std::same_as<std::remove_cv_t<T>, ModuleAndName>;
|
||||
};
|
||||
#endif
|
||||
} //namespace detail
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename... Outs, detail::ConstCharTuple... Params>
|
||||
#else
|
||||
template <typename... Outs, typename... Params>
|
||||
#endif
|
||||
std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names);
|
||||
|
||||
template <typename R, typename... Args>
|
||||
R call (VM& vm, const Handle& object, const Handle& method, const Args&... args);
|
||||
|
||||
template <typename R, typename... Args>
|
||||
R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args);
|
||||
R call (VM& vm, const 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, ModuleAndName object, const char (&method)[N], const Args&... args);
|
||||
R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args);
|
||||
|
||||
template <typename T, typename... Args>
|
||||
ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
|
||||
template <typename T>
|
||||
foreign_class_t make_foreign_class();
|
||||
|
||||
#if defined(WRENPP_WITH_NAME_GUESSING)
|
||||
template <typename T, dhandy::bt::string Mod, typename... Args>
|
||||
ForeignObject<T> make_wren_object(VM& vm, Args&&... args);
|
||||
#endif
|
||||
template <auto V>
|
||||
foreign_method_t make_method_bindable();
|
||||
|
||||
void interpret (VM& vm, const std::string& module_name, const std::string& script);
|
||||
void variable(VM& vm, ModuleAndName mod_and_name, int slot);
|
||||
void set (VM& vm, int slot_num, const char* value);
|
||||
void set (VM& vm, int slot_num, double value);
|
||||
void set (VM& vm, int slot_num, bool value);
|
||||
void set (VM& vm, int slot_num, std::nullptr_t);
|
||||
void set (VM& vm, int slot_num, const char* bytes, std::size_t length);
|
||||
void set (VM& vm, int slot_num, const std::string& value);
|
||||
void set (VM& vm, int slot_num, std::string_view value);
|
||||
void set (VM& vm, int slot_num, const std::vector<char>& value);
|
||||
void set (VM& vm, int slot_num, const char* beg, const char* end);
|
||||
void set (VM& vm, int slot_num, int value);
|
||||
void set (VM& vm, int slot_num, std::size_t value);
|
||||
std::string_view slot_string_view (VM& vm, int slot_num);
|
||||
template <typename T> detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num);
|
||||
template <typename T> T* foreign (VM& vm, int slot_num);
|
||||
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot);
|
||||
void variable(VM& vm, const Handle& handle, 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);
|
||||
void abort_fiber_with_error (VM& vm, int slot, std::string_view message);
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct CleanParamForGet { typedef typename std::decay<T>::type type; };
|
||||
template <typename T>
|
||||
struct CleanParamForGet<ForeignObject<T>> { typedef T type; };
|
||||
template <typename T>
|
||||
using CleanParamForGetT = typename CleanParamForGet<T>::type;
|
||||
template <typename T> struct TType { typedef T type; };
|
||||
|
||||
template<typename T>struct GetTypeToRetType{
|
||||
static_assert(not std::is_fundamental_v<T>, "User type expected");
|
||||
static_assert(not std::is_pointer_v<T>, "Unexpected pointer type");
|
||||
typedef std::remove_cv_t<T>* type;
|
||||
};
|
||||
template<>struct GetTypeToRetType<const char*> : TType<const char*>{};
|
||||
template<>struct GetTypeToRetType<double> : TType<double>{};
|
||||
template<>struct GetTypeToRetType<bool> : TType<bool>{};
|
||||
template<>struct GetTypeToRetType<std::pair<const char*,int>> : TType<std::pair<const char*,int>> {};
|
||||
template<>struct GetTypeToRetType<int> : TType<int>{};
|
||||
template<>struct GetTypeToRetType<std::size_t> : TType<std::size_t>{};
|
||||
template<>struct GetTypeToRetType<std::string> : TType<std::string>{};
|
||||
template<>struct GetTypeToRetType<std::string_view> : TType<std::string_view>{};
|
||||
template<>struct GetTypeToRetType<std::vector<char>> : TType<std::vector<char>>{};
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename... Outs, int... Indices, ConstCharTuple... Params>
|
||||
#else
|
||||
template <typename... Outs, int... Indices, typename... Params>
|
||||
#endif
|
||||
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables_impl (
|
||||
VM& vm,
|
||||
std::integer_sequence<int, Indices...>,
|
||||
Params&&... modules_names
|
||||
) {
|
||||
if constexpr (sizeof...(Outs) == 0) {
|
||||
return {};
|
||||
}
|
||||
else {
|
||||
static_assert(sizeof...(Params) == sizeof...(Outs), "Expected a module/name pair per requested output");
|
||||
static_assert(sizeof...(Outs) == sizeof...(Indices), "Mismatching index count");
|
||||
|
||||
vm.ensure_slots(sizeof...(Params));
|
||||
(variable(vm, modules_names, Indices), ...);
|
||||
return std::tuple<detail::GetTypeToRetType_t<Outs>...>(get<Outs>(vm, Indices)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void set_single_for_call (VM& vm, int slot, const T& value) {
|
||||
set(vm, slot, value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void set_single_for_call (VM& vm, int slot_num, const Handle& handle) {
|
||||
vm.set_slot_handle(handle, slot_num);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void set_single_for_call (VM& vm, int slot_num, const ModuleAndName& name) {
|
||||
variable(vm, name, slot_num);
|
||||
}
|
||||
|
||||
//Sets arguments so wren is ready to perform a function call. It doesn't
|
||||
//touch at slot 0, so eventual objects for method calls must be set
|
||||
//manually
|
||||
template <typename... Args, int... Indices>
|
||||
inline void set_for_call (std::integer_sequence<int, Indices...>, VM& vm, const Args&... args) {
|
||||
vm.ensure_slots(sizeof...(Args));
|
||||
(set(vm, Indices + 1, args), ...);
|
||||
(set_single_for_call(vm, Indices + 1, args), ...);
|
||||
}
|
||||
|
||||
template <auto V>
|
||||
class CallImplemProvider;
|
||||
template <typename T, typename R, typename... Args, R(T::*Method)(Args...)>
|
||||
class CallImplemProvider<Method> {
|
||||
protected:
|
||||
typedef R return_type;
|
||||
static constexpr std::size_t argument_count = sizeof...(Args);
|
||||
|
||||
template <typename T, typename R, auto Method, typename... Args> struct MakeMethodBindableConstNonConst {
|
||||
private:
|
||||
template <int... Indices>
|
||||
static R call_implem (std::integer_sequence<int, Indices...>, VM& vm) {
|
||||
static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count");
|
||||
T* const obj = foreign<T>(vm, 0);
|
||||
return (obj->*Method)(get<CleanParamForGetT<Args>>(vm, Indices + 1)...);
|
||||
T* obj = foreign<T>(vm, 0);
|
||||
return (obj->*Method)(get<std::decay_t<Args>>(vm, Indices + 1)...);
|
||||
}
|
||||
};
|
||||
template <typename T, typename R, typename... Args, R(T::*ConstMethod)(Args...)const>
|
||||
class CallImplemProvider<ConstMethod> {
|
||||
protected:
|
||||
typedef R return_type;
|
||||
static constexpr std::size_t argument_count = sizeof...(Args);
|
||||
|
||||
template <int... Indices>
|
||||
static R call_implem (std::integer_sequence<int, Indices...>, VM& vm) {
|
||||
static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count");
|
||||
T* const obj = foreign<T>(vm, 0);
|
||||
return (obj->*ConstMethod)(get<CleanParamForGetT<Args>>(vm, Indices + 1)...);
|
||||
}
|
||||
};
|
||||
template <typename R, typename... Args, R(*Function)(Args...)>
|
||||
class CallImplemProvider<Function> {
|
||||
protected:
|
||||
typedef R return_type;
|
||||
static constexpr std::size_t argument_count = sizeof...(Args);
|
||||
|
||||
template <int... Indices>
|
||||
static R call_implem (std::integer_sequence<int, Indices...>, VM& vm) {
|
||||
static_assert(sizeof...(Indices) == sizeof...(Args), "Mismatching argument count");
|
||||
return (*Function)(get<CleanParamForGetT<Args>>(vm, Indices + 1)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <auto V>
|
||||
struct MakeFunctionBindable : private CallImplemProvider<V> {
|
||||
foreign_method_t operator()() const {
|
||||
using R = typename CallImplemProvider<V>::return_type;
|
||||
constexpr int argument_count = static_cast<int>(CallImplemProvider<V>::argument_count);
|
||||
|
||||
return [](VM& vm, ModuleAndName mn) {
|
||||
public:
|
||||
static foreign_method_t make() {
|
||||
return [](VM& vm) {
|
||||
if constexpr (std::is_same_v<R, void>) {
|
||||
CallImplemProvider<V>::call_implem(std::make_integer_sequence<int, argument_count>(), vm);
|
||||
call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
|
||||
}
|
||||
else {
|
||||
auto ret = CallImplemProvider<V>::call_implem(std::make_integer_sequence<int, argument_count>(), vm);
|
||||
//TODO: check for errors
|
||||
assert(vm.slot_count() >= 1); //vm.ensure_slots(1);
|
||||
if constexpr (std::is_fundamental<R>::value) {
|
||||
set(vm, 0, ret);
|
||||
}
|
||||
else if constexpr (IsKindOfHandle<R>::value) {
|
||||
IsKindOfHandle<R>::set_to_slot(0, ret);
|
||||
assert(vm.slot_type(0) == SlotType::Foreign);
|
||||
}
|
||||
else {
|
||||
ModuleAndName wren_name = wren_class_name_from_type<R>(vm);
|
||||
ForeignObject<R> new_object = make_wren_object<R>(vm, wren_name, std::move(ret));
|
||||
static_cast<void>(new_object);
|
||||
}
|
||||
auto ret = call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
|
||||
vm.ensure_slots(1);
|
||||
set(vm, 0, ret);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, void(T::*Method)(VM&,ModuleAndName)> struct MakeFunctionBindable<Method> {
|
||||
foreign_method_t operator()() const {
|
||||
return [](VM& vm, ModuleAndName mn) {
|
||||
template <auto V> struct MakeMethodBindable;
|
||||
template <typename T, void(T::*Method)(VM&)> struct MakeMethodBindable<Method> {
|
||||
static foreign_method_t make() {
|
||||
return [](VM& vm) {
|
||||
T* obj = foreign<T>(vm, 0);
|
||||
(obj->*Method)(vm, mn);
|
||||
(obj->*Method)(vm);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <void(*Function)(VM&,ModuleAndName)> struct MakeFunctionBindable<Function> {
|
||||
foreign_method_t operator()() const {
|
||||
return [](VM& vm, ModuleAndName mn) {
|
||||
(*Function)(vm, mn);
|
||||
};
|
||||
}
|
||||
};
|
||||
template <typename T, typename R, typename... Args, R(T::*Method)(Args...)> struct MakeMethodBindable<Method> : MakeMethodBindableConstNonConst<T, R, Method, Args...> {};
|
||||
template <typename T, typename R, typename... Args, R(T::*Method)(Args...)const> struct MakeMethodBindable<Method> : MakeMethodBindableConstNonConst<T, R, Method, Args...> {};
|
||||
} //namespace detail
|
||||
|
||||
#if __cpp_concepts >= 201907
|
||||
template <typename... Outs, detail::ConstCharTuple... Params>
|
||||
#else
|
||||
template <typename... Outs, typename... Params>
|
||||
#endif
|
||||
inline std::tuple<detail::GetTypeToRetType_t<Outs>...> variables(VM& vm, Params&&... modules_names) {
|
||||
return detail::variables_impl<Outs...>(vm, std::make_integer_sequence<int, sizeof...(Outs)>(), std::forward<Params>(modules_names)...);
|
||||
}
|
||||
|
||||
inline void interpret (VM& vm, const std::string& module_name, const std::string& script) {
|
||||
return vm.interpret(module_name.c_str(), script.c_str());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const char* value) {
|
||||
vm.set_slot_string(slot_num, value);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, double value) {
|
||||
vm.set_slot_double(slot_num, value);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, bool value) {
|
||||
vm.set_slot_bool(slot_num, value);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, std::nullptr_t) {
|
||||
vm.set_slot_null(slot_num);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const char* bytes, std::size_t length) {
|
||||
vm.set_slot_bytes(slot_num, bytes, length);
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const std::string& value) {
|
||||
vm.set_slot_string(slot_num, value.c_str());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, std::string_view value) {
|
||||
vm.set_slot_bytes(slot_num, value.data(), value.size());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, const std::vector<char>& value) {
|
||||
vm.set_slot_bytes(slot_num, value.data(), value.size());
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, int value) {
|
||||
vm.set_slot_double(slot_num, static_cast<double>(value));
|
||||
}
|
||||
|
||||
inline void set (VM& vm, int slot_num, std::size_t value) {
|
||||
vm.set_slot_double(slot_num, static_cast<double>(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* foreign (VM& vm, int slot_num) {
|
||||
T* obj = static_cast<T*>(vm.slot_foreign(slot_num));
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <typename R, typename... Args>
|
||||
inline R call (VM& vm, const Handle& object, const Handle& method, const Args&... args) {
|
||||
detail::set_for_call<Args...>(std::make_integer_sequence<int, sizeof...(Args)>(), vm, args...);
|
||||
vm.set_slot_handle(object, 0);
|
||||
vm.call(method);
|
||||
if constexpr (not std::is_same<void, R>::value) {
|
||||
return get<R>(vm, 0);
|
||||
|
@ -184,7 +253,7 @@ namespace wren {
|
|||
}
|
||||
|
||||
template <typename R, typename... Args>
|
||||
inline R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args) {
|
||||
inline R call (VM& vm, const 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);
|
||||
|
@ -193,51 +262,58 @@ 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 auto params = string("(") +
|
||||
((static_cast<void>(args), string(",_")) + ... + string("")).template substr<1>() +
|
||||
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(")");
|
||||
;
|
||||
char cat_buff[params.size() + 1 + N - 1];
|
||||
char cat_buff[params.size() + 1];
|
||||
std::copy(method, method + N - 1, cat_buff);
|
||||
std::copy(params.data(), params.data() + params.size() + 1, cat_buff + N - 1);
|
||||
std::copy(params.data() + N - 1, params.data() + params.size() + 1, cat_buff + N - 1);
|
||||
return call<R, Args...>(vm, object, vm.make_call_handle(cat_buff), args...);
|
||||
}
|
||||
|
||||
template <typename R, std::size_t N, typename... Args>
|
||||
inline R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args) {
|
||||
inline R call (VM& vm, const 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);
|
||||
return call<R, N, Args...>(vm, obj_handle, method, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
|
||||
variable_ensure_slot(vm, mn, 0);
|
||||
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
|
||||
try {
|
||||
T* const obj = new(mem) T{std::forward<Args>(args)...};
|
||||
return {obj, vm.slot_handle(0)};
|
||||
}
|
||||
catch (const std::runtime_error& err) {
|
||||
abort_fiber_with_error(vm, 1, err.what());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
inline foreign_class_t make_foreign_class() {
|
||||
foreign_class_t ret;
|
||||
ret.allocate = [](VM& vm) {
|
||||
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
|
||||
new(mem) T;
|
||||
};
|
||||
ret.finalize = [](void* mem) {
|
||||
const auto cale = static_cast<T*>(mem);
|
||||
cale->~T();
|
||||
};
|
||||
|
||||
#if defined(WRENPP_WITH_NAME_GUESSING)
|
||||
template <typename T, dhandy::bt::string Mod, typename... Args>
|
||||
inline ForeignObject<T> make_wren_object(VM& vm, Args&&... args) {
|
||||
return make_wren_object<T>(
|
||||
vm,
|
||||
MN<Mod, g_guessed_class_name<T>>,
|
||||
std::forward<Args>(args)...
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <auto V>
|
||||
constexpr detail::MakeFunctionBindable<V> make_function_bindable;
|
||||
inline foreign_method_t make_method_bindable() {
|
||||
return detail::MakeMethodBindable<V>::make();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num) {
|
||||
return foreign<T>(vm, slot_num);
|
||||
}
|
||||
|
||||
template<> const char* get<const char*> (VM& vm, int slot_num);
|
||||
template <> double get<double> (VM& vm, int slot_num);
|
||||
template <> bool get<bool> (VM& vm, int slot_num);
|
||||
template <> std::pair<const char*, int> get<std::pair<const char*,int>> (VM& vm, int slot_num);
|
||||
template<> int get<int> (VM& vm, int slot_num);
|
||||
template<> std::size_t get<std::size_t> (VM& vm, int slot_num);
|
||||
template<> std::string get<std::string> (VM& vm, int slot_num);
|
||||
template <> std::string_view get<std::string_view> (VM& vm, int slot_num);
|
||||
template <> std::vector<char> get<std::vector<char>> (VM& vm, int slot_num);
|
||||
} //namespace wren
|
||||
|
|
8
links.txt
Normal file
8
links.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
https://stackoverflow.com/questions/36093158/how-does-string-conversion-between-pyunicode-string-and-c-string-work
|
||||
https://stackoverflow.com/questions/8001923/python-extension-module-with-variable-number-of-arguments
|
||||
https://stackoverflow.com/questions/27451743/how-can-i-print-the-type-of-a-pyobject-in-an-error-message-for-an-embedded-pytho/27452057
|
||||
|
||||
https://docs.python.org/3.8/c-api/unicode.html#creating-and-accessing-unicode-strings
|
||||
https://docs.python.org/3/extending/extending.html
|
||||
|
||||
https://stackoverflow.com/questions/28263177/should-tp-alloc-tp-dealloc-and-tp-new-tp-free-be-considered-as-pairs
|
61
meson.build
61
meson.build
|
@ -1,9 +1,11 @@
|
|||
project('wrenpp', 'cpp',
|
||||
version: '0.2.0',
|
||||
meson_version: '>=0.55.0',
|
||||
default_options: ['buildtype=release', 'cpp_std=c++20', 'b_ndebug=if-release']
|
||||
version: '0.1.1',
|
||||
meson_version: '>=0.49.2',
|
||||
default_options: ['buildtype=release', 'cpp_std=c++17', 'b_ndebug=if-release'],
|
||||
)
|
||||
|
||||
pymod = import('python')
|
||||
|
||||
wren_dep = dependency('wren', version: '>=0.2.0',
|
||||
fallback: ['wren', 'wren_dep'],
|
||||
default_options: [
|
||||
|
@ -14,7 +16,11 @@ wren_dep = dependency('wren', version: '>=0.2.0',
|
|||
],
|
||||
static: true,
|
||||
)
|
||||
public_incl = [include_directories('include')]
|
||||
python = pymod.find_installation('python3',
|
||||
required: get_option('wrenpp_with_python'),
|
||||
disabler: true
|
||||
)
|
||||
public_incl = include_directories('include')
|
||||
|
||||
os = host_machine.system()
|
||||
if os == 'gnu'
|
||||
|
@ -35,22 +41,49 @@ conf = configuration_data()
|
|||
if os == 'gnu' and arch == 'amd64'
|
||||
ptr_size = 8
|
||||
func_ptr_size = 8
|
||||
elif os == 'gnu' and arch == 'aarch64'
|
||||
ptr_size = 8
|
||||
func_ptr_size = 8
|
||||
endif
|
||||
|
||||
global_compiler_opts = []
|
||||
if get_option('wrenpp_with_name_guessing')
|
||||
global_compiler_opts += ['-DWRENPP_WITH_NAME_GUESSING']
|
||||
endif
|
||||
|
||||
conf.set('POINTER_SIZE', ptr_size)
|
||||
conf.set('FUNC_POINTER_SIZE', func_ptr_size)
|
||||
conf.set('WRENPP_NAME', meson.project_name())
|
||||
|
||||
subdir('include')
|
||||
subdir('src')
|
||||
project_config_file = configure_file(
|
||||
input: 'src/config.h.in',
|
||||
output: 'config.h',
|
||||
configuration: conf
|
||||
)
|
||||
|
||||
wrenpp = library(meson.project_name(),
|
||||
project_config_file,
|
||||
'src/vm.cpp',
|
||||
'src/configuration.cpp',
|
||||
'src/def_configuration.cpp',
|
||||
'src/dynafunc_maker.cpp',
|
||||
'src/dynafunc_' + arch + '_' + os + '.S',
|
||||
'src/handle.cpp',
|
||||
'src/vm_fun.cpp',
|
||||
dependencies: [wren_dep],
|
||||
include_directories: public_incl,
|
||||
install: true,
|
||||
)
|
||||
wrenpp_dep = declare_dependency(
|
||||
link_with: wrenpp,
|
||||
include_directories: public_incl,
|
||||
)
|
||||
|
||||
python.extension_module('py' + meson.project_name(),
|
||||
sources: [
|
||||
'src/pywrenppmodule.cpp',
|
||||
],
|
||||
dependencies: [
|
||||
python.dependency(
|
||||
version: '>=3.6.0',
|
||||
required: get_option('wrenpp_with_python'),
|
||||
),
|
||||
wrenpp_dep,
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
||||
if get_option('build_examples')
|
||||
subdir('examples')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
option('build_testing', type: 'boolean', value: false)
|
||||
option('build_examples', type: 'boolean', value: false)
|
||||
option('wren_with_rand', type: 'boolean', value: false)
|
||||
option('wren_with_meta', type: 'boolean', value: false)
|
||||
option('wrenpp_with_name_guessing', type: 'boolean', value: true)
|
||||
option('wren_with_rand', type: 'boolean', value: false, yield: true)
|
||||
option('wren_with_meta', type: 'boolean', value: false, yield: true)
|
||||
option('wrenpp_with_python', type: 'feature', value: 'disabled')
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace wren::detail {
|
||||
FullSignatureOwning::FullSignatureOwning (std::string_view module_name, std::string_view class_name, std::string_view signature) :
|
||||
FullSignatureBase(std::hash<std::string_view>{}(module_name), std::hash<std::string_view>{}(class_name), std::hash<std::string_view>{}(signature)),
|
||||
StringsInVector<3>(module_name, class_name, signature)
|
||||
{
|
||||
}
|
||||
|
||||
TempFullSignature::TempFullSignature (const FullSignatureOwning& full_sig) :
|
||||
FullSignatureBase(full_sig),
|
||||
m_module_name(full_sig.module_name()),
|
||||
m_class_name(full_sig.class_name()),
|
||||
m_signature(full_sig.signature())
|
||||
{ }
|
||||
|
||||
TempFullSignature::TempFullSignature (std::string_view module_name, std::string_view class_name, std::string_view signature) :
|
||||
FullSignatureBase(std::hash<std::string_view>{}(module_name), std::hash<std::string_view>{}(class_name), std::hash<std::string_view>{}(signature)),
|
||||
m_module_name(module_name),
|
||||
m_class_name(class_name),
|
||||
m_signature(signature)
|
||||
{ }
|
||||
|
||||
bool FullSignatureEqual::operator()(TempFullSignature left, TempFullSignature right) const {
|
||||
return left.class_name() == right.class_name() and
|
||||
left.module_name() == right.module_name() and
|
||||
left.signature() == right.signature();
|
||||
}
|
||||
|
||||
std::size_t FullSignatureHash::operator() (TempFullSignature key) const {
|
||||
//see example at https://en.cppreference.com/w/cpp/utility/hash
|
||||
const std::size_t h1 = key.module_hash();
|
||||
const std::size_t h2 = key.class_hash();
|
||||
const std::size_t h3 = key.signature_hash();
|
||||
return h1 ^ ((h2 ^ (h3 << 1)) << 1);
|
||||
}
|
||||
} //namespace wren::detail
|
||||
|
||||
namespace wren {
|
||||
CallbackManager::CallbackManager() = default;
|
||||
CallbackManager::~CallbackManager() noexcept = default;
|
||||
|
||||
CallbackManager& CallbackManager::add_callback (
|
||||
bool is_static,
|
||||
std::string_view module_name,
|
||||
std::string_view class_name,
|
||||
std::string_view signature,
|
||||
std::function<foreign_method_t()> make_cb
|
||||
) {
|
||||
using detail::FullSignatureOwning;
|
||||
using detail::TempFullSignature;
|
||||
|
||||
MethodMap& map = *method_map(is_static);
|
||||
auto it_found = map.find(TempFullSignature{module_name, class_name, signature});
|
||||
if (map.cend() == it_found)
|
||||
map.insert(it_found, std::make_pair(FullSignatureOwning{module_name, class_name, signature}, make_cb()));
|
||||
else
|
||||
it_found->second = make_cb();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
foreign_method_t CallbackManager::callback (bool is_static, std::string_view module_name, std::string_view class_name, std::string_view signature) const {
|
||||
using detail::TempFullSignature;
|
||||
|
||||
const MethodMap* const map = method_map(is_static);
|
||||
const auto it_found = map->find(TempFullSignature{module_name, class_name, signature});
|
||||
if (map->cend() != it_found)
|
||||
return it_found->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto CallbackManager::method_map(bool is_static) noexcept -> MethodMap* {
|
||||
return (is_static ? &m_static_methods : &m_normal_methods);
|
||||
}
|
||||
|
||||
auto CallbackManager::method_map(bool is_static) const noexcept -> const MethodMap* {
|
||||
return const_cast<CallbackManager*>(this)->method_map(is_static);
|
||||
}
|
||||
} //namespace wren
|
|
@ -1,147 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
#include <cassert>
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
ClassNameBase::ClassNameBase (const std::string_view& module_name, const std::string_view& class_name) :
|
||||
m_module_hash(std::hash<std::string_view>{}(module_name)),
|
||||
m_class_name_hash(std::hash<std::string_view>{}(class_name))
|
||||
{
|
||||
}
|
||||
|
||||
bool ClassNameBase::operator==(const ClassNameBase& other) const {
|
||||
return m_module_hash == other.m_module_hash and
|
||||
m_class_name_hash == other.m_class_name_hash;
|
||||
}
|
||||
|
||||
ClassNameOwning::ClassNameOwning(const std::string_view& module_name, const std::string_view& class_name) :
|
||||
StringsInVector<2>(module_name, class_name),
|
||||
ClassNameBase(module_name, class_name)
|
||||
{
|
||||
}
|
||||
|
||||
ClassNameOwning::operator ModuleAndName() const {
|
||||
return ModuleAndName{
|
||||
this->raw_buffer(),
|
||||
this->module_name().size(),
|
||||
this->class_name().size()
|
||||
};
|
||||
}
|
||||
|
||||
bool ClassNameOwning::operator== (const ClassNameOwning& other) const {
|
||||
return
|
||||
*static_cast<const ClassNameBase*>(this) == static_cast<const ClassNameBase&>(other) or
|
||||
*static_cast<const StringsInVector<2>*>(this) == static_cast<const StringsInVector<2>&>(other);
|
||||
}
|
||||
|
||||
TempClassName::TempClassName(std::string_view module_name, std::string_view class_name) :
|
||||
ClassNameBase(module_name, class_name),
|
||||
m_module_name(module_name),
|
||||
m_class_name(class_name)
|
||||
{
|
||||
}
|
||||
|
||||
TempClassName::TempClassName (const ClassNameOwning& other) :
|
||||
ClassNameBase(other),
|
||||
m_module_name(other.module_name()),
|
||||
m_class_name(other.class_name())
|
||||
{
|
||||
}
|
||||
|
||||
bool TempClassName::operator== (const TempClassName& other) const {
|
||||
return *static_cast<const ClassNameBase*>(this) == static_cast<const ClassNameBase&>(other) and
|
||||
m_module_name == other.m_module_name and
|
||||
m_class_name == other.m_class_name;
|
||||
}
|
||||
|
||||
bool ClassNameEqual::operator()(TempClassName left, TempClassName right) const {
|
||||
return left == right;
|
||||
}
|
||||
|
||||
std::size_t ClassNameHash::operator()(TempClassName value) const {
|
||||
return value.module_hash() ^ (value.class_hash() << 1);
|
||||
}
|
||||
|
||||
std::size_t TypeIDHash::operator()(TypeID tid) const {
|
||||
if constexpr (sizeof(tid.id()) > sizeof(std::size_t)) {
|
||||
return std::hash<decltype(tid.id())>{}(tid.id());
|
||||
}
|
||||
else {
|
||||
return static_cast<std::size_t>(tid.id());
|
||||
}
|
||||
}
|
||||
} //namespace detail
|
||||
|
||||
ClassManager::ClassManager() = default;
|
||||
ClassManager::~ClassManager() noexcept = default;
|
||||
|
||||
foreign_class_t ClassManager::make_class (std::string_view module_name, std::string_view class_name) {
|
||||
using detail::TempClassName;
|
||||
|
||||
auto it_found = m_classes.find(TempClassName{module_name, class_name});
|
||||
if (m_classes.cend() != it_found)
|
||||
return it_found->second();
|
||||
else
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
auto ClassManager::add_class_maker_implem (
|
||||
std::string_view module_name,
|
||||
std::string_view class_name,
|
||||
make_foreign_class_t maker
|
||||
) -> ClassMap::const_iterator {
|
||||
using detail::TempClassName;
|
||||
using detail::ClassNameOwning;
|
||||
|
||||
auto it_found = m_classes.find(TempClassName{module_name, class_name});
|
||||
ClassMap::const_iterator retval;
|
||||
if (m_classes.cend() == it_found) {
|
||||
retval = m_classes.insert(
|
||||
it_found,
|
||||
std::make_pair(ClassNameOwning{module_name, class_name}, maker)
|
||||
);
|
||||
}
|
||||
else {
|
||||
it_found->second = maker;
|
||||
retval = it_found;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ClassManager::add_type (TypeID hash, const detail::ClassNameOwning* name) {
|
||||
using detail::TempClassName;
|
||||
|
||||
assert(m_types.count(hash) == 0 or *m_types.at(hash) == *name);
|
||||
//insert if not present, leave old value if hash is already there
|
||||
m_types.insert(std::make_pair(hash, name));
|
||||
}
|
||||
|
||||
ModuleAndName ClassManager::wren_class_name_from_hash(TypeID hash) const {
|
||||
const auto it_found = m_types.find(hash);
|
||||
if (m_types.cend() != it_found) {
|
||||
const detail::ClassNameOwning* const name = it_found->second;
|
||||
return *name;
|
||||
}
|
||||
else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
} //namespace wren
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/detail/crc32.hpp"
|
||||
#include "crc32_config.h"
|
||||
|
||||
namespace wren::detail {
|
||||
#if HAVE_NEON
|
||||
[[gnu::const]] bool has_crc32_neon() noexcept;
|
||||
[[gnu::pure]] std::uint32_t crc32c_neon(const char*, std::size_t, std::uint32_t) noexcept;
|
||||
#endif
|
||||
#if HAVE_SSE42
|
||||
[[gnu::const]] bool has_crc32_sse42() noexcept;
|
||||
[[gnu::pure]] std::uint32_t crc32c_sse42(const char*, std::size_t, std::uint32_t) noexcept;
|
||||
#endif
|
||||
} //namespace wren::detail
|
||||
|
||||
namespace wren::detail {
|
||||
//Some useful polynomials:
|
||||
// zlib: 0x04C11DB7
|
||||
// castagnoli (intel): 0x1EDC6F41
|
||||
|
||||
namespace {
|
||||
[[gnu::const]]
|
||||
auto best_crc32_function() {
|
||||
#if HAVE_NEON
|
||||
if (has_crc32_neon())
|
||||
return &crc32c_neon;
|
||||
#endif
|
||||
|
||||
#if HAVE_SSE42
|
||||
if (has_crc32_sse42())
|
||||
return &crc32c_sse42;
|
||||
#endif
|
||||
|
||||
return &crc32<detail::g_castagnoli_polynomial>;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
[[gnu::const]]
|
||||
std::uint32_t runtime_crc32c (const char* data, std::size_t size, std::uint32_t crc) {
|
||||
static const auto crc32c_implem = best_crc32_function();
|
||||
return (*crc32c_implem)(data, size, crc);
|
||||
}
|
||||
} //namespace wren::detail
|
|
@ -1,104 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#include <cstdint>
|
||||
|
||||
// Byte-boundary alignment issues
|
||||
#define CALC_CRC(op, crc, type, buf, len) \
|
||||
do { \
|
||||
for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
|
||||
(crc) = op((crc), *(type *) (buf)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
namespace wren::detail {
|
||||
//King_DuckZ - adapted from
|
||||
//https://github.com/rurban/smhasher/blob/master/sse2neon.h
|
||||
namespace {
|
||||
[[gnu::always_inline]] [[gnu::const]]
|
||||
inline std::uint32_t neon_crc32cb(std::uint32_t crc, std::uint8_t v) {
|
||||
__asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t"
|
||||
: [c] "+r"(crc)
|
||||
: [v] "r"(v));
|
||||
return crc;
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] [[gnu::const]]
|
||||
inline std::uint32_t neon_crc32ch (std::uint32_t crc, std::uint16_t v) {
|
||||
__asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t"
|
||||
: [c] "+r"(crc)
|
||||
: [v] "r"(v));
|
||||
return crc;
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] [[gnu::const]]
|
||||
inline std::uint32_t neon_crc32cw(std::uint32_t crc, std::uint32_t v) {
|
||||
__asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t"
|
||||
: [c] "+r"(crc)
|
||||
: [v] "r"(v));
|
||||
return crc;
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] [[gnu::const]]
|
||||
inline std::uint64_t neon_crc32cx (std::uint64_t crc, std::uint64_t v) {
|
||||
__asm__ __volatile__("crc32cx %w[c], %w[c], %x[v]\n\t"
|
||||
: [c] "+r"(crc)
|
||||
: [v] "r"(v));
|
||||
return crc;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
[[gnu::const]]
|
||||
bool has_crc32_neon() noexcept {
|
||||
//see
|
||||
//https://community.arm.com/arm-community-blogs/b/operating-systems-blog/posts/runtime-detection-of-cpu-features-on-an-armv8-a-cpu
|
||||
const bool has_hw_crc32 = (getauxval(AT_HWCAP) & HWCAP_CRC32 ? true : false);
|
||||
return has_hw_crc32;
|
||||
}
|
||||
|
||||
/* Compute CRC-32C using the Intel hardware instruction. */
|
||||
/* for better parallelization with bigger buffers see
|
||||
http://www.drdobbs.com/parallel/fast-parallelized-crc-computation-using/229401411 */
|
||||
[[gnu::pure]]
|
||||
std::uint32_t crc32c_neon(const char* input, std::size_t len, std::uint32_t crc) noexcept {
|
||||
//see https://github.com/rurban/smhasher/blob/master/crc32_hw.c
|
||||
constexpr std::size_t align_size = alignof(std::uint64_t);
|
||||
constexpr std::size_t align_mask = align_size - 1;
|
||||
|
||||
// XOR the initial CRC with INT_MAX
|
||||
//crc ^= 0xFFFFFFFF;
|
||||
crc = ~crc;
|
||||
|
||||
// Align the input to the word boundary
|
||||
for (; (len > 0) && (reinterpret_cast<std::uintptr_t>(input) & align_mask); len--, input++) {
|
||||
crc = neon_crc32cb(crc, *input);
|
||||
}
|
||||
|
||||
// Blast off the CRC32 calculation
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
CALC_CRC(neon_crc32cx, crc, std::uint64_t, input, len);
|
||||
#endif
|
||||
CALC_CRC(neon_crc32cw, crc, std::uint32_t, input, len);
|
||||
CALC_CRC(neon_crc32ch, crc, std::uint16_t, input, len);
|
||||
CALC_CRC(neon_crc32cb, crc, std::uint8_t, input, len);
|
||||
|
||||
// Post-process the crc
|
||||
return ~crc;
|
||||
}
|
||||
} //namespace wren::detail
|
|
@ -1,66 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include <smmintrin.h>
|
||||
#include <immintrin.h>
|
||||
#include <cstdint>
|
||||
|
||||
// Byte-boundary alignment issues
|
||||
#define CALC_CRC(op, crc, type, buf, len) \
|
||||
do { \
|
||||
for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
|
||||
(crc) = op((crc), *(type *) (buf)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
namespace wren::detail {
|
||||
[[gnu::const]]
|
||||
bool has_crc32_sse42() noexcept {
|
||||
const bool has_hw_crc32 = (__builtin_cpu_supports("sse4.2") ? true : false);
|
||||
return has_hw_crc32;
|
||||
}
|
||||
|
||||
/* Compute CRC-32C using the Intel hardware instruction. */
|
||||
/* for better parallelization with bigger buffers see
|
||||
http://www.drdobbs.com/parallel/fast-parallelized-crc-computation-using/229401411 */
|
||||
[[gnu::pure]]
|
||||
std::uint32_t crc32c_sse42(const char* input, std::size_t len, std::uint32_t crc) noexcept {
|
||||
//see https://github.com/rurban/smhasher/blob/master/crc32_hw.c
|
||||
constexpr std::size_t align_size = alignof(std::uint64_t);
|
||||
constexpr std::size_t align_mask = align_size - 1;
|
||||
|
||||
// XOR the initial CRC with INT_MAX
|
||||
//crc ^= 0xFFFFFFFF;
|
||||
crc = ~crc;
|
||||
|
||||
// Align the input to the word boundary
|
||||
for (; (len > 0) && (reinterpret_cast<std::uintptr_t>(input) & align_mask); len--, input++) {
|
||||
crc = _mm_crc32_u8(crc, *input);
|
||||
}
|
||||
|
||||
// Blast off the CRC32 calculation
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
CALC_CRC(_mm_crc32_u64, crc, std::uint64_t, input, len);
|
||||
#endif
|
||||
CALC_CRC(_mm_crc32_u32, crc, std::uint32_t, input, len);
|
||||
CALC_CRC(_mm_crc32_u16, crc, std::uint16_t, input, len);
|
||||
CALC_CRC(_mm_crc32_u8, crc, std::uint8_t, input, len);
|
||||
|
||||
// Post-process the crc
|
||||
return ~crc;
|
||||
}
|
||||
} //namespace wren::detail
|
|
@ -1,40 +0,0 @@
|
|||
simd = import('unstable-simd')
|
||||
|
||||
compiler_opts = []
|
||||
if arch == 'amd64'
|
||||
compiler_opts += ['-msse4.2']
|
||||
elif arch == 'aarch64'
|
||||
#gcc options here:
|
||||
#https://gcc.gnu.org/onlinedocs/gcc-11.2.0/gcc/AArch64-Options.html
|
||||
compiler_opts += ['-mcpu=generic+crc']
|
||||
endif
|
||||
|
||||
cpp = meson.get_compiler('cpp')
|
||||
crc32_simd = simd.check('crc32_hw',
|
||||
sse42: 'crc32_sse42.cpp',
|
||||
neon: 'crc32_neon.cpp',
|
||||
compiler: cpp,
|
||||
cpp_args: compiler_opts,
|
||||
)
|
||||
|
||||
crc32_objs = crc32_simd[0]
|
||||
crc32_config = crc32_simd[1]
|
||||
|
||||
project_config_file = configure_file(
|
||||
output: 'crc32_config.h',
|
||||
configuration: crc32_config
|
||||
)
|
||||
|
||||
crc32 = static_library('crc32',
|
||||
'crc32.cpp',
|
||||
include_directories: [public_incl],
|
||||
install: false,
|
||||
cpp_args: global_compiler_opts,
|
||||
link_with: crc32_objs,
|
||||
)
|
||||
|
||||
crc32_dep = declare_dependency(
|
||||
include_directories: public_incl,
|
||||
link_with: crc32,
|
||||
compile_args: global_compiler_opts,
|
||||
)
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -16,52 +16,37 @@
|
|||
*/
|
||||
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
#include "wrenpp/vm.hpp"
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace wren {
|
||||
namespace {
|
||||
template <typename T>
|
||||
bool empty(T* message) {
|
||||
return not (message and *message);
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
void DefConfiguration::write_fn (VM*, wren_string_t text) {
|
||||
void DefConfiguration::write_fn (VM*, const char* text) {
|
||||
std::cout << text;
|
||||
}
|
||||
|
||||
void DefConfiguration::error_fn (VM*, ErrorType type, wren_string_t module, int line, wren_string_t message) {
|
||||
using std::empty;
|
||||
|
||||
std::cerr << "Wren error: " << message;
|
||||
if (!empty(module)) {
|
||||
std::cerr << " in " << module;
|
||||
if (line > -1) {
|
||||
std::cerr << ':' << line;
|
||||
}
|
||||
}
|
||||
std::cerr << '\n';
|
||||
void DefConfiguration::error_fn (VM*, ErrorType type, const char* module, int line, const char* message) {
|
||||
std::cerr << "Wren error: " << message << " in " << module << ':' << line << '\n';
|
||||
}
|
||||
|
||||
void* DefConfiguration::reallocate_fn (void* ptr, std::size_t size) {
|
||||
if (0 == size) {
|
||||
std::free(ptr);
|
||||
return nullptr;
|
||||
if (ptr and size) {
|
||||
//reallocate
|
||||
char* const old_mem = static_cast<char*>(ptr);
|
||||
char* const new_mem = new char[size];
|
||||
std::copy(old_mem, old_mem + size, new_mem);
|
||||
delete[] old_mem;
|
||||
return new_mem;
|
||||
}
|
||||
|
||||
return std::realloc(ptr, size);
|
||||
}
|
||||
|
||||
foreign_method_t DefConfiguration::foreign_method_fn (VM* vm, wren_string_t module_name, wren_string_t class_name, bool is_static, wren_string_t signature) {
|
||||
return vm->callback_manager().callback(is_static, module_name, class_name, signature);
|
||||
}
|
||||
|
||||
foreign_class_t DefConfiguration::foreign_class_fn (wren::VM* vm, std::string_view module_name, std::string_view class_name) {
|
||||
return vm->class_manager().make_class(module_name, class_name);
|
||||
else if (ptr and not size) {
|
||||
//free
|
||||
char* const old_mem = static_cast<char*>(ptr);
|
||||
delete[] old_mem;
|
||||
}
|
||||
else if (not ptr and size) {
|
||||
//allocate
|
||||
char* const new_mem = new char[size];
|
||||
return new_mem;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
} //namespace wren
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#as --march=generic64 -o dynafunc.o ~/dev/code/cpp/wrentest/src/dynafunc.asm
|
||||
#objcopy -j .text -O binary dynafunc.o dynafunc.bin
|
||||
#xxd -i dynafunc.bin
|
||||
|
||||
.global g_dynafunc
|
||||
.global g_dynafunc_end
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.text
|
||||
|
||||
g_dynafunc:
|
||||
ldr x0, .+20
|
||||
ldr x1, .+24
|
||||
ldr x2, .+28
|
||||
ldr x9, .+32
|
||||
br x9
|
||||
.dword 0xdeadbeefdeadbeef //function VM& parameter
|
||||
.dword 0x1badb0021badb002 //ModuleAndName parameter, string part
|
||||
.dword 0xfee1deadfee1dead //ModuleAndName parameter, data part
|
||||
.dword 0xbadc0ffee0ddf00d //function pointer
|
||||
g_dynafunc_end:
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -21,19 +21,10 @@
|
|||
|
||||
.global g_dynafunc
|
||||
.global g_dynafunc_end
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
.text
|
||||
|
||||
g_dynafunc:
|
||||
//VM pointer, parameter 1
|
||||
movabsq $0xdeadbeefdeadbeef, %rdi
|
||||
//ModuleAndName string part, parameter 2
|
||||
movabsq $0x1badb0021badb002, %rsi
|
||||
//ModuleAndName data part, parameter 3
|
||||
movabsq $0xfee1deadfee1dead, %rdx
|
||||
|
||||
//jump address
|
||||
movabsq $0xbadc0ffee0ddf00d, %rax
|
||||
jmp *%rax
|
||||
movq $0xdeadbeefdeadbeef, %rdi
|
||||
movq $0xbadc0ffee0ddf00d, %rdx
|
||||
jmp *%rdx
|
||||
ret
|
||||
g_dynafunc_end:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -21,8 +21,7 @@
|
|||
#endif
|
||||
|
||||
#include "dynafunc_maker.hpp"
|
||||
#include "pvt_config.h"
|
||||
#include "wrenpp/detail/strings_in_vector.hpp"
|
||||
#include "config.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <unistd.h> //for sysconf()
|
||||
|
@ -32,8 +31,6 @@
|
|||
#include <sys/mman.h> //for mprotect()
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wren {
|
||||
namespace {
|
||||
|
@ -45,18 +42,10 @@ namespace wren {
|
|||
extern "C" const char g_dynafunc_end[];
|
||||
const unsigned int g_dynafunc_len = g_dynafunc_end - g_dynafunc;
|
||||
|
||||
constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
|
||||
constexpr unsigned int g_dynafunc_ptr2_size = ASM_FUNC_PTR_SIZE;
|
||||
//For inspiration: https://www.liquisearch.com/deadbeef/magic_debug_values
|
||||
//0xdeadbeefdeadbeef
|
||||
constexpr unsigned char g_dynafunc_ptr1[] = {0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde};
|
||||
//0xbadc0ffee0ddf00d
|
||||
constexpr unsigned char g_dynafunc_ptr2[] = {0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba};
|
||||
//0x1badb0021badb002
|
||||
constexpr unsigned char g_dynafunc_ptr3[] = {0x02, 0xb0, 0xad, 0x1b, 0x02, 0xb0, 0xad, 0x1b};
|
||||
//0xfee1deadfee1dead
|
||||
constexpr unsigned char g_dynafunc_ptr4[] = {0xad, 0xde, 0xe1, 0xfe, 0xad, 0xde, 0xe1, 0xfe};
|
||||
|
||||
const constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
|
||||
const constexpr unsigned int g_dynafunc_ptr2_size = ASM_FUNC_PTR_SIZE;
|
||||
const constexpr unsigned char g_dynafunc_ptr1[] = {0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde};
|
||||
const constexpr unsigned char g_dynafunc_ptr2[] = {0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba};
|
||||
static_assert(sizeof(g_dynafunc_ptr1) / sizeof(g_dynafunc_ptr1[0]) >= g_dynafunc_ptr1_size);
|
||||
static_assert(sizeof(g_dynafunc_ptr2) / sizeof(g_dynafunc_ptr2[0]) >= g_dynafunc_ptr2_size);
|
||||
|
||||
|
@ -74,51 +63,11 @@ namespace wren {
|
|||
std::copy(ptr, ptr + sizeof(T), subseq);
|
||||
}
|
||||
|
||||
void make_dynafunc_asm(
|
||||
unsigned char* out,
|
||||
VM* ptr1,
|
||||
foreign_method_t ptr2,
|
||||
RawAccessModuleAndName mn
|
||||
) {
|
||||
static_assert(std::is_standard_layout<ModuleAndName>::value,
|
||||
"Must be a standard layout to be compliant with the assembly functions");
|
||||
static_assert(sizeof(void*) * 2 == sizeof(ModuleAndName),
|
||||
"Must fit into 2 registers to be compliant with the assembly functions");
|
||||
|
||||
void make_dynafunc_asm(unsigned char* out, VM* ptr1, foreign_method_t ptr2) {
|
||||
std::copy(g_dynafunc, g_dynafunc_end, out);
|
||||
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr1, ptr1);
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr2, ptr2);
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr3, mn.raw.string);
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr4, mn.raw.data);
|
||||
}
|
||||
|
||||
ModuleAndName store_module_name (
|
||||
std::list<std::vector<char>>& dst,
|
||||
std::string_view mod_name,
|
||||
std::string_view cls_name
|
||||
) {
|
||||
typedef std::vector<char> CharVec;
|
||||
CharVec new_entry = strings_to_vector(mod_name, cls_name);
|
||||
|
||||
const auto it_found = std::lower_bound(
|
||||
dst.cbegin(),
|
||||
dst.cend(),
|
||||
new_entry,
|
||||
[](const CharVec& a, const CharVec& b) {
|
||||
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
|
||||
}
|
||||
);
|
||||
|
||||
const CharVec* source_mem;
|
||||
if (dst.cend() != it_found && std::equal(it_found->cbegin(), it_found->cend(), new_entry.cbegin(), new_entry.cend())) {
|
||||
source_mem = &*it_found;
|
||||
}
|
||||
else {
|
||||
source_mem = &*dst.insert(it_found, std::move(new_entry));
|
||||
}
|
||||
|
||||
return {source_mem->data(), mod_name.size(), cls_name.size()};
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
|
@ -137,11 +86,9 @@ namespace wren {
|
|||
clear();
|
||||
}
|
||||
|
||||
void* DynafuncMaker::make (VM* vm, foreign_method_t cb, const char* mod_name, const char* cls_name) {
|
||||
void* DynafuncMaker::make (VM* vm, foreign_method_t cb) {
|
||||
unsigned char* const mem = allocate_chunk();
|
||||
const auto mn = store_module_name(m_string_params, mod_name, cls_name);
|
||||
make_dynafunc_asm(mem, vm, cb, mn);
|
||||
|
||||
make_dynafunc_asm(mem, vm, cb);
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
@ -154,9 +101,7 @@ namespace wren {
|
|||
}
|
||||
|
||||
std::size_t DynafuncMaker::total_memory() const {
|
||||
return m_pages.size() * m_page_size +
|
||||
m_pages.capacity() * sizeof(decltype(m_pages)::value_type) +
|
||||
0;
|
||||
return m_pages.size() * m_page_size;
|
||||
}
|
||||
|
||||
unsigned char* DynafuncMaker::allocate_chunk() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -17,18 +17,19 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "wrenpp/detail/wren_types.hpp"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cstddef>
|
||||
|
||||
namespace wren {
|
||||
class VM;
|
||||
typedef void(*foreign_method_t)(VM&);
|
||||
|
||||
class DynafuncMaker {
|
||||
public:
|
||||
DynafuncMaker();
|
||||
~DynafuncMaker() noexcept;
|
||||
|
||||
void* make (VM* vm, foreign_method_t cb, const char* mod_name, const char* cls_name);
|
||||
void* make (VM* vm, foreign_method_t cb);
|
||||
void clear() noexcept;
|
||||
|
||||
std::size_t total_memory() const;
|
||||
|
@ -36,7 +37,6 @@ namespace wren {
|
|||
private:
|
||||
unsigned char* allocate_chunk();
|
||||
|
||||
std::list<std::vector<char>> m_string_params;
|
||||
std::vector<void*> m_pages;
|
||||
std::size_t m_page_size;
|
||||
std::size_t m_used_bytes;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2024, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -18,25 +18,14 @@
|
|||
#include "wrenpp/handle.hpp"
|
||||
#include "wrenpp/vm.hpp"
|
||||
#include <cassert>
|
||||
#include <ciso646>
|
||||
|
||||
namespace wren {
|
||||
Handle::Handle (VM* vm, int slot_num) :
|
||||
Handle(vm->slot_handle(slot_num))
|
||||
{
|
||||
}
|
||||
|
||||
Handle::~Handle() noexcept {
|
||||
release();
|
||||
}
|
||||
|
||||
void Handle::release() noexcept {
|
||||
assert(m_vm or not m_handle);
|
||||
if (m_vm)
|
||||
m_vm->release_handle(*this);
|
||||
}
|
||||
|
||||
void Handle::set_to_slot (int slot) {
|
||||
m_vm->set_slot_handle(*this, slot);
|
||||
assert(m_vm);
|
||||
m_vm->release_handle(*this);
|
||||
}
|
||||
} //namespace wren
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
subdir('crc32')
|
||||
|
||||
project_config_file = configure_file(
|
||||
input: 'pvt_config.h.in',
|
||||
output: 'pvt_config.h',
|
||||
configuration: conf
|
||||
)
|
||||
|
||||
wrenpp = library(meson.project_name(),
|
||||
project_config_file,
|
||||
'vm.cpp',
|
||||
'configuration.cpp',
|
||||
'def_configuration.cpp',
|
||||
'dynafunc_maker.cpp',
|
||||
'dynafunc_' + arch + '_' + os + '.S',
|
||||
'handle.cpp',
|
||||
'vm_fun.cpp',
|
||||
'callback_manager.cpp',
|
||||
'class_manager.cpp',
|
||||
'wren_class_name_from_type.cpp',
|
||||
'module_and_name.cpp',
|
||||
'setters_getters.cpp',
|
||||
dependencies: [wren_dep, crc32_dep],
|
||||
include_directories: public_incl,
|
||||
install: (not meson.is_subproject() or get_option('default_library')=='shared'),
|
||||
c_args: global_compiler_opts,
|
||||
cpp_args: global_compiler_opts,
|
||||
)
|
||||
|
||||
wrenpp_dep = declare_dependency(
|
||||
link_with: wrenpp,
|
||||
include_directories: public_incl,
|
||||
compile_args: global_compiler_opts,
|
||||
)
|
||||
|
||||
meson.override_dependency(meson.project_name(), wrenpp_dep)
|
|
@ -1,30 +0,0 @@
|
|||
/* 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/detail/module_and_name.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace wren::detail {
|
||||
bool deep_equal(const ModuleAndName& a, const ModuleAndName& b) noexcept {
|
||||
const auto a_size = a.raw_buffer_size();
|
||||
const auto b_size = b.raw_buffer_size();
|
||||
if (a_size != b_size)
|
||||
return false;
|
||||
|
||||
return std::equal(a.m_base, a.m_base + a_size, b.m_base);
|
||||
}
|
||||
} //namespace wren::detail
|
178
src/pywrenppmodule.cpp
Normal file
178
src/pywrenppmodule.cpp
Normal file
|
@ -0,0 +1,178 @@
|
|||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "wrenpp/vm.hpp"
|
||||
#include "wrenpp/vm_fun.hpp"
|
||||
#include "wrenpp/def_configuration.hpp"
|
||||
#include "config.h"
|
||||
#include <vector>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
#define CURR_MODULE_NAME "py" WRENPP_NAME
|
||||
|
||||
namespace {
|
||||
struct VMObject;
|
||||
int vm_init (VMObject* self, PyObject*, PyObject*);
|
||||
PyObject* vm_new (PyTypeObject* type, PyObject*, PyObject*);
|
||||
void vm_dealloc (VMObject* self);
|
||||
PyObject* vm_interpret (VMObject* self, PyObject* args);
|
||||
PyObject* vm_call (VMObject* self, PyObject* args);
|
||||
|
||||
class VMConfig : public wren::DefConfiguration {
|
||||
public:
|
||||
wren::foreign_method_t foreign_method_fn (
|
||||
wren::VM* vm,
|
||||
const char* module_ptr,
|
||||
const char* class_name_ptr,
|
||||
bool is_static,
|
||||
const char* signature_ptr
|
||||
) {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
PyMethodDef WrenppMethods[] = {
|
||||
//{"eval_script", &eval_script, METH_VARARGS, "Evaluate a Wren script"},
|
||||
{nullptr, nullptr, 0, nullptr}
|
||||
};
|
||||
|
||||
struct PyModuleDef WrenppModule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
CURR_MODULE_NAME, //module name
|
||||
"Python bindings for Wrenpp", //module documentation
|
||||
-1, //size of per-interpreter state of the module, or -1 if the module keeps state in global variables
|
||||
WrenppMethods
|
||||
};
|
||||
|
||||
struct VMObject {
|
||||
PyObject_HEAD
|
||||
wren::VM vm;
|
||||
};
|
||||
//PyMemberDef VMProperties[] = {
|
||||
// {nullptr}
|
||||
//};
|
||||
PyMethodDef VMMethods[] = {
|
||||
{
|
||||
"interpret",
|
||||
reinterpret_cast<PyCFunction>(vm_interpret),
|
||||
METH_VARARGS,
|
||||
"Interpret a string script"
|
||||
},
|
||||
{
|
||||
"call",
|
||||
reinterpret_cast<PyCFunction>(vm_call),
|
||||
METH_VARARGS,
|
||||
"Call a method from a previously parsed script"
|
||||
},
|
||||
{nullptr}
|
||||
};
|
||||
|
||||
PyTypeObject VMType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = CURR_MODULE_NAME ".VM",
|
||||
.tp_basicsize = sizeof(VMObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_dealloc = reinterpret_cast<destructor>(vm_dealloc),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "Wrenpp VM",
|
||||
.tp_methods = VMMethods,
|
||||
.tp_members = nullptr, //VMProperties,
|
||||
.tp_init = reinterpret_cast<initproc>(vm_init),
|
||||
.tp_new = vm_new,
|
||||
};
|
||||
|
||||
PyObject* vm_new (PyTypeObject* type, PyObject* /*args*/, PyObject* /*kwds*/) {
|
||||
VMObject* const self = reinterpret_cast<VMObject*>(type->tp_alloc(type, 0));
|
||||
if (self) {
|
||||
try {
|
||||
VMConfig config;
|
||||
new(&self->vm) wren::VM(&config, nullptr);
|
||||
}
|
||||
catch (...) {
|
||||
Py_DECREF(self);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return reinterpret_cast<PyObject*>(self);
|
||||
}
|
||||
|
||||
void vm_dealloc (VMObject* self) {
|
||||
self->vm.~VM();
|
||||
}
|
||||
|
||||
int vm_init (VMObject* self, PyObject* /*args*/, PyObject* /*kwds*/) {
|
||||
VMConfig config;
|
||||
self->vm.reset(&config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* vm_interpret (VMObject* self, PyObject* args) {
|
||||
const char* module_name;
|
||||
const char* script;
|
||||
if (!PyArg_ParseTuple(args, "ss", &module_name, &script))
|
||||
return NULL;
|
||||
|
||||
self->vm.interpret(module_name, script);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject* vm_call (VMObject* self, PyObject* args) {
|
||||
const Py_ssize_t argc = PyTuple_Size(args);
|
||||
std::vector<PyObject*> objects;
|
||||
objects.reserve(argc);
|
||||
|
||||
self->vm.ensure_slots(static_cast<std::size_t>(argc) + 1);
|
||||
variable(self->vm, wren::ModuleAndName{"main", "the_user"}, 0);
|
||||
|
||||
//TODO: missing error checks, see
|
||||
//https://stackoverflow.com/questions/8001923/python-extension-module-with-variable-number-of-arguments
|
||||
|
||||
std::string func_sig;
|
||||
{
|
||||
Py_ssize_t sz;
|
||||
PyObject* const obj = PyTuple_GetItem(args, 0);
|
||||
const char* const buf = PyUnicode_AsUTF8AndSize(obj, &sz);
|
||||
func_sig.reserve(sz + 3);
|
||||
func_sig.append(buf, sz);
|
||||
func_sig.append(1, '(');
|
||||
}
|
||||
|
||||
for (Py_ssize_t z = 1; z < argc; ++z) {
|
||||
PyObject* const obj = PyTuple_GetItem(args, z);
|
||||
if (not obj)
|
||||
return nullptr;
|
||||
|
||||
const std::string_view type_name(Py_TYPE(obj)->tp_name);
|
||||
//std::cout << "vm_call, parameter " << z+1 << " has type \"" << type_name << "\"\n";
|
||||
if (type_name == "str") {
|
||||
const char* const buf = PyUnicode_AsUTF8(obj);
|
||||
self->vm.set_slot_string(static_cast<std::size_t>(z), buf);
|
||||
}
|
||||
func_sig += "_,";
|
||||
}
|
||||
|
||||
if (func_sig.back() == ',')
|
||||
func_sig.resize(func_sig.size() - 1);
|
||||
func_sig += ")";
|
||||
auto handle = self->vm.make_call_handle(func_sig.c_str());
|
||||
self->vm.call(handle);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
PyMODINIT_FUNC PyInit_pywrenpp(void) {
|
||||
if (PyType_Ready(&VMType) < 0)
|
||||
return nullptr;
|
||||
PyObject* const m = PyModule_Create(&WrenppModule);
|
||||
if (not m)
|
||||
return nullptr;
|
||||
|
||||
Py_INCREF(&VMType);
|
||||
if (PyModule_AddObject(m, "VM", reinterpret_cast<PyObject*>(&VMType)) < 0) {
|
||||
Py_DECREF(&VMType);
|
||||
Py_DECREF(m);
|
||||
return nullptr;
|
||||
}
|
||||
return m;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/* Copyright 2020-2024, 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/>.
|
||||
*/
|
||||
|
||||
#include "wrenpp/detail/setters_getters.hpp"
|
||||
|
||||
namespace wren {
|
||||
} //namespace wren
|
125
src/vm.cpp
125
src/vm.cpp
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -17,8 +17,6 @@
|
|||
|
||||
#include "wrenpp/vm.hpp"
|
||||
#include "wrenpp/configuration.hpp"
|
||||
#include "wrenpp/callback_manager.hpp"
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
#include "dynafunc_maker.hpp"
|
||||
#include <wren.hpp>
|
||||
#include <cassert>
|
||||
|
@ -36,8 +34,6 @@ namespace wren {
|
|||
};
|
||||
}
|
||||
|
||||
void load_module_complete_fn (WrenVM* wvm, const char* name, struct WrenLoadModuleResult result);
|
||||
|
||||
void write_fn (WrenVM* wvm, const char* text) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
|
@ -49,8 +45,7 @@ namespace wren {
|
|||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->error_fn and cb->config_obj and cb->owner);
|
||||
const char* const sane_module = (module ? module : "");
|
||||
cb->error_fn(*cb->config_obj, cb->owner, to_error_type(type), sane_module, line, message);
|
||||
cb->error_fn(*cb->config_obj, cb->owner, to_error_type(type), module, line, message);
|
||||
}
|
||||
|
||||
const char* resolve_module_fn (WrenVM* wvm, const char* importer, const char* name) {
|
||||
|
@ -60,25 +55,11 @@ namespace wren {
|
|||
return cb->resolve_module_fn(*cb->config_obj, cb->owner, importer, name);
|
||||
}
|
||||
|
||||
void* reallocate_fn (void* memory, size_t size, void* user_data) {
|
||||
auto cb = static_cast<detail::Callbacks*>(user_data);
|
||||
assert(cb);
|
||||
assert(cb->reallocate_fn);
|
||||
return cb->reallocate_fn(memory, size);
|
||||
}
|
||||
|
||||
WrenLoadModuleResult load_module_fn (WrenVM* wvm, const char* name) {
|
||||
const auto user_data = wrenGetUserData(wvm);
|
||||
auto cb = static_cast<detail::Callbacks*>(user_data);
|
||||
char* load_module_fn (WrenVM* wvm, const char* name) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->load_module_fn and cb->config_obj and cb->owner);
|
||||
|
||||
char* const source = cb->load_module_fn(*cb->config_obj, cb->owner, name);
|
||||
return ::WrenLoadModuleResult{
|
||||
.source = source,
|
||||
.onComplete = (cb->load_module_complete_fn ? &load_module_complete_fn : nullptr),
|
||||
.userData = nullptr
|
||||
};
|
||||
return cb->load_module_fn(*cb->config_obj, cb->owner, name);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn foreign_method_fn (WrenVM* wvm, const char* module, const char* class_name, bool is_static, const char* signature) {
|
||||
|
@ -89,18 +70,7 @@ namespace wren {
|
|||
if (func) {
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
//dfm->make creates a function that takes one WrenVM* parameter
|
||||
//which it disregards; then it calls func passing cb->owner to
|
||||
//it and a ModuleAndName object populated with the values given
|
||||
//here. This should rarely change, but please double check if
|
||||
//this is important to you as this comment might become
|
||||
//outdated.
|
||||
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(
|
||||
cb->owner,
|
||||
func,
|
||||
module,
|
||||
class_name
|
||||
));
|
||||
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, func));
|
||||
return retval;
|
||||
}
|
||||
else {
|
||||
|
@ -108,18 +78,6 @@ namespace wren {
|
|||
}
|
||||
}
|
||||
|
||||
void load_module_complete_fn (WrenVM* wvm, const char* name, struct WrenLoadModuleResult result) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
assert(cb->load_module_complete_fn and cb->config_obj and cb->owner);
|
||||
|
||||
//Documentation says result is the same object we returned from
|
||||
//load_module_fn. It should then be safe to const_cast source,
|
||||
//since it wasn't const when we got it there
|
||||
char* const non_const_buff = const_cast<char*>(result.source);
|
||||
(*cb->load_module_complete_fn)(*cb->config_obj, cb->owner, name, non_const_buff);
|
||||
}
|
||||
|
||||
WrenForeignClassMethods foreign_class_fn (WrenVM* wvm, const char* module, const char* class_name) {
|
||||
auto cb = static_cast<detail::Callbacks*>(wrenGetUserData(wvm));
|
||||
assert(cb);
|
||||
|
@ -129,12 +87,7 @@ namespace wren {
|
|||
if (funcs.allocate) {
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(
|
||||
cb->owner,
|
||||
funcs.allocate,
|
||||
module,
|
||||
class_name
|
||||
));
|
||||
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, funcs.allocate));
|
||||
}
|
||||
else {
|
||||
retval.allocate = nullptr;
|
||||
|
@ -162,8 +115,7 @@ namespace wren {
|
|||
struct VM::LocalData {
|
||||
explicit LocalData (const detail::Callbacks& cb) :
|
||||
callbacks(cb),
|
||||
wvm(nullptr),
|
||||
user_data_type(type_id<std::nullptr_t>())
|
||||
wvm(nullptr)
|
||||
{
|
||||
callbacks.dynafunc = &dynafunc;
|
||||
}
|
||||
|
@ -175,16 +127,14 @@ namespace wren {
|
|||
#endif
|
||||
}
|
||||
|
||||
CallbackManager callback_manager;
|
||||
ClassManager class_manager;
|
||||
detail::Callbacks callbacks;
|
||||
DynafuncMaker dynafunc;
|
||||
WrenVM* wvm;
|
||||
void* user_data;
|
||||
TypeID user_data_type;
|
||||
std::uint32_t user_data_type;
|
||||
};
|
||||
|
||||
VM::VM (Configuration* conf, const detail::Callbacks& cb, void* user_data, TypeID user_data_type) :
|
||||
VM::VM (Configuration* conf, const detail::Callbacks& cb, void* user_data, std::uint32_t user_data_type) :
|
||||
m_local(std::make_unique<LocalData>(cb))
|
||||
{
|
||||
this->reset(conf);
|
||||
|
@ -198,7 +148,7 @@ namespace wren {
|
|||
return &m_local->dynafunc;
|
||||
}
|
||||
|
||||
TypeID VM::user_data_type() const {
|
||||
std::uint32_t VM::user_data_type() const {
|
||||
return m_local->user_data_type;
|
||||
}
|
||||
|
||||
|
@ -206,7 +156,7 @@ namespace wren {
|
|||
return m_local->user_data;
|
||||
}
|
||||
|
||||
void VM::set_user_data (void* user_data, TypeID user_data_type) {
|
||||
void VM::set_user_data (void* user_data, std::uint32_t user_data_type) {
|
||||
m_local->user_data = user_data;
|
||||
m_local->user_data_type = user_data_type;
|
||||
}
|
||||
|
@ -282,26 +232,13 @@ namespace wren {
|
|||
|
||||
void VM::set_user_data (std::nullptr_t) {
|
||||
m_local->user_data = nullptr;
|
||||
m_local->user_data_type = type_id<std::nullptr_t>();
|
||||
m_local->user_data_type = detail::type_id<std::nullptr_t>();
|
||||
}
|
||||
|
||||
bool VM::has_user_data() const noexcept {
|
||||
bool VM::has_user_data() const {
|
||||
return nullptr != m_local->user_data;
|
||||
}
|
||||
|
||||
bool VM::has_module(const char* module) const noexcept {
|
||||
assert(module);
|
||||
return wrenHasModule(m_local->wvm, module);
|
||||
}
|
||||
|
||||
bool VM::has_variable(const char* module, const char* name) const noexcept {
|
||||
return wrenHasVariable(m_local->wvm, module, name);
|
||||
}
|
||||
|
||||
void VM::abort_fiber(int slot_num) {
|
||||
wrenAbortFiber(m_local->wvm, slot_num);
|
||||
}
|
||||
|
||||
std::size_t VM::dynafunc_byte_size() const {
|
||||
return m_local->dynafunc.total_memory();
|
||||
}
|
||||
|
@ -323,7 +260,7 @@ namespace wren {
|
|||
wconf.errorFn = &error_fn;
|
||||
|
||||
if (cb.reallocate_fn)
|
||||
wconf.reallocateFn = &reallocate_fn;
|
||||
wconf.reallocateFn = cb.reallocate_fn;
|
||||
|
||||
if (cb.resolve_module_fn)
|
||||
wconf.resolveModuleFn = &resolve_module_fn;
|
||||
|
@ -346,22 +283,6 @@ namespace wren {
|
|||
m_local->dynafunc.clear();
|
||||
}
|
||||
|
||||
CallbackManager& VM::callback_manager() {
|
||||
return m_local->callback_manager;
|
||||
}
|
||||
|
||||
const CallbackManager& VM::callback_manager() const {
|
||||
return m_local->callback_manager;
|
||||
}
|
||||
|
||||
ClassManager& VM::class_manager() {
|
||||
return m_local->class_manager;
|
||||
}
|
||||
|
||||
const ClassManager& VM::class_manager() const {
|
||||
return m_local->class_manager;
|
||||
}
|
||||
|
||||
void VM::ensure_slots (int num_slots) {
|
||||
wrenEnsureSlots(m_local->wvm, num_slots);
|
||||
}
|
||||
|
@ -370,23 +291,10 @@ namespace wren {
|
|||
return wrenGetSlotCount(m_local->wvm);
|
||||
}
|
||||
|
||||
void VM::variable(const char* module, const char* name, int slot) noexcept {
|
||||
assert(slot_count() >= 1);
|
||||
void VM::variable(const char* module, const char* name, int slot) {
|
||||
wrenGetVariable(m_local->wvm, module, name, slot);
|
||||
}
|
||||
|
||||
void VM::variable_or_throw(const char* module, const char* name, int slot) {
|
||||
using std::string;
|
||||
using std::runtime_error;
|
||||
|
||||
if (not has_module(module))
|
||||
throw runtime_error(string{"Module "} + module + " is unknown");
|
||||
if (not has_variable(module, name))
|
||||
throw runtime_error(string{"Variable "} + module + "::" + name + " not found");
|
||||
|
||||
variable(module, name, slot);
|
||||
}
|
||||
|
||||
void VM::set_slot_handle (const Handle& handle, int slot) {
|
||||
wrenSetSlotHandle(m_local->wvm, slot, handle);
|
||||
}
|
||||
|
@ -401,7 +309,6 @@ namespace wren {
|
|||
case WREN_TYPE_STRING: return SlotType::String;
|
||||
case WREN_TYPE_FOREIGN: return SlotType::Foreign;
|
||||
case WREN_TYPE_UNKNOWN: return SlotType::Unknown;
|
||||
case WREN_TYPE_MAP: return SlotType::Map;
|
||||
};
|
||||
assert(false);
|
||||
return SlotType::Unknown;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright 2020-2022, Michele Santullo
|
||||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of wrenpp.
|
||||
*
|
||||
* Wrenpp is free software: you can redistribute it and/or modify
|
||||
|
@ -72,26 +72,11 @@ namespace wren {
|
|||
return std::vector<char>{arr.first, arr.first + arr.second};
|
||||
}
|
||||
|
||||
void variable(VM& vm, ModuleAndName mod_and_name, int slot) {
|
||||
vm.variable_or_throw(mod_and_name.module_name_char(), mod_and_name.class_name_char(), slot);
|
||||
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot) {
|
||||
vm.variable(std::get<0>(mod_and_name), std::get<1>(mod_and_name), slot);
|
||||
}
|
||||
|
||||
void variable (VM& vm, const Handle& handle, int slot) {
|
||||
vm.set_slot_handle(handle, slot);
|
||||
}
|
||||
|
||||
void variable_ensure_slot(VM& vm, ModuleAndName mod_and_name, int slot) {
|
||||
vm.ensure_slots(1);
|
||||
variable(vm, mod_and_name, slot);
|
||||
}
|
||||
|
||||
void variable_ensure_slot (VM& vm, const Handle& handle, int slot) {
|
||||
vm.ensure_slots(1);
|
||||
variable(vm, handle, slot);
|
||||
}
|
||||
|
||||
void abort_fiber_with_error (VM& vm, int slot, std::string_view message) {
|
||||
set(vm, slot, message);
|
||||
vm.abort_fiber(slot);
|
||||
}
|
||||
} //namespace wren
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
#include "wrenpp/detail/wren_class_name_from_type.hpp"
|
||||
#include "wrenpp/vm.hpp"
|
||||
#include "wrenpp/class_manager.hpp"
|
||||
|
||||
namespace wren {
|
||||
namespace detail {
|
||||
ModuleAndName fetch_class_name_from_manager (
|
||||
const VM& vm,
|
||||
TypeID hash
|
||||
) {
|
||||
return vm.class_manager().wren_class_name_from_hash(hash);
|
||||
}
|
||||
} //namespace detail
|
||||
} //namespace wren
|
|
@ -1,8 +0,0 @@
|
|||
[wrap-git]
|
||||
url = https://github.com/wren-lang/wren.git
|
||||
revision = 4a18fc489f9ea3d253b20dd40f4cdad0d6bb40eb
|
||||
patch_directory = wren
|
||||
|
||||
[provide]
|
||||
dependency_names = wren-0.4.0
|
||||
wren = wren_dep
|
|
@ -1,5 +1,5 @@
|
|||
project('wren', 'c',
|
||||
version: '0.4.0',
|
||||
version: '0.3.0',
|
||||
meson_version: '>=0.54.0',
|
||||
default_options: ['buildtype=release', 'c_std=c99', 'build_testing=true'],
|
||||
)
|
||||
|
@ -17,27 +17,27 @@ else
|
|||
c_opts += '-DWREN_OPT_META=0'
|
||||
endif
|
||||
|
||||
wren_incl = include_directories('src/include', is_system: true)
|
||||
wren_pvt_incl = include_directories('src/vm', 'src/optional')
|
||||
test_incl = include_directories('test')
|
||||
wren_incl = include_directories('wren/src/include', is_system: true)
|
||||
wren_pvt_incl = include_directories('wren/src/vm', 'wren/src/optional')
|
||||
test_incl = include_directories('wren/test')
|
||||
|
||||
threads_dep = dependency('threads')
|
||||
libuv_dep = c_compiler.find_library('uv', required: true)
|
||||
libuv_dep = c_compiler.find_library('libuv', required: true)
|
||||
m_dep = c_compiler.find_library('m', required: true)
|
||||
|
||||
opt_src = [
|
||||
'src/optional/wren_opt_random.c',
|
||||
'src/optional/wren_opt_meta.c',
|
||||
'wren/src/optional/wren_opt_random.c',
|
||||
'wren/src/optional/wren_opt_meta.c',
|
||||
]
|
||||
|
||||
vm_src = [
|
||||
'src/vm/wren_compiler.c',
|
||||
'src/vm/wren_core.c',
|
||||
'src/vm/wren_debug.c',
|
||||
'src/vm/wren_primitive.c',
|
||||
'src/vm/wren_utils.c',
|
||||
'src/vm/wren_value.c',
|
||||
'src/vm/wren_vm.c',
|
||||
'wren/src/vm/wren_compiler.c',
|
||||
'wren/src/vm/wren_core.c',
|
||||
'wren/src/vm/wren_debug.c',
|
||||
'wren/src/vm/wren_primitive.c',
|
||||
'wren/src/vm/wren_utils.c',
|
||||
'wren/src/vm/wren_value.c',
|
||||
'wren/src/vm/wren_vm.c',
|
||||
]
|
||||
|
||||
force_static = meson.is_subproject()
|
||||
|
@ -69,25 +69,24 @@ if get_option('build_testing')
|
|||
fs = import('fs')
|
||||
|
||||
test_src = [
|
||||
'test/api/api_tests.c',
|
||||
'test/api/benchmark.c',
|
||||
'test/api/call.c',
|
||||
'test/api/call_calls_foreign.c',
|
||||
'test/api/call_wren_call_root.c',
|
||||
'test/api/error.c',
|
||||
'test/api/foreign_class.c',
|
||||
'test/api/get_variable.c',
|
||||
'test/api/handle.c',
|
||||
'test/api/lists.c',
|
||||
'test/api/maps.c',
|
||||
'test/api/new_vm.c',
|
||||
'test/api/reset_stack_after_call_abort.c',
|
||||
'test/api/reset_stack_after_foreign_construct.c',
|
||||
'test/api/resolution.c',
|
||||
'test/api/slots.c',
|
||||
'test/api/user_data.c',
|
||||
'test/main.c',
|
||||
'test/test.c',
|
||||
'wren/test/api/api_tests.c',
|
||||
'wren/test/api/benchmark.c',
|
||||
'wren/test/api/call.c',
|
||||
'wren/test/api/call_calls_foreign.c',
|
||||
'wren/test/api/call_wren_call_root.c',
|
||||
'wren/test/api/error.c',
|
||||
'wren/test/api/foreign_class.c',
|
||||
'wren/test/api/get_variable.c',
|
||||
'wren/test/api/handle.c',
|
||||
'wren/test/api/lists.c',
|
||||
'wren/test/api/new_vm.c',
|
||||
'wren/test/api/reset_stack_after_call_abort.c',
|
||||
'wren/test/api/reset_stack_after_foreign_construct.c',
|
||||
'wren/test/api/resolution.c',
|
||||
'wren/test/api/slots.c',
|
||||
'wren/test/api/user_data.c',
|
||||
'wren/test/main.c',
|
||||
'wren/test/test.c',
|
||||
]
|
||||
|
||||
test_script_paths = [
|
||||
|
@ -104,7 +103,7 @@ if get_option('build_testing')
|
|||
|
||||
test_scripts = run_command(
|
||||
files('find_scripts.py'),
|
||||
meson.current_source_dir() / 'test',
|
||||
meson.current_source_dir() / 'wren/test',
|
||||
test_script_paths,
|
||||
).stdout().strip().split('\n')
|
||||
|
||||
|
@ -136,7 +135,7 @@ endif
|
|||
|
||||
if not force_static
|
||||
install_headers(
|
||||
'src/include/wren.h',
|
||||
'src/include/wren.hpp',
|
||||
'wren/src/include/wren.h',
|
||||
'wren/src/include/wren.hpp',
|
||||
)
|
||||
endif
|
1
subprojects/wren/wren
Submodule
1
subprojects/wren/wren
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit cd012469976d1a9da796581cd9a9591842cb0cf8
|
|
@ -24,24 +24,6 @@ System.print("my_sum = %(my_sum) (expected: 19)")
|
|||
var my_sub = Maths.sub(Maths.sub(8, 5), Maths.sub(20, 19)) + 1
|
||||
System.print("my_sub = %(my_sub) (expected: 3)")
|
||||
|
||||
)script";
|
||||
|
||||
const constexpr char g_script_2[] = ""
|
||||
R"script(class Maths {
|
||||
foreign static mul(a,b)
|
||||
foreign static div(a,b)
|
||||
foreign static sum(a,b)
|
||||
foreign static sub(a,b)
|
||||
}
|
||||
|
||||
var my_mul_2 = Maths.mul(Maths.mul(2, 2), Maths.mul(3, 2)) - 4
|
||||
System.print("my_mul_2 = %(my_mul_2) (expected: 20)")
|
||||
|
||||
var my_sum_2 = Maths.sum(Maths.sum(3, 4), Maths.sum(5, -1)) + 8
|
||||
System.print("my_sum_2 = %(my_sum_2) (expected: 19)")
|
||||
|
||||
var my_sub_2 = Maths.sub(Maths.sub(8, 5), Maths.sub(20, 19)) + 1
|
||||
System.print("my_sub_2 = %(my_sub_2) (expected: 3)")
|
||||
)script";
|
||||
|
||||
class MyConfig : public wren::DefConfiguration {
|
||||
|
@ -107,18 +89,6 @@ int main() {
|
|||
|
||||
wren::VM vm(&config, nullptr);
|
||||
vm.interpret("main", g_script);
|
||||
wren::variable_ensure_slot(vm, {"main", "my_mul"}, 0);
|
||||
|
||||
std::cout << "Dynafunc mem usage: " << vm.dynafunc_byte_size() << " bytes\n";
|
||||
|
||||
vm.reset(&config);
|
||||
std::cout << "Dynafunc mem usage after reset: " << vm.dynafunc_byte_size() << " bytes\n";
|
||||
vm.interpret("main", g_script_2);
|
||||
|
||||
{
|
||||
auto [var] = wren::variables<int>(vm, wren::ModuleAndName{"main", "my_mul_2"});
|
||||
std::cout << "main::my_mul2 == " << var << " (expected: 20)\n";
|
||||
}
|
||||
|
||||
std::cout << "Dynafunc mem usage: " << vm.dynafunc_byte_size() << " bytes\n";
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue