diff --git a/CMakeLists.txt b/CMakeLists.txt index a80a16f..c3608cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.21) include(${CMAKE_ROOT}/Modules/ExternalProject.cmake) project(PyG2O) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) # Specify build type @@ -63,7 +63,9 @@ endif() file(GLOB_RECURSE SOURCE "include/*.h" - + + "src/NoNut/core/*.h" + "src/NoNut/core/*.cpp" "src/*.h" "src/*.cpp" "src/events/*.h" diff --git a/src/NoNut/core/Array.cpp b/src/NoNut/core/Array.cpp new file mode 100644 index 0000000..7caa582 --- /dev/null +++ b/src/NoNut/core/Array.cpp @@ -0,0 +1,20 @@ +#include "CommonHeader.h" +#include "Array.h" + +namespace nonut +{ + Array::Array(const SQObject object) : object(object), cachedSize(size()) + { + } + + Array::~Array() = default; + + size_t Array::size() const + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_pushobject(vm, object); + const auto result = sq_getsize(vm, -1); + sq_pop(vm, 1); + return static_cast(result); + } +} diff --git a/src/NoNut/core/Array.h b/src/NoNut/core/Array.h new file mode 100644 index 0000000..ac4496c --- /dev/null +++ b/src/NoNut/core/Array.h @@ -0,0 +1,51 @@ +#ifndef NONUT_CORE_ARRAY_H +#define NONUT_CORE_ARRAY_H +#include "CommonHeader.h" + +#include "Utils.h" +#include + +namespace nonut +{ + class Array + { + public: + explicit Array(SQObject object); + ~Array(); + + [[nodiscard]] size_t size() const; + + template + T get(const String index) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + T result{}; + sq_pushobject(vm, object); + sq_pushstring(vm, index.c_str(), index.length()); + + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); + return result; + } + if constexpr (std::is_same_v) + { + const SQChar* intermediateResult = nullptr; + sq_getstring(vm, -1, &intermediateResult); + result = intermediateResult; + } + else + { + sqGetValue(vm, -1, &result); + } + + sq_pop(vm, 2); + return result; + } + + private: + SQObject object; + size_t cachedSize; + }; +} +#endif // NONUT_CORE_ARRAY_H diff --git a/src/NoNut/core/Bind.h b/src/NoNut/core/Bind.h new file mode 100644 index 0000000..28b87c4 --- /dev/null +++ b/src/NoNut/core/Bind.h @@ -0,0 +1,31 @@ +#ifndef NONUT_CORE_BIND_H +#define NONUT_CORE_BIND_H + +#include "CommonHeader.h" +#include + +namespace nonut +{ + //TODO: Finish Bind and remove placeholder + + class Bind + { + public: + static void registerFunction(String funcName, const SQFUNCTION func, size_t funcSize) + { + const auto top = sq_gettop(vm); + sq_pushroottable(vm); + sq_pushstring(vm, funcName.c_str(), funcName.length()); + sq_newclosure(vm, func, 0); //create a new function + sq_newslot(vm, -3, SQFalse); + sq_settop(vm, top); + } + + //template + //static void Function(String functionName, F& function) + //{ + // + //} + }; +} +#endif // NONUT_CORE_BIND_H diff --git a/src/NoNut/core/Class.cpp b/src/NoNut/core/Class.cpp new file mode 100644 index 0000000..c0bb583 --- /dev/null +++ b/src/NoNut/core/Class.cpp @@ -0,0 +1,63 @@ +#include "CommonHeader.h" +#include "Class.h" + +namespace nonut +{ + Class::Class(const String& className, const SQObject classObjectInstance) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + if (classObjectInstance._type == OT_NULL) + { + const auto top = sq_gettop(vm); + + sq_pushroottable(vm); //push root table + sq_pushstring(vm, className.c_str(), className.length()); //push class name + + if (sq_get(vm, -2) == SQ_OK) //retrieve class + { + sq_getstackobj(vm, -1, &classObject); + sq_addref(vm, &classObject); + if (sq_createinstance(vm, -1) == SQ_OK) //create class instance + { + //1. Get object ptr + sq_getstackobj(vm, -1, &this->classObjectInstance); //retrieve object + sq_addref(vm, &this->classObjectInstance); + //Add ref thanks to which object will not be immediately deleted + sq_pop(vm, 1); // pop class instance + } + } + sq_settop(vm, top); // TODO: FIX LEAK PROPERLY + } + else + { + this->classObjectInstance = classObjectInstance; + const auto top = sq_gettop(vm); + sq_addref(vm, &this->classObjectInstance); + + sq_pushroottable(vm); //push root table + sq_pushstring(vm, className.c_str(), className.length()); //push class name + + if (sq_get(vm, -2) == SQ_OK) //retrieve class + { + sq_getstackobj(vm, -1, &classObject); + sq_addref(vm, &classObject); + } + + sq_settop(vm, top); + } + } + + Class::~Class() + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_release(vm, &classObject); + sq_release(vm, &classObjectInstance); + sq_resetobject(&classObject); + sq_resetobject(&classObjectInstance); + } + + SQObject Class::getInstance() const + { + return classObjectInstance; + } +} diff --git a/src/NoNut/core/Class.h b/src/NoNut/core/Class.h new file mode 100644 index 0000000..d5cdde1 --- /dev/null +++ b/src/NoNut/core/Class.h @@ -0,0 +1,42 @@ +#ifndef NONUT_CORE_CLASS_H +#define NONUT_CORE_CLASS_H +#include "CommonHeader.h" +#include + +#include "Function.h" +// ReSharper disable once CppUnusedIncludeDirective +#include "Property.h" +#include "Instance.h" + +#define METHOD_CTOR(methodName) methodName(#methodName, this->classObjectInstance, this->classObject) +#define PROPERTY_CTOR(propertyName) propertyName(#propertyName, this->classObjectInstance) +#define COPY_CTOR(type) type(const type& other) : type(other.getInstance()){} \ + type& operator=(const type& other) = delete + +namespace nonut +{ + static constexpr auto CONSTRUCTOR_NAME = "constructor"; + + class Class : public Instance + { + public: + Class(const String& className, SQObject classObjectInstance = SQ_NULL); + virtual ~Class(); + + [[nodiscard]] SQObject getInstance() const override; + + protected: + // Object holding information about class + SQObject classObject{}; + // Class object instance + SQObject classObjectInstance{}; + + template + void classCtor(Args ... args) + { + Function ctor(CONSTRUCTOR_NAME, classObjectInstance, classObject); + ctor(std::forward(args)...); + } + }; +} +#endif // NONUT_CORE_CLASS_H diff --git a/src/NoNut/core/CommonHeader.h b/src/NoNut/core/CommonHeader.h new file mode 100644 index 0000000..34ac6c5 --- /dev/null +++ b/src/NoNut/core/CommonHeader.h @@ -0,0 +1,21 @@ +#ifndef CORE_COMMONHEADER_H_ +#define CORE_COMMONHEADER_H_ + +#include "sqrat.h" + +namespace nonut +{ + using Int = SQInteger; + using UInt = SQUnsignedInteger; + using UInt32 = SQUnsignedInteger32; + using Float = SQFloat; + using Bool = SQBool; + using String = std::string; + + constexpr SQObject SQ_NULL{ OT_NULL }; +} + +namespace nonut::g2o{} +namespace g2o = nonut::g2o; + +#endif // CORE_COMMONHEADER_H_ diff --git a/src/NoNut/core/Constant.cpp b/src/NoNut/core/Constant.cpp new file mode 100644 index 0000000..75707b3 --- /dev/null +++ b/src/NoNut/core/Constant.cpp @@ -0,0 +1,14 @@ +#include "Constant.h" + +namespace nonut +{ + SQObject getConstTable() + { + SQObject obj; + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_pushconsttable(vm); + sq_getstackobj(vm, -1, &obj); + sq_pop(vm, 1); // No addref needed, since the consttable is always around + return obj; + } +} diff --git a/src/NoNut/core/Constant.h b/src/NoNut/core/Constant.h new file mode 100644 index 0000000..db10fc1 --- /dev/null +++ b/src/NoNut/core/Constant.h @@ -0,0 +1,10 @@ +#ifndef NONUT_CORE_CONSTANT_H +#define NONUT_CORE_CONSTANT_H +#include "CommonHeader.h" +#include + +namespace nonut +{ + SQObject getConstTable(); +}; +#endif // NONUT_CORE_CONSTANT_H diff --git a/src/NoNut/core/Function.h b/src/NoNut/core/Function.h new file mode 100644 index 0000000..a40e5b2 --- /dev/null +++ b/src/NoNut/core/Function.h @@ -0,0 +1,166 @@ +#ifndef NONUT_CORE_FUNCTION_H +#define NONUT_CORE_FUNCTION_H + +#include +#include + +#include +#include "Utils.h" + +#define FUNCTION_CTOR(function) function(#function) + +namespace nonut +{ + class Class; + + template + class Function + { + public: + // Ctor for functions + Function(const String& functionName, const SQObject env = getRootTable()) : envObj(env) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_pushobject(vm, envObj); + sq_pushstring(vm, functionName.c_str(), functionName.length()); + + // get the function from the root table + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); + throw; + } + + // check the type + if (const SQObjectType value_type = sq_gettype(vm, -1); value_type != OT_CLOSURE && value_type != + OT_NATIVECLOSURE) + { + sq_pop(vm, 2); + throw; + } + + // get function and add ref + sq_getstackobj(vm, -1, &funcObj); + sq_addref(vm, &funcObj); + + sq_pop(vm, 2); + } + + // Ctor for class methods + Function(const String& functionName, const SQObject classObjectInstance, + const SQObject classObject) : envObj(classObjectInstance) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + isClassMethod = true; // Prevent release of the resources cause we don't own them + sq_pushobject(vm, classObject); + sq_pushstring(vm, functionName.c_str(), functionName.length()); + + // get the function from the root table + if (SQ_FAILED(sq_get(vm, -2))) + { + sq_pop(vm, 1); + throw; + } + + // check the type + if (const SQObjectType value_type = sq_gettype(vm, -1); value_type != OT_CLOSURE && value_type != + OT_NATIVECLOSURE) + { + sq_pop(vm, 2); + throw; + } + + // get function and add ref + sq_getstackobj(vm, -1, &funcObj); + sq_addref(vm, &funcObj); + + sq_pop(vm, 2); + } + + ~Function() + { + if (!isClassMethod) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_release(vm, &funcObj); + sq_release(vm, &envObj); + sq_resetobject(&funcObj); + sq_resetobject(&envObj); + } + } + + ReturnType operator()(Args ... args) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + const auto top = sq_gettop(vm); + sq_pushobject(vm, funcObj); + sq_pushobject(vm, envObj); + auto debug = sq_gettop(vm); + (sqPushValue(vm, args), ...); + + if constexpr (std::is_same_v) + { + debug = sq_gettop(vm); + auto returnCode = sq_call(vm, ARG_COUNT + 1, SQFalse, SQFalse); // TODO: HANDLE ERROR RETURN CODE + sq_pop(vm, 2); + sq_settop(vm, top); + return void(); + } + else + { + auto returnCode = sq_call(vm, ARG_COUNT + 1, SQTrue, SQFalse); // TODO: HANDLE ERROR RETURN CODE + + std::optional result; + + if constexpr (std::derived_from) + { + result = std::make_optional(); + auto intermediateResult = returnVar(); + result.value().convert(intermediateResult); + sq_release(vm, &intermediateResult); + sq_resetobject(&intermediateResult); + } + else if constexpr (std::derived_from) + { + auto intermediateResult = returnVar(); + //result = std::make_optional(ReturnType(intermediateResult)); + result.emplace(ReturnType(intermediateResult)); + + sq_release(vm, &intermediateResult); + sq_resetobject(&intermediateResult); + } + else + { + result = std::make_optional(returnVar()); + } + + sq_pop(vm, 2); + sq_settop(vm, top); + return result.value(); + } + } + + [[nodiscard]] SQObject getObject() const + { + return funcObj; + } + + private: + SQObject funcObj{}; + SQObject envObj{}; + bool isClassMethod = false; + static constexpr auto ARG_COUNT{sizeof...(Args)}; + + static SQObject getRootTable() + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + SQObject rootTable{}; + sq_pushroottable(vm); + sq_getstackobj(vm, -1, &rootTable); + sq_addref(vm, &rootTable); + sq_pop(vm, 1); // pop root table + return rootTable; + } + }; +} +#endif // NONUT_CORE_FUNCTION_H diff --git a/src/NoNut/core/Instance.h b/src/NoNut/core/Instance.h new file mode 100644 index 0000000..8123793 --- /dev/null +++ b/src/NoNut/core/Instance.h @@ -0,0 +1,12 @@ +#ifndef NONUT_CORE_INSTANCE_H +#define NONUT_CORE_INSTANCE_H + +namespace nonut +{ + class Instance + { + public: + [[nodiscard]] virtual SQObject getInstance() const = 0; + }; +} +#endif //NONUT_CORE_INSTANCE_H diff --git a/src/NoNut/core/Property.h b/src/NoNut/core/Property.h new file mode 100644 index 0000000..6bd2d29 --- /dev/null +++ b/src/NoNut/core/Property.h @@ -0,0 +1,135 @@ +#ifndef NONUT_CORE_PROPERTY_H +#define NONUT_CORE_PROPERTY_H + +#include + +#include +#include "Utils.h" +#include "Class.h" + +namespace nonut +{ + template + T getProperty(const SQObject& object, const String& name) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + const auto top = sq_gettop(vm); + + sq_pushobject(vm, object); + sq_pushstring(vm, name.c_str(), name.length()); + + if constexpr (std::derived_from) + { + SQObject intermediateResult{}; + if (SQ_SUCCEEDED(sq_get(vm, -2))) // pops property + { + sqGetValue(vm, -1, &intermediateResult); + sq_pop(vm, 1); // pops result + } + + sq_pop(vm, 1); // pops object + sq_settop(vm, top); + return T(intermediateResult); + } + else + { + T result{}; + + if (SQ_SUCCEEDED(sq_get(vm, -2))) // pops property + { + sqGetValue(vm, -1, &result); + sq_pop(vm, 1); // pops result + } + + sq_pop(vm, 1); // pops object + sq_settop(vm, top); + return result; + } + } + + template <> + inline bool getProperty(const SQObject& object, const String& name) + { + return getProperty(object, name); + } + + template <> + inline String getProperty(const SQObject& object, const String& name) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + const Int top = sq_gettop(vm); + const SQChar* result{}; + + sq_pushobject(vm, object); + sq_pushstring(vm, name.c_str(), name.length()); + + if (SQ_SUCCEEDED(sq_get(vm, -2))) // pops property + { + sq_getstring(vm, -1, &result); + sq_pop(vm, 1); // pops result + } + + sq_pop(vm, 1); // pops object + sq_settop(vm, top); + return result; + } + + + template + void setProperty(SQObject& object, String& name, T value) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_pushobject(vm, object); + sq_pushstring(vm, name.c_str(), name.length()); + if constexpr (std::derived_from) + { + sqPushValue(vm, value.getInstance()); + } + else + { + sqPushValue(vm, value); + } + + + auto result = sq_set(vm, -3); // pops name and value + + sq_pop(vm, 1); // pops object + } + + template + class Property + { + public: + Property(String propertyName, const SQObject object) : object(object), + propertyName(std::move(propertyName)) + { + } + + Property& operator=(const T& other) noexcept + { + set(other); + return *this; + } + + operator T() + { + return this->get(); + } + + [[nodiscard]] T get() const + { + return getProperty(object, propertyName); + } + + void set(T value) + { + static_assert(!IsReadOnly, "Cannot set read-only property."); + setProperty(object, propertyName, value); + } + + private: + SQObject object; + String propertyName; + }; +} +#endif // NONUT_CORE_PROPERTY_H diff --git a/src/NoNut/core/StaticClass.cpp b/src/NoNut/core/StaticClass.cpp new file mode 100644 index 0000000..e790a75 --- /dev/null +++ b/src/NoNut/core/StaticClass.cpp @@ -0,0 +1,32 @@ +#include "StaticClass.h" + +namespace nonut +{ + StaticClass::StaticClass(const String& className) + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + const auto top = sq_gettop(vm); + + sq_pushroottable(vm); //push root table + sq_pushstring(vm, className.c_str(), className.length()); //push class instance name + + if (sq_get(vm, -2) == SQ_OK) //retrieve class instance + { + sq_getstackobj(vm, -1, &classObjectInstance); + sq_addref(vm, &classObjectInstance); + sq_getclass(vm, -1); + sq_getstackobj(vm, -1, &classObject); + sq_addref(vm, &classObject); + } + sq_settop(vm, top); // TODO: FIX LEAK PROPERLY + } + + StaticClass::~StaticClass() + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + sq_release(vm, &classObject); + sq_release(vm, &classObjectInstance); + sq_resetobject(&classObject); + sq_resetobject(&classObjectInstance); + } +} diff --git a/src/NoNut/core/StaticClass.h b/src/NoNut/core/StaticClass.h new file mode 100644 index 0000000..3df68a6 --- /dev/null +++ b/src/NoNut/core/StaticClass.h @@ -0,0 +1,25 @@ +#ifndef NONUT_CORE_STATIC_CLASS_H +#define NONUT_CORE_STATIC_CLASS_H + +#include "Function.h" +#include "Property.h" + +#define METHOD_CTOR(methodName) methodName(#methodName, this->classObjectInstance, this->classObject) +#define PROPERTY_CTOR(propertyName) propertyName(#propertyName, this->classObjectInstance) + +namespace nonut +{ + class StaticClass + { + public: + explicit StaticClass(const String& className); + ~StaticClass(); + + protected: + // Object holding information about class + SQObject classObject{}; + // Class object instance + SQObject classObjectInstance{}; + }; +} +#endif // NONUT_CORE_STATIC_CLASS_H diff --git a/src/NoNut/core/StringHelpers.h b/src/NoNut/core/StringHelpers.h new file mode 100644 index 0000000..27366c9 --- /dev/null +++ b/src/NoNut/core/StringHelpers.h @@ -0,0 +1,347 @@ +#ifndef NONUT_CORE_STRING_HELPERS_H +#define NONUT_CORE_STRING_HELPERS_H +#include +#include + +namespace nonut +{ + const std::unordered_map WINDOWS1250_UTF8_MAP + { + {'\x80', "\xe2\x82\xac"}, // euro sign + {'\x82', "\xe2\x80\x9a"}, // lower quotation mark + {'\x84', "\xe2\x80\x9e"}, // lower quotation marks + {'\x85', "\xe2\x80\xa6"}, // ellipsis + {'\x86', "\xe2\x80\xa0"}, // dagger + {'\x87', "\xe2\x80\xa1"}, // double dagger + {'\x89', "\xe2\x80\xb0"}, // per mille + {'\x8a', "\xc5\xa0"}, // S with caron + {'\x8b', "\xe2\x80\xb9"}, // left guillemet + {'\x8c', "\xc5\x9a"}, // S with acute + {'\x8d', "\xc5\xa4"}, // T with caron + {'\x8e', "\xc5\xbd"}, // Z with caron + {'\x8f', "\xc5\xb9"}, // Z with acute + + {'\x91', "\xe2\x80\x98"}, // upper quotation mark (opening) + {'\x92', "\xe2\x80\x99"}, // upper quotation mark (closing) + {'\x93', "\xe2\x80\x9c"}, // upper quotation marks (opening) + {'\x94', "\xe2\x80\x9d"}, // upper quotation marks (closing) + {'\x95', "\xe2\x80\xa2"}, // bullet sign + {'\x96', "\xe2\x80\x93"}, // en dash + {'\x97', "\xe2\x80\x94"}, // em dash + {'\x99', "\xe2\x84\xa2"}, // trademark sign + {'\x9a', "\xc5\xa1"}, // s with caron + {'\x9b', "\xe2\x80\xba"}, // right guillemet + {'\x9c', "\xc5\x9b"}, // s with acute + {'\x9d', "\xc5\xa5"}, // t with caron + {'\x9e', "\xc5\xbe"}, // z with caron + {'\x9f', "\xc5\xba"}, // z with acute + + {'\xa0', "\x20"}, // NBSP + {'\xa1', "\xcb\x87"}, // caron + {'\xa2', "\xcb\x98"}, // breve + {'\xa3', "\xc5\x81"}, // L with stroke + {'\xa4', "\xc2\xa4"}, // currency sign + {'\xa5', "\xc4\x84"}, // A with ogonek + {'\xa6', "\xc2\xa6"}, // vertical bar + {'\xa7', "\xc2\xa7"}, // section sign + {'\xa8', "\xc2\xa8"}, // diaeresis + {'\xa9', "\xc2\xa9"}, // copyright sign + {'\xaa', "\xc5\x9e"}, // S-cedilla + {'\xab', "\xc2\xab"}, // left guillemets + {'\xac', "\xc2\xac"}, // negation + {'\xad', "\xc2\xad"}, // soft hyphen + {'\xae', "\xc2\xae"}, // registered trademark sign + {'\xaf', "\xc5\xbb"}, // Z with dot above + + {'\xb0', "\xc2\xb0"}, // degree sign + {'\xb1', "\xc2\xb1"}, // plus-minus sign + {'\xb2', "\xcb\x9b"}, // ogonek + {'\xb3', "\xc5\x82"}, // l with stroke + {'\xb4', "\xc2\xb4"}, // acute accent + {'\xb5', "\xc2\xb5"}, // Mu letter + {'\xb6', "\xc2\xb6"}, // pilcrow + {'\xb7', "\xc2\xb7"}, // middle dot + {'\xb8', "\xc2\xb8"}, // cedilla + {'\xb9', "\xc4\x85"}, // a with ogonek + {'\xba', "\xc5\x9f"}, // s-cedilla + {'\xbb', "\xc2\xbb"}, // right guillemets + {'\xbc', "\xc4\xbd"}, // Lj- + {'\xbd', "\xcb\x9d"}, // double acute accent + {'\xbe', "\xc4\xbe"}, // lj- + {'\xbf', "\xc5\xbc"}, // z with dot above + + {'\xc0', "\xc5\x94"}, // R with acute + {'\xc1', "\xc3\x81"}, // A with acute + {'\xc2', "\xc3\x82"}, // A-circumflex + {'\xc3', "\xc4\x82"}, // A-breve + {'\xc4', "\xc3\x84"}, // A with diaeresis + {'\xc5', "\xc4\xb9"}, // L with acute + {'\xc6', "\xc4\x86"}, // C with acute + {'\xc7', "\xc3\x87"}, // C-cedilla + {'\xc8', "\xc4\x8c"}, // C with caron + {'\xc9', "\xc3\x89"}, // C with acute + {'\xca', "\xc4\x98"}, // E with ogonek + {'\xcb', "\xc3\x8b"}, // E with diaeresis + {'\xcc', "\xc3\x8b"}, // E with caron + {'\xcd', "\xc3\x8d"}, // I with acute + {'\xce', "\xc3\x8e"}, // I-circumflex + {'\xcf', "\xc4\x8e"}, // D with caron + + {'\xd0', "\xc4\x90"}, // crossed D + {'\xd1', "\xc5\x83"}, // N with acute + {'\xd2', "\xc5\x87"}, // N with caron + {'\xd3', "\xc3\x93"}, // O with acute + {'\xd4', "\xc3\x94"}, // O-circumflex + {'\xd5', "\xc5\x90"}, // O with dobule accute + {'\xd6', "\xc3\x96"}, // O with diaeresis + {'\xd7', "\xc3\x97"}, // multiplication sign + {'\xd8', "\xc5\x98"}, // R with caron + {'\xd9', "\xc5\xae"}, // U with diacritic + {'\xda', "\xc3\x9a"}, // U with acute + {'\xdb', "\xc5\xb0"}, // U with double accent + {'\xdc', "\xc3\x9c"}, // U with diaeresis + {'\xdd', "\xc3\x9d"}, // Y with acute + {'\xdf', "\xc5\xa2"}, // T-cedilla + + {'\xe0', "\xc5\x95"}, // r with acute + {'\xe1', "\xc3\xa1"}, // a with acute + {'\xe2', "\xc3\xa2"}, // a-circumflex + {'\xe3', "\xc4\x83"}, // a-breve + {'\xe4', "\xc3\xa4"}, // a with diaeresis + {'\xe5', "\xc4\xba"}, // l with acute + {'\xe6', "\xc4\x87"}, // c with acute + {'\xe7', "\xc3\xa7"}, // c-cedilla + {'\xe8', "\xc4\x8d"}, // c with caron + {'\xe9', "\xc3\xa9"}, // c with acute + {'\xea', "\xc4\x99"}, // e with ogonek + {'\xeb', "\xc3\xab"}, // e with diaeresis + {'\xec', "\xc4\x9b"}, // e with caron + {'\xed', "\xc3\xad"}, // i with acute + {'\xee', "\xc3\xae"}, // i-circumflex + {'\xef', "\xc4\x8f"}, // d with caron + + {'\xf0', "\xc4\x91"}, // crossed d + {'\xf1', "\xc5\x84"}, // n with acute + {'\xf2', "\xc5\x88"}, // n with caron + {'\xf3', "\xc3\xb3"}, // o with acute + {'\xf4', "\xc3\xb4"}, // o-circumflex + {'\xf5', "\xc5\x91"}, // o with double accent + {'\xf6', "\xc3\xb6"}, // o with diaeresis + {'\xf7', "\xc3\xb7"}, // division sign + {'\xf8', "\xc5\x99"}, // r with caron + {'\xf9', "\xc5\xaf"}, // u with diacritic + {'\xfa', "\xc3\xba"}, // u with acute + {'\xfb', "\xc5\xb1"}, // u with double accent + {'\xfc', "\xc3\xbc"}, // u with diaeresis + {'\xfd', "\xc3\xbd"}, // y with acute + {'\xfe', "\xc5\xa3"}, // t-cedilla + {'\xff', "\xcb\x99"}, // diactric dot + }; + + const std::unordered_map UTF8_WINDOWS1250_MAP + { + {"\xe2\x82\xac", '\x80'}, // euro sign + {"\xe2\x80\x9a", '\x82'}, // lower quotation mark + {"\xe2\x80\x9e", '\x84'}, // lower quotation marks + {"\xe2\x80\xa6", '\x85'}, // ellipsis + {"\xe2\x80\xa0", '\x86'}, // dagger + {"\xe2\x80\xa1", '\x87'}, // double dagger + {"\xe2\x80\xb0", '\x89'}, // per mille + {"\xc5\xa0", '\x8a'}, // S with caron + {"\xe2\x80\xb9", '\x8b'}, // left guillemet + {"\xc5\x9a", '\x8c'}, // S with acute + {"\xc5\xa4", '\x8d'}, // T with caron + {"\xc5\xbd", '\x8e'}, // Z with caron + {"\xc5\xb9", '\x8f'}, // Z with acute + + {"\xe2\x80\x98", '\x91'}, // upper quotation mark (opening) + {"\xe2\x80\x99", '\x92'}, // upper quotation mark (closing) + {"\xe2\x80\x9c", '\x93'}, // upper quotation marks (opening) + {"\xe2\x80\x9d", '\x94'}, // upper quotation marks (closing) + {"\xe2\x80\xa2", '\x95'}, // bullet sign + {"\xe2\x80\x93", '\x96'}, // en dash + {"\xe2\x80\x94", '\x97'}, // em dash + {"\xe2\x84\xa2", '\x99'}, // trademark sign + {"\xc5\xa1", '\x9a'}, // s with caron + {"\xe2\x80\xba", '\x9b'}, // right guillemet + {"\xc5\x9b", '\x9c'}, // s with acute + {"\xc5\xa5", '\x9d'}, // t with caron + {"\xc5\xbe", '\x9e'}, // z with caron + {"\xc5\xba", '\x9f'}, // z with acute + + {"\x20", '\xa0'}, // NBSP + {"\xcb\x87", '\xa1'}, // caron + {"\xcb\x98", '\xa2'}, // breve + {"\xc5\x81", '\xa3'}, // L with stroke + {"\xc2\xa4", '\xa4'}, // currency sign + {"\xc4\x84", '\xa5'}, // A with ogonek + {"\xc2\xa6", '\xa6'}, // vertical bar + {"\xc2\xa7", '\xa7'}, // section sign + {"\xc2\xa8", '\xa8'}, // diaeresis + {"\xc2\xa9", '\xa9'}, // copyright sign + {"\xc5\x9e", '\xaa'}, // S-cedilla + {"\xc2\xab", '\xab'}, // left guillemets + {"\xc2\xac", '\xac'}, // negation + {"\xc2\xad", '\xad'}, // soft hyphen + {"\xc2\xae", '\xae'}, // registered trademark sign + {"\xc5\xbb", '\xaf'}, // Z with dot above + + {"\xc2\xb0", '\xb0'}, // degree sign + {"\xc2\xb1", '\xb1'}, // plus-minus sign + {"\xcb\x9b", '\xb2'}, // ogonek + {"\xc5\x82", '\xb3'}, // l with stroke + {"\xc2\xb4", '\xb4'}, // acute accent + {"\xc2\xb5", '\xb5'}, // Mu letter + {"\xc2\xb6", '\xb6'}, // pilcrow + {"\xc2\xb7", '\xb7'}, // middle dot + {"\xc2\xb8", '\xb8'}, // cedilla + {"\xc4\x85", '\xb9'}, // a with ogonek + {"\xc5\x9f", '\xba'}, // s-cedilla + {"\xc2\xbb", '\xbb'}, // right guillemets + {"\xc4\xbd", '\xbc'}, // Lj- + {"\xcb\x9d", '\xbd'}, // double acute accent + {"\xc4\xbe", '\xbe'}, // lj- + {"\xc5\xbc", '\xbf'}, // z with dot above + + {"\xc5\x94", '\xc0'}, // R with acute + {"\xc3\x81", '\xc1'}, // A with acute + {"\xc3\x82", '\xc2'}, // A-circumflex + {"\xc4\x82", '\xc3'}, // A-breve + {"\xc3\x84", '\xc4'}, // A with diaeresis + {"\xc4\xb9", '\xc5'}, // L with acute + {"\xc4\x86", '\xc6'}, // C with acute + {"\xc3\x87", '\xc7'}, // C-cedilla + {"\xc4\x8c", '\xc8'}, // C with caron + {"\xc3\x89", '\xc9'}, // C with acute + {"\xc4\x98", '\xca'}, // E with ogonek + {"\xc3\x8b", '\xcb'}, // E with diaeresis + {"\xc3\x8b", '\xcc'}, // E with caron + {"\xc3\x8d", '\xcd'}, // I with acute + {"\xc3\x8e", '\xce'}, // I-circumflex + {"\xc4\x8e", '\xcf'}, // D with caron + + {"\xc4\x90", '\xd0'}, // crossed D + {"\xc5\x83", '\xd1'}, // N with acute + {"\xc5\x87", '\xd2'}, // N with caron + {"\xc3\x93", '\xd3'}, // O with acute + {"\xc3\x94", '\xd4'}, // O-circumflex + {"\xc5\x90", '\xd5'}, // O with dobule accute + {"\xc3\x96", '\xd6'}, // O with diaeresis + {"\xc3\x97", '\xd7'}, // multiplication sign + {"\xc5\x98", '\xd8'}, // R with caron + {"\xc5\xae", '\xd9'}, // U with diacritic + {"\xc3\x9a", '\xda'}, // U with acute + {"\xc5\xb0", '\xdb'}, // U with double accent + {"\xc3\x9c", '\xdc'}, // U with diaeresis + {"\xc3\x9d", '\xdd'}, // Y with acute + {"\xc5\xa2", '\xdf'}, // T-cedilla + + {"\xc5\x95", '\xe0'}, // r with acute + {"\xc3\xa1", '\xe1'}, // a with acute + {"\xc3\xa2", '\xe2'}, // a-circumflex + {"\xc4\x83", '\xe3'}, // a-breve + {"\xc3\xa4", '\xe4'}, // a with diaeresis + {"\xc4\xba", '\xe5'}, // l with acute + {"\xc4\x87", '\xe6'}, // c with acute + {"\xc3\xa7", '\xe7'}, // c-cedilla + {"\xc4\x8d", '\xe8'}, // c with caron + {"\xc3\xa9", '\xe9'}, // c with acute + {"\xc4\x99", '\xea'}, // e with ogonek + {"\xc3\xab", '\xeb'}, // e with diaeresis + {"\xc4\x9b", '\xec'}, // e with caron + {"\xc3\xad", '\xed'}, // i with acute + {"\xc3\xae", '\xee'}, // i-circumflex + {"\xc4\x8f", '\xef'}, // d with caron + + {"\xc4\x91", '\xf0'}, // crossed d + {"\xc5\x84", '\xf1'}, // n with acute + {"\xc5\x88", '\xf2'}, // n with caron + {"\xc3\xb3", '\xf3'}, // o with acute + {"\xc3\xb4", '\xf4'}, // o-circumflex + {"\xc5\x91", '\xf5'}, // o with double accent + {"\xc3\xb6", '\xf6'}, // o with diaeresis + {"\xc3\xb7", '\xf7'}, // division sign + {"\xc5\x99", '\xf8'}, // r with caron + {"\xc5\xaf", '\xf9'}, // u with diacritic + {"\xc3\xba", '\xfa'}, // u with acute + {"\xc5\xb1", '\xfb'}, // u with double accent + {"\xc3\xbc", '\xfc'}, // u with diaeresis + {"\xc3\xbd", '\xfd'}, // y with acute + {"\xc5\xa3", '\xfe'}, // t-cedilla + {"\xcb\x99", '\xff'}, // diactric dot + }; + + inline std::string win1250ToUTF8(const std::string& strRef) + { + std::string result; + result.reserve(strRef.size() * 2); + + for (auto&& c : strRef) + { + if (WINDOWS1250_UTF8_MAP.contains(static_cast(c))) + result += WINDOWS1250_UTF8_MAP.at(static_cast(c)); + else + result += c; + } + + return result; + } + + inline std::string UTF8ToWin1250(const std::string& strRef) + { + std::string result; + result.reserve(strRef.size()); + size_t charSize = 1; + + for (size_t i = 0; i < strRef.length(); ++i) + { + if (const int c = static_cast(strRef[i]); c >= 128) + { + if (c < 224) + charSize = 2; + else if (c < 240) + charSize = 3; + else if (c < 248) + charSize = 4; + else if (c == 252) + charSize = 5; + else + charSize = 6; + } + // Update loop index according to UTF8 charSize; + i += charSize - 1; + + if (charSize == 1) + { + result += strRef[i]; + continue; + } + + if (i + charSize > strRef.length()) + { + result += '?'; + return result; + } + + String utfChar; + utfChar.reserve(charSize); + + for (size_t j = 0; j < charSize; ++j) + { + utfChar += strRef[i + j]; + } + + if (UTF8_WINDOWS1250_MAP.contains(utfChar)) + { + result += static_cast(UTF8_WINDOWS1250_MAP.at(utfChar)); + } + else + { + result += '?'; + } + } + + return result; + } +} +#endif // NONUT_CORE_STRING_HELPERS_H diff --git a/src/NoNut/core/Stringify.h b/src/NoNut/core/Stringify.h new file mode 100644 index 0000000..9b4e3dc --- /dev/null +++ b/src/NoNut/core/Stringify.h @@ -0,0 +1,22 @@ +#ifndef NONUT_CORE_STRINGIFY_H +#define NONUT_CORE_STRINGIFY_H + +#include "CommonHeader.h" +#define QUOTIFY(arg) #arg +#define STRINGIFY(arg) QUOTIFY(arg) + +namespace nonut +{ + template + class Stringify + { + public: + virtual ~Stringify() = default; + + [[nodiscard]] virtual String toString() const + { + return STRINGIFY(T); + } + }; +} +#endif //NONUT_CORE_STRINGIFY_H diff --git a/src/NoNut/core/UserData.h b/src/NoNut/core/UserData.h new file mode 100644 index 0000000..ea2ad7b --- /dev/null +++ b/src/NoNut/core/UserData.h @@ -0,0 +1,13 @@ +#ifndef NONUT_CORE_USER_DATA_H +#define NONUT_CORE_USER_DATA_H + +namespace nonut +{ + class UserData + { + public: + SQUserPointer userPtr = nullptr; + SQUserPointer tagPtr = nullptr; + }; +} +#endif //NONUT_CORE_INSTANCE_H diff --git a/src/NoNut/core/Utils.h b/src/NoNut/core/Utils.h new file mode 100644 index 0000000..62deaf1 --- /dev/null +++ b/src/NoNut/core/Utils.h @@ -0,0 +1,108 @@ +#ifndef NONUT_CORE_UTILS_H +#define NONUT_CORE_UTILS_H + +#include "Instance.h" +#include "CommonHeader.h" + +namespace nonut +{ + struct CustomType + { + virtual void convert(HSQOBJECT object) = 0; + }; + + template + void sqGetValue(SQVM* vm, SQInteger idx, T outPtr) + { + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + "Not supported return type"); + + if constexpr (std::is_same_v) + sq_getbool(vm, idx, outPtr); + if constexpr (std::is_same_v) + sq_getinteger(vm, idx, outPtr); + if constexpr (std::is_same_v) + sq_getfloat(vm, idx, outPtr); + if constexpr (std::is_same_v) + sq_getstring(vm, idx, outPtr); + if constexpr (std::is_same_v) + { + sq_getstackobj(vm, idx, outPtr); + sq_addref(vm, outPtr); + } + if constexpr (std::is_same_v) + { + sq_getuserpointer(vm, idx, outPtr); + } + } + + template + void sqPushValue(SQVM* vm, T value) + { + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::derived_from, + "Not supported return type"); + + if constexpr (std::is_same_v) + sq_pushbool(vm, value); + if constexpr (std::is_same_v) + sq_pushbool(vm, value); + if constexpr (std::is_same_v) + sq_pushinteger(vm, value); + if constexpr (std::is_same_v) + sq_pushfloat(vm, value); + if constexpr (std::is_same_v) + sq_pushstring(vm, value, -1); + if constexpr (std::is_same_v) + sq_pushobject(vm, value); + if constexpr (std::is_same_v || std::is_same_v) + sq_pushstring(vm, value.c_str(), value.length()); + if constexpr (std::is_same_v) + sq_pushuserpointer(vm, value); + if constexpr (std::derived_from) + sq_pushobject(vm, value.getInstance()); + } + + template + T returnVar() + { + HSQUIRRELVM vm = Sqrat::DefaultVM::Get(); + static_assert( + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v, + "Not supported return type"); + + T result{}; + sqGetValue(vm, -1, &result); + sq_pop(vm, 1); // pops result + return result; + } + + template <> + inline String returnVar() + { + const SQChar* result = ""; + sq_getstring(Sqrat::DefaultVM::Get(), -1, &result); + sq_pop(Sqrat::DefaultVM::Get(), 1); // pops result + return result; + } +} +#endif // NONUT_CORE_UTILS_H