Compare commits

..

5 commits

Author SHA1 Message Date
8a721494b1 Refactor so that make_method_bindable also accepts free functions now
This includes pointers to static member functions too of course.
`make_method_bindable` got renamed into the more generic
`make_function_bindable` because it deals with all functions
now, not only member functions.
2022-05-19 15:05:18 +02:00
c993f8a38e Fix off-by-one error
bt::string takes the full length of the buffer including
the terminating null-char
2022-05-19 15:01:36 +02:00
e55390338a Build fix on gcc 12 2022-05-19 14:39:30 +02:00
678624a75d Build fix on clang 2022-05-19 12:32:09 +02:00
65fee858dd Temporary commit - work in progress 2022-05-19 01:06:09 +02:00
48 changed files with 378 additions and 1269 deletions

1
.gitignore vendored
View file

@ -1,3 +1,2 @@
tags
compile_commands.json
subprojects/wren/

3
.gitmodules vendored
View file

@ -0,0 +1,3 @@
[submodule "subprojects/wren/wren"]
path = subprojects/wren/wren
url = https://github.com/wren-lang/wren.git

View file

@ -117,19 +117,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,6 +130,16 @@ 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.
@ -164,8 +161,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

View file

@ -128,7 +128,7 @@ int main() {
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;

View file

@ -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;
}

View file

@ -1,5 +0,0 @@
executable('cpp_calls',
'main.cpp',
dependencies: wrenpp_dep,
install: false,
)

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020-2022, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -21,7 +21,6 @@
#include <chrono>
#include <thread>
#include <unistd.h>
#include <iostream>
#if defined(__GNU_LIBRARY__) && ((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17) || __GLIBC__ > 2)
# define HasSecureGetenv
@ -63,6 +62,8 @@ void user_get_env (wren::VM& vm, wren::ModuleAndName) {
} //unnamed namespace
int main() {
//typedef wren::ModuleAndName MN;
wren::DefConfiguration config;
wren::VM vm(&config, nullptr);
vm.callback_manager().add_callback(true, "main", "User", "get_env(_)", [](){return &user_get_env;});

View file

@ -108,7 +108,6 @@ System.print("vec_base_x modified by scripting: <%(vec_base_x.x), %(vec_base_x.y
int main() {
using wren::make_function_bindable;
using wren::make_foreign_class;
using wren::ConstructorParameters;
MyConf conf;
wren::VM vm(&conf, nullptr);
@ -124,8 +123,8 @@ int main() {
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
std::tuple<double, double, double>, //x,y,z constructor
std::tuple<> //default constructor
>);
vm.interpret("main", g_test_script);

View file

@ -2,4 +2,3 @@ subdir('dieroll')
subdir('greet')
subdir('calendar')
subdir('math_vector')
subdir('cpp_calls')

View file

@ -21,7 +21,6 @@
#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>
@ -80,28 +79,22 @@ namespace wren {
std::size_t operator()(TempClassName value) const;
};
class TypeIDHash {
public:
std::size_t operator()(TypeID tid) const;
template <typename F>
struct CppClassTypeHelper {
static void register_ifp(ClassManager&, const ClassNameOwning* name);
};
define_has_typedef(class_type, ClassType);
template <typename T, typename... Args>
struct CppClassTypeHelper<MakeForeignClass<T, Args...>> {
static void register_ifp(ClassManager& classman, const ClassNameOwning* name);
};
} //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 {
template <typename F> friend struct detail::CppClassTypeHelper;
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;
typedef std::unordered_map<ClassManagerNameHashType, const detail::ClassNameOwning*> TypeMap;
public:
ClassManager();
~ClassManager() noexcept;
@ -109,7 +102,7 @@ namespace wren {
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;
ModuleAndName wren_class_name_from_hash(ClassManagerNameHashType hash) const;
template <typename T>
ModuleAndName wren_class_name_from_type() const;
@ -120,27 +113,33 @@ namespace wren {
make_foreign_class_t
);
void add_type (TypeID hash, const detail::ClassNameOwning* name);
void add_type (ClassManagerNameHashType 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);
namespace detail {
template <typename F>
inline void CppClassTypeHelper<F>::register_ifp(ClassManager&, const ClassNameOwning*) {
//Nothing to do
}
template <typename T, typename... Args>
inline void CppClassTypeHelper<MakeForeignClass<T, Args...>>::register_ifp(
ClassManager& classman,
const ClassNameOwning* name
) {
const auto new_hash = type_hash<T>();
classman.add_type(new_hash, name);
}
} //namespace detail
template <typename F>
inline ClassManager& ClassManager::add_class_maker (std::string module_name, std::string_view class_name, F&& maker) {
auto it_new = this->add_class_maker_implem(module_name, class_name, std::forward<F>(maker));
const auto& owning_name = it_new->first;
detail::CppClassTypeHelper<std::decay_t<F>>::register_ifp(*this, &owning_name);
return *this;
}

View 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, std::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<std::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

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020-2022, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -23,12 +23,11 @@
# include "guess_class_name.hpp"
#endif
#include <utility>
#include <tuple>
#include <cassert>
#include <cstdint>
namespace wren {
template <typename... Args> struct ConstructorParameters { };
namespace detail {
template <typename T, typename... Args, int... Indices>
inline void construct_single (
@ -47,13 +46,13 @@ namespace wren {
template <typename T, typename... Args>
struct ForeignClassHelper;
template <typename T, typename... PackArgs, typename... Args>
struct ForeignClassHelper<T, ConstructorParameters<PackArgs...>, Args...> {
template <typename T, template <typename...> class Pack, typename... PackArgs, typename... Args>
struct ForeignClassHelper<T, Pack<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
//once we find a tuple-like parameter 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) {
@ -76,12 +75,7 @@ namespace wren {
return ConstructResult{1, true};
}
else {
if constexpr (sizeof...(Args) > 0) {
return ForeignClassHelper<T, Args...>::construct(vm, cardinality, memory);
}
else {
return ConstructResult{0, false};
}
return ForeignClassHelper<T, Args...>::construct(vm, cardinality, memory);
}
}
};
@ -124,8 +118,7 @@ namespace wren {
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) {
if constexpr (sizeof...(Args) > 0) {
constexpr auto dummy = AssertIfDuplicateValues<ForeignParamHelper<Args>::argument_count...>::value;
static_assert(dummy == 1); //always true
}
@ -150,14 +143,14 @@ namespace wren {
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 "} +
set(vm, 1, std::string{"No registered c++ constructor "} +
#if defined(WRENPP_WITH_NAME_GUESSING)
"for class " + guess_class_name<T>() + " " +
"for class " + guess_class_name<T>() + " " +
#endif
"takes " + std::to_string(result.parameter_count) +
" parameter" + (result.parameter_count == 1 ? "" : "s")
"takes " + std::to_string(result.parameter_count) +
" parameter" + (result.parameter_count == 1 ? "" : "s")
);
vm.abort_fiber(1);
}
};
ret.finalize = [](void* mem) {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,14 +1,13 @@
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',
'StringCRC32.hpp',
'strings_in_vector.hpp',
'type_id.hpp',
'wren_class_name_from_type.hpp',
'wren_types.hpp',
]

View file

@ -18,30 +18,19 @@
#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>
template <dhandy::bt::string S>
struct ModuleAndNameStaticStorage {
static constexpr dhandy::bt::string value = Str;
static constexpr const auto value = S;
};
[[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
//Non-owning, lightweight class for storing a module nome/class name pair.
//They are stored as consecutive strings within a single buffer with a
//null-char in-between and at the end so that each name is null-terminated
//and can be used with C APIs.
//Keep the size small, ideally within 2 registers size. Altering this might
@ -51,16 +40,9 @@ namespace wren {
//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 ModuleAndName (const char* base, std::uint32_t hash, std::size_t mod_name_len, std::size_t class_name_len);
constexpr const char* module_name_char() const noexcept { return m_base; }
constexpr const char* class_name_char() const noexcept { return m_base + 1 + m_mod_name_len; }
@ -71,19 +53,10 @@ namespace wren {
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::uint32_t 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 {
@ -105,59 +78,21 @@ namespace wren {
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) :
constexpr ModuleAndName::ModuleAndName (const char* base, std::uint32_t hash, std::size_t mod_name_len, std::size_t class_name_len) :
m_base(base),
m_hash(hash),
m_mod_name_len(mod_name_len),
m_class_name_len(class_name_len)
{}
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 {
constexpr ModuleAndName make_module_and_name() {
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 const char* data = detail::ModuleAndNameStaticStorage<S1 + string("\0") + S2>::value.data();
constexpr std::uint16_t s1_len = static_cast<std::uint16_t>(S1.size());
constexpr std::uint16_t s2_len = static_cast<std::uint16_t>(S2.size());
constexpr ModuleAndNameHashType hash = crc32c(
StaticStorage::value.data(),
StaticStorage::value.size()
);
constexpr std::uint32_t hash = 0; //not implemented yet
return ModuleAndName{data, hash, s1_len, s2_len};
}

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020-2022, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -18,10 +18,7 @@
#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>
@ -36,14 +33,8 @@ namespace wren {
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;
typedef 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>{};
@ -96,8 +87,6 @@ namespace wren {
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);
@ -149,14 +138,6 @@ namespace wren {
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));
@ -174,16 +155,16 @@ namespace wren {
template <typename T>
inline detail::GetTypeToRetType_t<T> get (VM& vm, int slot_num) {
return {&vm, foreign<T>(vm, slot_num), 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 <> 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);
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

View file

@ -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,9 +37,7 @@ 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;
@ -130,13 +122,11 @@ 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 bool string<S, Ch>::operator== (const string<S, Ch>& other) const {
@ -146,7 +136,7 @@ namespace dhandy {
template <std::size_t S, typename Ch>
template <std::size_t Start, std::size_t Len>
constexpr auto string<S, Ch>::substr() const {
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1), 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), 0) + string("");
}
} //namespace bt
} //namespace dhandy

View file

@ -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

View file

@ -18,27 +18,34 @@
#pragma once
#include "module_and_name.hpp"
#include "type_id.hpp"
#include "crc32.hpp"
#include <utility>
#include <string_view>
#include <cstddef>
namespace wren {
typedef std::size_t ClassManagerNameHashType;
class VM;
namespace detail {
//TODO: work in progress, make it take a type T and hash that for real
template<typename T>
inline ClassManagerNameHashType type_hash() {
static const ClassManagerNameHashType my_hash = 0;
return static_cast<ClassManagerNameHashType>(reinterpret_cast<std::uintptr_t>(&my_hash));
}
//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
ClassManagerNameHashType hash
);
template <typename T>
inline ModuleAndName wren_class_name_from_type (const VM& vm) {
return fetch_class_name_from_manager(vm, type_id<T>());
return fetch_class_name_from_manager(vm, type_hash<T>());
}
} //namespace detail
} //namespace wren

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020-2022, 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;

View file

@ -19,7 +19,7 @@
#include "detail/has_method.hpp"
#include "detail/error_type.hpp"
#include "detail/type_id.hpp"
#include "detail/StringCRC32.hpp"
#include "detail/wren_types.hpp"
#include "handle.hpp"
#include <memory>
@ -116,11 +116,11 @@ namespace wren {
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;
@ -151,6 +151,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>
@ -192,7 +198,7 @@ namespace wren {
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 +206,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 +215,7 @@ namespace wren {
static_cast<Configuration*>(conf),
to_callbacks(*conf),
nullptr,
type_id<std::nullptr_t>()
detail::type_id<std::nullptr_t>()
)
{
}
@ -220,7 +226,7 @@ namespace wren {
static_cast<Configuration*>(conf),
to_callbacks(*conf),
reinterpret_cast<void*>(user_data),
type_id<U>()
detail::type_id<U>()
)
{
}

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020-2022, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp is free software: you can redistribute it and/or modify
@ -26,8 +26,6 @@
#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>
#include <string_view>
#include <type_traits>
@ -48,11 +46,11 @@ namespace wren {
R call (VM& vm, 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);
T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
#if defined(WRENPP_WITH_NAME_GUESSING)
template <typename T, dhandy::bt::string Mod, typename... Args>
ForeignObject<T> make_wren_object(VM& vm, Args&&... args);
T* make_wren_object(VM& vm, Args&&... args);
#endif
void interpret (VM& vm, const std::string& module_name, const std::string& script);
@ -60,15 +58,22 @@ namespace wren {
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;
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
@ -76,7 +81,7 @@ namespace wren {
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>
@ -90,8 +95,8 @@ namespace wren {
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>
@ -103,8 +108,8 @@ namespace wren {
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)...);
T* obj = foreign<T>(vm, 0);
return (obj->*ConstMethod)(get<std::decay_t<Args>>(vm, Indices + 1)...);
}
};
template <typename R, typename... Args, R(*Function)(Args...)>
@ -116,7 +121,7 @@ namespace wren {
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)...);
return (*Function)(get<std::decay_t<Args>>(vm, Indices + 1)...);
}
};
@ -133,17 +138,13 @@ namespace wren {
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);
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));
R* const new_object = make_wren_object<R>(vm, wren_name, std::move(ret));
static_cast<void>(new_object);
}
}
@ -195,13 +196,15 @@ namespace wren {
inline R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args) {
using dhandy::bt::string;
const constexpr auto params = string("(") +
const constexpr char dummy_name_buff[N] = {0};
const constexpr auto params = string<N, char>(dummy_name_buff) +
string("(") +
((static_cast<void>(args), string(",_")) + ... + string("")).template substr<1>() +
string(")");
;
char cat_buff[params.size() + 1 + 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...);
}
@ -214,22 +217,16 @@ namespace wren {
}
template <typename T, typename... Args>
inline ForeignObject<T> make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
variable_ensure_slot(vm, mn, 0);
inline T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
variable(vm, mn, 0);
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
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;
}
T* const obj = new(mem) T{std::forward<Args>(args)...};
return obj;
}
#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) {
inline T* make_wren_object(VM& vm, Args&&... args) {
return make_wren_object<T>(
vm,
MN<Mod, g_guessed_class_name<T>>,

View file

@ -1,6 +1,6 @@
project('wrenpp', 'cpp',
version: '0.2.0',
meson_version: '>=0.55.0',
version: '0.1.3',
meson_version: '>=0.49.2',
default_options: ['buildtype=release', 'cpp_std=c++20', 'b_ndebug=if-release']
)
@ -40,17 +40,46 @@ elif os == 'gnu' and arch == 'aarch64'
func_ptr_size = 8
endif
global_compiler_opts = []
compiler_opts = []
if get_option('wrenpp_with_name_guessing')
global_compiler_opts += ['-DWRENPP_WITH_NAME_GUESSING']
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())
project_config_file = configure_file(
input: 'src/pvt_config.h.in',
output: 'pvt_config.h',
configuration: conf
)
subdir('include')
subdir('src')
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',
'src/callback_manager.cpp',
'src/class_manager.cpp',
'src/wren_class_name_from_type.cpp',
dependencies: [wren_dep],
include_directories: public_incl,
install: (not meson.is_subproject() or get_option('default_library')=='shared'),
c_args: compiler_opts,
cpp_args: compiler_opts,
)
wrenpp_dep = declare_dependency(
link_with: wrenpp,
include_directories: public_incl,
compile_args: compiler_opts,
)
if get_option('build_examples')
subdir('examples')

View file

@ -40,6 +40,7 @@ namespace wren {
ClassNameOwning::operator ModuleAndName() const {
return ModuleAndName{
this->raw_buffer(),
0, //TODO: replace with hash
this->module_name().size(),
this->class_name().size()
};
@ -78,15 +79,6 @@ namespace wren {
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;
@ -126,15 +118,15 @@ namespace wren {
return retval;
}
void ClassManager::add_type (TypeID hash, const detail::ClassNameOwning* name) {
void ClassManager::add_type (ClassManagerNameHashType hash, const detail::ClassNameOwning* name) {
using detail::TempClassName;
assert(m_types.count(hash) == 0 or *m_types.at(hash) == *name);
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 {
ModuleAndName ClassManager::wren_class_name_from_hash(ClassManagerNameHashType hash) const {
const auto it_found = m_types.find(hash);
if (m_types.cend() != it_found) {
const detail::ClassNameOwning* const name = it_found->second;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,
)

View file

@ -21,8 +21,6 @@
.global g_dynafunc
.global g_dynafunc_end
.section .note.GNU-stack,"",@progbits
.text
g_dynafunc:
ldr x0, .+20

View file

@ -21,8 +21,6 @@
.global g_dynafunc
.global g_dynafunc_end
.section .note.GNU-stack,"",@progbits
.text
g_dynafunc:
//VM pointer, parameter 1

View file

@ -111,14 +111,15 @@ namespace wren {
);
const CharVec* source_mem;
if (dst.cend() != it_found && std::equal(it_found->cbegin(), it_found->cend(), new_entry.cbegin(), new_entry.cend())) {
if (dst.cend() != it_found) {
assert(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()};
return {source_mem->data(), 0, mod_name.size(), cls_name.size()};
}
} //unnamed namespace

View file

@ -1,4 +1,4 @@
/* Copyright 2020-2024, Michele Santullo
/* Copyright 2020-2022, 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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -162,8 +162,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;
}
@ -181,10 +180,10 @@ namespace wren {
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 +197,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 +205,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,7 +281,7 @@ 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 {

View file

@ -89,9 +89,4 @@ namespace wren {
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

View file

@ -6,7 +6,7 @@ namespace wren {
namespace detail {
ModuleAndName fetch_class_name_from_manager (
const VM& vm,
TypeID hash
ClassManagerNameHashType hash
) {
return vm.class_manager().wren_class_name_from_hash(hash);
}

View file

@ -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

View file

@ -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

@ -0,0 +1 @@
Subproject commit 4ffe2ed38b238ff410e70654cbe38883f7533d3f