diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ab8f3b1..d1d78f09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,6 @@ option(BUILD_SAMPLES "Build Samples Folder" FALSE) option(RUN_FUZZY_TESTS "Run tests generated by AFL" FALSE) option(USE_STD_MAKE_SHARED "Use std::make_shared instead of chaiscript::make_shared" FALSE) option(RUN_PERFORMANCE_TESTS "Run Performance Tests" FALSE) -option(BUILD_IN_CPP17_MODE "Build with C++17 flags" FALSE) mark_as_advanced(USE_STD_MAKE_SHARED) @@ -49,8 +48,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") option(ENABLE_MEMORY_SANITIZER "Enable memory sanitizer testing in gcc/clang" FALSE) if(ENABLE_MEMORY_SANITIZER) - add_definitions(-fsanitize=memory -g) - set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory") + add_definitions(-fsanitize=memory -fsanitize-memory-track-origins -g) + set(LINKER_FLAGS "${LINKER_FLAGS} -fsanitize=memory -fsanitize-memory-track-origins ") endif() option(ENABLE_UNDEFINED_SANITIZER "Enable undefined behavior sanitizer testing in gcc/clang" FALSE) @@ -98,8 +97,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt") -set(CPACK_PACKAGE_VERSION_MAJOR 6) -set(CPACK_PACKAGE_VERSION_MINOR 1) +set(CPACK_PACKAGE_VERSION_MAJOR 7) +set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_PATCH 0) set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval") @@ -149,27 +148,16 @@ if(CMAKE_COMPILER_IS_GNUCC) if(GCC_VERSION VERSION_LESS 4.9) set(CPP14_FLAG "-std=c++1y") else() - if (BUILD_IN_CPP17_MODE) - set(CPP14_FLAG "-std=c++1z") - else() - set(CPP14_FLAG "-std=c++14") - endif() + set(CPP14_FLAG "-std=c++1z") endif() else() - if (BUILD_IN_CPP17_MODE) - set(CPP14_FLAG "-std=c++1z") - else() - set(CPP14_FLAG "-std=c++14") - endif() + set(CPP14_FLAG "-std=c++1z") endif() if(MSVC) - add_definitions(/W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928) - - if (BUILD_IN_CPP17_MODE) - add_definitions(/std:c++17) - endif() + add_definitions(/std:c++latest /W4 /w14545 /w34242 /w34254 /w34287 /w44263 /w44265 /w44296 /w44311 /w44826 /we4289 /w14546 /w14547 /w14549 /w14555 /w14619 /w14905 /w14906 /w14928) + add_definitions(/std:c++17) if (MSVC_VERSION STREQUAL "1800") @@ -190,10 +178,10 @@ if(MSVC) # how to workaround or fix the error. So I'm disabling it globally. add_definitions(/wd4503) else() - add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP14_FLAG}) + add_definitions(-Wall -Wextra -Wconversion -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -Wno-noexcept-type -Wpedantic ${CPP14_FLAG}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template) + add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors -Wno-documentation-unknown-command -Wno-unused-template -Wno-undef ) else() add_definitions(-Wnoexcept) endif() diff --git a/include/chaiscript/chaiscript_defines.hpp b/include/chaiscript/chaiscript_defines.hpp index add4774a..71a672b9 100644 --- a/include/chaiscript/chaiscript_defines.hpp +++ b/include/chaiscript/chaiscript_defines.hpp @@ -21,6 +21,7 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req #endif #include +#include #if defined( _LIBCPP_VERSION ) #define CHAISCRIPT_LIBCPP @@ -75,13 +76,13 @@ static_assert(_MSC_FULL_VER >= 190024210, "Visual C++ 2015 Update 3 or later req #include namespace chaiscript { - static const int version_major = 6; - static const int version_minor = 1; - static const int version_patch = 0; + constexpr static const int version_major = 7; + constexpr static const int version_minor = 0; + constexpr static const int version_patch = 0; - static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION; - static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; - static const bool debug_build = CHAISCRIPT_DEBUG; + constexpr static const char *compiler_version = CHAISCRIPT_COMPILER_VERSION; + constexpr static const char *compiler_name = CHAISCRIPT_COMPILER_NAME; + constexpr static const bool debug_build = CHAISCRIPT_DEBUG; template inline std::shared_ptr make_shared(Arg && ... arg) @@ -104,17 +105,17 @@ namespace chaiscript { } struct Build_Info { - static int version_major() + constexpr static int version_major() noexcept { return chaiscript::version_major; } - static int version_minor() + constexpr static int version_minor() noexcept { return chaiscript::version_minor; } - static int version_patch() + constexpr static int version_patch() noexcept { return chaiscript::version_patch; } @@ -144,7 +145,7 @@ namespace chaiscript { return chaiscript::compiler_name; } - static bool debug_build() + constexpr static bool debug_build() noexcept { return chaiscript::debug_build; } @@ -152,10 +153,10 @@ namespace chaiscript { template - auto parse_num(const char *t_str) -> typename std::enable_if::value, T>::type + constexpr auto parse_num(const std::string_view t_str) noexcept -> typename std::enable_if::value, T>::type { T t = 0; - for (char c = *t_str; (c = *t_str) != 0; ++t_str) { + for (const auto c : t_str) { if (c < '0' || c > '9') { return t; } @@ -167,15 +168,14 @@ namespace chaiscript { template - auto parse_num(const char *t_str) -> typename std::enable_if::value, T>::type + auto parse_num(const std::string_view t_str) -> typename std::enable_if::value, T>::type { T t = 0; T base{}; T decimal_place = 0; int exponent = 0; - for (char c;; ++t_str) { - c = *t_str; + for (const auto c : t_str) { switch (c) { case '.': @@ -213,16 +213,24 @@ namespace chaiscript { } break; default: - return exponent ? base * std::pow(T(10), t * static_cast(exponent)) : t; + break; } } + return exponent ? base * std::pow(T(10), t * static_cast(exponent)) : t; + + } - template - T parse_num(const std::string &t_str) - { - return parse_num(t_str.c_str()); + struct str_less { + bool operator()(const std::string &t_lhs, const std::string &t_rhs) const noexcept { + return t_lhs < t_rhs; } + template + constexpr bool operator()(const LHS &t_lhs, const RHS &t_rhs) const noexcept { + return std::lexicographical_compare(t_lhs.begin(), t_lhs.end(), t_rhs.begin(), t_rhs.end()); + } + struct is_transparent{}; + }; enum class Options { diff --git a/include/chaiscript/chaiscript_threading.hpp b/include/chaiscript/chaiscript_threading.hpp index 41306ea4..3875f9cf 100644 --- a/include/chaiscript/chaiscript_threading.hpp +++ b/include/chaiscript/chaiscript_threading.hpp @@ -17,6 +17,7 @@ #ifndef CHAISCRIPT_NO_THREADS #include #include +#include #else #ifndef CHAISCRIPT_NO_THREADS_WARNING #pragma message ("ChaiScript is compiling without thread safety.") @@ -49,13 +50,13 @@ namespace chaiscript using unique_lock = std::unique_lock; template - using shared_lock = std::unique_lock; + using shared_lock = std::shared_lock; template using lock_guard = std::lock_guard; - using shared_mutex = std::mutex; + using std::shared_mutex; using std::mutex; @@ -78,22 +79,22 @@ namespace chaiscript t().erase(this); } - inline const T *operator->() const + inline const T *operator->() const noexcept { return &(t()[this]); } - inline const T &operator*() const + inline const T &operator*() const noexcept { return t()[this]; } - inline T *operator->() + inline T *operator->() noexcept { return &(t()[this]); } - inline T &operator*() + inline T &operator*() noexcept { return t()[this]; } @@ -102,7 +103,9 @@ namespace chaiscript void *m_key; private: - static std::unordered_map &t() + /// todo: is it valid to make this noexcept? The allocation could fail, but if it + /// does there is no possible way to recover + static std::unordered_map &t() noexcept { thread_local std::unordered_map my_t; return my_t; @@ -114,25 +117,25 @@ namespace chaiscript class unique_lock { public: - explicit unique_lock(T &) {} - void lock() {} - void unlock() {} + constexpr explicit unique_lock(T &) noexcept {} + constexpr void lock() noexcept {} + constexpr void unlock() noexcept {} }; template class shared_lock { public: - explicit shared_lock(T &) {} - void lock() {} - void unlock() {} + constexpr explicit shared_lock(T &) noexcept {} + constexpr void lock() noexcept {} + constexpr void unlock() noexcept {} }; template class lock_guard { public: - explicit lock_guard(T &) {} + constexpr explicit lock_guard(T &) noexcept {} }; class shared_mutex { }; @@ -144,16 +147,16 @@ namespace chaiscript class Thread_Storage { public: - explicit Thread_Storage() + constexpr explicit Thread_Storage() noexcept { } - inline T *operator->() const + constexpr inline T *operator->() const noexcept { return &obj; } - inline T &operator*() const + constexpr inline T &operator*() const noexcept { return obj; } diff --git a/include/chaiscript/dispatchkit/any.hpp b/include/chaiscript/dispatchkit/any.hpp index ae8035c9..d13b653f 100644 --- a/include/chaiscript/dispatchkit/any.hpp +++ b/include/chaiscript/dispatchkit/any.hpp @@ -21,20 +21,11 @@ namespace chaiscript { class bad_any_cast : public std::bad_cast { public: - bad_any_cast() = default; - - bad_any_cast(const bad_any_cast &) = default; - - ~bad_any_cast() noexcept override = default; - /// \brief Description of what error occurred const char * what() const noexcept override { - return m_what.c_str(); + return "bad any cast"; } - - private: - std::string m_what = "bad any cast"; }; } @@ -43,18 +34,18 @@ namespace chaiscript { private: struct Data { - explicit Data(const std::type_info &t_type) + constexpr explicit Data(const std::type_info &t_type) noexcept : m_type(t_type) { } Data &operator=(const Data &) = delete; - virtual ~Data() = default; + virtual ~Data() noexcept = default; - virtual void *data() = 0; + virtual void *data() noexcept = 0; - const std::type_info &type() const + const std::type_info &type() const noexcept { return m_type; } @@ -72,14 +63,14 @@ namespace chaiscript { { } - void *data() override + void *data() noexcept override { return &m_data; } std::unique_ptr clone() const override { - return std::unique_ptr(new Data_Impl(m_data)); + return std::make_unique>(m_data); } Data_Impl &operator=(const Data_Impl&) = delete; @@ -91,25 +82,19 @@ namespace chaiscript { public: // construct/copy/destruct - Any() = default; + constexpr Any() noexcept = default; Any(Any &&) = default; Any &operator=(Any &&t_any) = default; - Any(const Any &t_any) - { - if (!t_any.empty()) - { - m_data = t_any.m_data->clone(); - } else { - m_data.reset(); - } + Any(const Any &t_any) + : m_data(t_any.empty() ? nullptr : t_any.m_data->clone()) + { } - template::type>::value>::type> + typename = std::enable_if_t>>> explicit Any(ValueType &&t_value) - : m_data(std::unique_ptr(new Data_Impl::type>(std::forward(t_value)))) + : m_data(std::make_unique>>(std::forward(t_value))) { } @@ -141,12 +126,12 @@ namespace chaiscript { } // queries - bool empty() const + bool empty() const noexcept { return !bool(m_data); } - const std::type_info & type() const + const std::type_info & type() const noexcept { if (m_data) { return m_data->type(); diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp index d880feab..9a779020 100644 --- a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -15,6 +15,7 @@ #include #include "../chaiscript_defines.hpp" +#include "../utility/static_string.hpp" #include "type_info.hpp" namespace chaiscript { @@ -34,22 +35,22 @@ namespace chaiscript { public: bad_boxed_cast(Type_Info t_from, const std::type_info &t_to, - std::string t_what) noexcept + utility::Static_String t_what) noexcept : from(t_from), to(&t_to), m_what(std::move(t_what)) { } - bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) - : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast: " + t_from.name() + " to: " + t_to.name()) + bad_boxed_cast(Type_Info t_from, const std::type_info &t_to) noexcept + : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") { } - explicit bad_boxed_cast(std::string t_what) noexcept + explicit bad_boxed_cast(utility::Static_String t_what) noexcept : m_what(std::move(t_what)) { } - bad_boxed_cast(const bad_boxed_cast &) = default; + bad_boxed_cast(const bad_boxed_cast &) noexcept = default; ~bad_boxed_cast() noexcept override = default; /// \brief Description of what error occurred @@ -62,7 +63,7 @@ namespace chaiscript const std::type_info *to = nullptr; ///< std::type_info of the desired (but failed) result type private: - std::string m_what; + utility::Static_String m_what; }; } } diff --git a/include/chaiscript/dispatchkit/bind_first.hpp b/include/chaiscript/dispatchkit/bind_first.hpp index 3dbcc4d2..cc794c08 100644 --- a/include/chaiscript/dispatchkit/bind_first.hpp +++ b/include/chaiscript/dispatchkit/bind_first.hpp @@ -19,37 +19,37 @@ namespace chaiscript { template - T* get_pointer(T *t) + constexpr T* get_pointer(T *t) noexcept { return t; } template - T* get_pointer(const std::reference_wrapper &t) + T* get_pointer(const std::reference_wrapper &t) noexcept { return &t.get(); } template - auto bind_first(Ret (*f)(P1, Param...), O&& o) + constexpr auto bind_first(Ret (*f)(P1, Param...), O&& o) { - return [f, o](Param...param) -> Ret { - return f(std::forward(o), std::forward(param)...); + return [f, o = std::forward(o)](Param...param) -> Ret { + return f(o, std::forward(param)...); }; } template - auto bind_first(Ret (Class::*f)(Param...), O&& o) + constexpr auto bind_first(Ret (Class::*f)(Param...), O&& o) { - return [f, o](Param...param) -> Ret { + return [f, o = std::forward(o)](Param...param) -> Ret { return (get_pointer(o)->*f)(std::forward(param)...); }; } template - auto bind_first(Ret (Class::*f)(Param...) const, O&& o) + constexpr auto bind_first(Ret (Class::*f)(Param...) const, O&& o) { - return [f, o](Param...param) -> Ret { + return [f, o = std::forward(o)](Param...param) -> Ret { return (get_pointer(o)->*f)(std::forward(param)...); }; @@ -58,22 +58,22 @@ namespace chaiscript template auto bind_first(const std::function &f, O&& o) { - return [f, o](Param...param) -> Ret { + return [f, o = std::forward(o)](Param...param) -> Ret { return f(o, std::forward(param)...); }; } template - auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const) + constexpr auto bind_first(const F &fo, O&& o, Ret (Class::*f)(P1, Param...) const) { - return [fo, o, f](Param ...param) -> Ret { + return [fo, o = std::forward(o), f](Param ...param) -> Ret { return (fo.*f)(o, std::forward(param)...); }; } template - auto bind_first(const F &f, O&& o) + constexpr auto bind_first(const F &f, O&& o) { return bind_first(f, std::forward(o), &F::operator()); } diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index c0ad7ce3..6178d4f6 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -22,11 +22,12 @@ namespace chaiscript template::value>::type > void array(const std::string &type, Module& m) { - typedef typename std::remove_extent::type ReturnType; + using ReturnType = typename std::remove_extent::type; + m.add(user_type(), type); m.add(fun( [](T& t, size_t index)->ReturnType &{ - constexpr auto extent = std::extent::value; + constexpr const auto extent = std::extent::value; if (extent > 0 && index >= extent) { throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); } else { @@ -38,7 +39,7 @@ namespace chaiscript m.add(fun( [](const T &t, size_t index)->const ReturnType &{ - constexpr auto extent = std::extent::value; + constexpr const auto extent = std::extent::value; if (extent > 0 && index >= extent) { throw std::range_error("Array index out of range. Received: " + std::to_string(index) + " expected < " + std::to_string(extent)); } else { @@ -50,8 +51,7 @@ namespace chaiscript m.add(fun( [](const T &) { - constexpr auto extent = std::extent::value; - return extent; + return std::extent::value; }), "size"); } @@ -111,31 +111,20 @@ namespace chaiscript /// Internal function for converting from a string to a value /// uses ostream operator >> to perform the conversion template - auto parse_string(const std::string &i) - -> typename std::enable_if< - !std::is_same::value - && !std::is_same::value - && !std::is_same::value, - Input>::type + Input parse_string(const std::string &i) { - std::stringstream ss(i); - Input t; - ss >> t; - return t; + if constexpr (!std::is_same::value + && !std::is_same::value + && !std::is_same::value) { + std::stringstream ss(i); + Input t; + ss >> t; + return t; + } else { + throw std::runtime_error("Parsing of wide characters is not yet supported"); + } } - template - auto parse_string(const std::string &) - -> typename std::enable_if< - std::is_same::value - || std::is_same::value - || std::is_same::value, - Input>::type - { - throw std::runtime_error("Parsing of wide characters is not yet supported"); - } - - /// Add all common functions for a POD type. All operators, and /// common conversions template @@ -202,12 +191,12 @@ namespace chaiscript } } - static void print(const std::string &s) + static void print(const std::string &s) noexcept { fwrite(s.c_str(), 1, s.size(), stdout); } - static void println(const std::string &s) + static void println(const std::string &s) noexcept { puts(s.c_str()); } @@ -271,10 +260,10 @@ namespace chaiscript } - static bool has_guard(const Const_Proxy_Function &t_pf) + static bool has_guard(const Const_Proxy_Function &t_pf) noexcept { auto pf = std::dynamic_pointer_cast(t_pf); - return pf && pf->get_guard(); + return pf && pf->has_guard(); } static Const_Proxy_Function get_guard(const Const_Proxy_Function &t_pf) @@ -305,7 +294,7 @@ namespace chaiscript } - static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) + static bool has_parse_tree(const chaiscript::Const_Proxy_Function &t_pf) noexcept { const auto pf = std::dynamic_pointer_cast(t_pf); return bool(pf); diff --git a/include/chaiscript/dispatchkit/bootstrap_stl.hpp b/include/chaiscript/dispatchkit/bootstrap_stl.hpp index 31c6deea..2bdba55a 100644 --- a/include/chaiscript/dispatchkit/bootstrap_stl.hpp +++ b/include/chaiscript/dispatchkit/bootstrap_stl.hpp @@ -44,19 +44,19 @@ namespace chaiscript template struct Bidir_Range { - typedef Container container_type; + using container_type = Container; - Bidir_Range(Container &c) + constexpr Bidir_Range(Container &c) : m_begin(c.begin()), m_end(c.end()) { } - bool empty() const + constexpr bool empty() const noexcept { return m_begin == m_end; } - void pop_front() + constexpr void pop_front() { if (empty()) { @@ -65,7 +65,7 @@ namespace chaiscript ++m_begin; } - void pop_back() + constexpr void pop_back() { if (empty()) { @@ -74,7 +74,7 @@ namespace chaiscript --m_end; } - decltype(auto) front() const + constexpr decltype(auto) front() const { if (empty()) { @@ -83,7 +83,7 @@ namespace chaiscript return (*m_begin); } - decltype(auto) back() const + constexpr decltype(auto) back() const { if (empty()) { @@ -355,7 +355,7 @@ namespace chaiscript , "back"); - typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &); + using push_back = void (ContainerType::*)(const typename ContainerType::value_type &); m.add(fun(static_cast(&ContainerType::push_back)), [&]()->std::string{ if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) { @@ -395,8 +395,8 @@ namespace chaiscript template void front_insertion_sequence_type(const std::string &type, Module& m) { - typedef void (ContainerType::*push_ptr)(typename ContainerType::const_reference); - typedef void (ContainerType::*pop_ptr)(); + using push_ptr = void (ContainerType::*)(typename ContainerType::const_reference); + using pop_ptr = void (ContainerType::*)(); m.add(fun([](ContainerType &container)->decltype(auto){ if (container.empty()) { @@ -498,7 +498,7 @@ namespace chaiscript { m.add(fun(detail::count), "count"); - typedef size_t (ContainerType::*erase_ptr)(const typename ContainerType::key_type &); + using erase_ptr = size_t (ContainerType::*)(const typename ContainerType::key_type &); m.add(fun(static_cast(&ContainerType::erase)), "erase"); @@ -529,8 +529,8 @@ namespace chaiscript { m.add(user_type(), type); - typedef typename MapType::mapped_type &(MapType::*elem_access)(const typename MapType::key_type &); - typedef const typename MapType::mapped_type &(MapType::*const_elem_access)(const typename MapType::key_type &) const; + using elem_access = typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &); + using const_elem_access = const typename MapType::mapped_type &(MapType::*)(const typename MapType::key_type &) const; m.add(fun(static_cast(&MapType::operator[])), "[]"); diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp index b7919bd2..ad26c296 100644 --- a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -27,7 +27,7 @@ namespace chaiscript // Cast_Helper_Inner helper classes template - T* throw_if_null(T *t) + constexpr T* throw_if_null(T *t) { if (t) { return t; } throw std::runtime_error("Attempted to dereference null Boxed_Value"); diff --git a/include/chaiscript/dispatchkit/boxed_number.hpp b/include/chaiscript/dispatchkit/boxed_number.hpp index 290a73ab..d133dbff 100644 --- a/include/chaiscript/dispatchkit/boxed_number.hpp +++ b/include/chaiscript/dispatchkit/boxed_number.hpp @@ -59,6 +59,7 @@ namespace chaiscript #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic ignored "-Wfloat-conversion" +#pragma GCC diagnostic ignored "-Wswitch" #endif /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values @@ -80,21 +81,18 @@ namespace chaiscript }; template - static inline void check_divide_by_zero(T t, typename std::enable_if::value>::type* = nullptr) + constexpr static inline void check_divide_by_zero([[maybe_unused]] T t) { #ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO - if (t == 0) { - throw chaiscript::exception::arithmetic_error("divide by zero"); + if constexpr (!std::is_floating_point::value) { + if (t == 0) { + throw chaiscript::exception::arithmetic_error("divide by zero"); + } } #endif } - template - static inline void check_divide_by_zero(T, typename std::enable_if::value>::type* = nullptr) - { - } - - static constexpr Common_Types get_common_type(size_t t_size, bool t_signed) + constexpr static Common_Types get_common_type(size_t t_size, bool t_signed) noexcept { return (t_size == 1 && t_signed)?(Common_Types::t_int8) :(t_size == 1)?(Common_Types::t_uint8) @@ -111,378 +109,234 @@ namespace chaiscript { const Type_Info &inp_ = t_bv.get_type_info(); - if (inp_ == typeid(int)) { + if (inp_ == user_type()) { return get_common_type(sizeof(int), true); - } else if (inp_ == typeid(double)) { + } else if (inp_ == user_type()) { return Common_Types::t_double; - } else if (inp_ == typeid(long double)) { + } else if (inp_ == user_type()) { return Common_Types::t_long_double; - } else if (inp_ == typeid(float)) { + } else if (inp_ == user_type()) { return Common_Types::t_float; - } else if (inp_ == typeid(char)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(char), std::is_signed::value); - } else if (inp_ == typeid(unsigned char)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(unsigned char), false); - } else if (inp_ == typeid(unsigned int)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(unsigned int), false); - } else if (inp_ == typeid(long)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(long), true); - } else if (inp_ == typeid(long long)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(long long), true); - } else if (inp_ == typeid(unsigned long)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(unsigned long), false); - } else if (inp_ == typeid(unsigned long long)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(unsigned long long), false); - } else if (inp_ == typeid(std::int8_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_int8; - } else if (inp_ == typeid(std::int16_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_int16; - } else if (inp_ == typeid(std::int32_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_int32; - } else if (inp_ == typeid(std::int64_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_int64; - } else if (inp_ == typeid(std::uint8_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_uint8; - } else if (inp_ == typeid(std::uint16_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_uint16; - } else if (inp_ == typeid(std::uint32_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_uint32; - } else if (inp_ == typeid(std::uint64_t)) { + } else if (inp_ == user_type()) { return Common_Types::t_uint64; - } else if (inp_ == typeid(wchar_t)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(wchar_t), std::is_signed::value); - } else if (inp_ == typeid(char16_t)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(char16_t), std::is_signed::value); - } else if (inp_ == typeid(char32_t)) { + } else if (inp_ == user_type()) { return get_common_type(sizeof(char32_t), std::is_signed::value); } else { throw chaiscript::detail::exception::bad_any_cast(); } } - template - static Boxed_Value boolean_go(Operators::Opers t_oper, const T &t, const T &u) + + + template + static auto go(Operators::Opers t_oper, const Boxed_Value &t_bv, LHS *t_lhs, const LHS &c_lhs, const RHS &c_rhs) { - switch (t_oper) - { + switch (t_oper) { case Operators::Opers::equals: - return const_var(t == u); + return const_var(c_lhs == c_rhs); case Operators::Opers::less_than: - return const_var(t < u); + return const_var(c_lhs < c_rhs); case Operators::Opers::greater_than: - return const_var(t > u); + return const_var(c_lhs > c_rhs); case Operators::Opers::less_than_equal: - return const_var(t <= u); + return const_var(c_lhs <= c_rhs); case Operators::Opers::greater_than_equal: - return const_var(t >= u); + return const_var(c_lhs >= c_rhs); case Operators::Opers::not_equal: - return const_var(t != u); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - template - static Boxed_Value unary_go(Operators::Opers t_oper, T &t, const Boxed_Value &t_lhs) - { - switch (t_oper) - { - case Operators::Opers::pre_increment: - ++t; - break; - case Operators::Opers::pre_decrement: - --t; - break; - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - - return t_lhs; - } - - template - static Boxed_Value binary_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) - { - switch (t_oper) - { - case Operators::Opers::assign: - t = u; - break; - case Operators::Opers::assign_product: - t *= u; - break; - case Operators::Opers::assign_sum: - t += u; - break; - case Operators::Opers::assign_quotient: - check_divide_by_zero(u); - t /= u; - break; - case Operators::Opers::assign_difference: - t -= u; - break; - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - - return t_lhs; - } - - template - static Boxed_Value binary_int_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) - { - switch (t_oper) - { - case Operators::Opers::assign_bitwise_and: - t &= u; - break; - case Operators::Opers::assign_bitwise_or: - t |= u; - break; - case Operators::Opers::assign_shift_left: - t <<= u; - break; - case Operators::Opers::assign_shift_right: - t >>= u; - break; - case Operators::Opers::assign_remainder: - check_divide_by_zero(u); - t %= u; - break; - case Operators::Opers::assign_bitwise_xor: - t ^= u; - break; - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - return t_lhs; - } - - template - static Boxed_Value const_unary_int_go(Operators::Opers t_oper, const T &t) - { - switch (t_oper) - { - case Operators::Opers::bitwise_complement: - return const_var(~t); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - template - static Boxed_Value const_binary_int_go(Operators::Opers t_oper, const T &t, const T &u) - { - switch (t_oper) - { - case Operators::Opers::shift_left: - return const_var(t << u); - case Operators::Opers::shift_right: - return const_var(t >> u); - case Operators::Opers::remainder: - check_divide_by_zero(u); - return const_var(t % u); - case Operators::Opers::bitwise_and: - return const_var(t & u); - case Operators::Opers::bitwise_or: - return const_var(t | u); - case Operators::Opers::bitwise_xor: - return const_var(t ^ u); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - template - static Boxed_Value const_unary_go(Operators::Opers t_oper, const T &t) - { - switch (t_oper) - { - case Operators::Opers::unary_minus: - return const_var(-t); - case Operators::Opers::unary_plus: - return const_var(+t); - default: - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - template - static Boxed_Value const_binary_go(Operators::Opers t_oper, const T &t, const T &u) - { - switch (t_oper) - { + return const_var(c_lhs != c_rhs); case Operators::Opers::sum: - return const_var(t + u); + return const_var(c_lhs + c_rhs); case Operators::Opers::quotient: - check_divide_by_zero(u); - return const_var(t / u); + check_divide_by_zero(c_rhs); + return const_var(c_lhs / c_rhs); case Operators::Opers::product: - return const_var(t * u); + return const_var(c_lhs * c_rhs); case Operators::Opers::difference: - return const_var(t - u); - default: - throw chaiscript::detail::exception::bad_any_cast(); + return const_var(c_lhs - c_rhs); } - } - template - static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) - -> typename std::enable_if::value && !std::is_floating_point::value, Boxed_Value>::type - { - typedef typename std::common_type::type common_type; - if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag) - { - return boolean_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); - } else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return binary_go(t_oper, *static_cast(t_lhs.get_ptr()), get_as_aux(t_rhs), t_lhs); - } else if (t_oper > Operators::Opers::non_const_int_flag && t_oper < Operators::Opers::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return binary_int_go(t_oper, *static_cast(t_lhs.get_ptr()), get_as_aux(t_rhs), t_lhs); - } else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) { - return const_binary_int_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); - } else if (t_oper > Operators::Opers::const_flag) { - return const_binary_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); - } else { - throw chaiscript::detail::exception::bad_any_cast(); + + if constexpr (!std::is_floating_point::value && !std::is_floating_point::value) { + switch (t_oper) { + case Operators::Opers::shift_left: + return const_var(c_lhs << c_rhs); + case Operators::Opers::shift_right: + return const_var(c_lhs >> c_rhs); + case Operators::Opers::remainder: + check_divide_by_zero(c_rhs); + return const_var(c_lhs % c_rhs); + case Operators::Opers::bitwise_and: + return const_var(c_lhs & c_rhs); + case Operators::Opers::bitwise_or: + return const_var(c_lhs | c_rhs); + case Operators::Opers::bitwise_xor: + return const_var(c_lhs ^ c_rhs); + } } - } - template - static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) - -> typename std::enable_if::value || std::is_floating_point::value, Boxed_Value>::type - { - typedef typename std::common_type::type common_type; - if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag) - { - return boolean_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); - } else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return binary_go(t_oper, *static_cast(t_lhs.get_ptr()), get_as_aux(t_rhs), t_lhs); - } else if (t_oper > Operators::Opers::const_flag) { - return const_binary_go(t_oper, get_as_aux(t_lhs), get_as_aux(t_rhs)); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - // Unary - template - static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) - -> typename std::enable_if::value, Boxed_Value>::type - { - if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return unary_go(t_oper, *static_cast(t_lhs.get_ptr()), t_lhs); - } else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) { - return const_unary_int_go(t_oper, *static_cast(t_lhs.get_const_ptr())); - } else if (t_oper > Operators::Opers::const_flag) { - return const_unary_go(t_oper, *static_cast(t_lhs.get_const_ptr())); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - template - static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) - -> typename std::enable_if::value, Boxed_Value>::type - { - if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { - return unary_go(t_oper, *static_cast(t_lhs.get_ptr()), t_lhs); - } else if (t_oper > Operators::Opers::const_flag) { - return const_unary_go(t_oper, *static_cast(t_lhs.get_const_ptr())); - } else { - throw chaiscript::detail::exception::bad_any_cast(); - } - } - - template - inline static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) - { - switch (get_common_type(t_rhs)) { - case Common_Types::t_int32: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint8: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_int8: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint16: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_int16: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint32: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint64: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_int64: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_double: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_float: - return go(t_oper, t_lhs, t_rhs); - case Common_Types::t_long_double: - return go(t_oper, t_lhs, t_rhs); + if (t_lhs) { + switch (t_oper) { + case Operators::Opers::assign: + *t_lhs = c_rhs; + return t_bv; + case Operators::Opers::assign_product: + *t_lhs *= c_rhs; + return t_bv; + case Operators::Opers::assign_sum: + *t_lhs += c_rhs; + return t_bv; + case Operators::Opers::assign_quotient: + check_divide_by_zero(c_rhs); + *t_lhs /= c_rhs; + return t_bv; + case Operators::Opers::assign_difference: + *t_lhs -= c_rhs; + return t_bv; } - throw chaiscript::detail::exception::bad_any_cast(); + if constexpr (!std::is_floating_point::value && !std::is_floating_point::value) { + switch (t_oper) { + case Operators::Opers::assign_bitwise_and: + check_divide_by_zero(c_rhs); + *t_lhs &= c_rhs; + return t_bv; + case Operators::Opers::assign_bitwise_or: + *t_lhs |= c_rhs; + return t_bv; + case Operators::Opers::assign_shift_left: + *t_lhs <<= c_rhs; + return t_bv; + case Operators::Opers::assign_shift_right: + *t_lhs >>= c_rhs; + return t_bv; + case Operators::Opers::assign_remainder: + *t_lhs %= c_rhs; + return t_bv; + case Operators::Opers::assign_bitwise_xor: + *t_lhs ^= c_rhs; + return t_bv; + } + } + } + + throw chaiscript::detail::exception::bad_any_cast(); + } + + template + inline static auto visit(const Boxed_Value &bv, Callable &&callable) + { + switch (get_common_type(bv)) { + case Common_Types::t_int32: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint8: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_int8: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint16: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_int16: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint32: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_uint64: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_int64: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_double: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_float: + return callable(*static_cast(bv.get_const_ptr())); + case Common_Types::t_long_double: + return callable(*static_cast(bv.get_const_ptr())); + default: + throw chaiscript::detail::exception::bad_any_cast(); + + } } inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) { - switch (get_common_type(t_lhs)) { - case Common_Types::t_int32: - return go(t_oper, t_lhs); - case Common_Types::t_uint8: - return go(t_oper, t_lhs); - case Common_Types::t_int8: - return go(t_oper, t_lhs); - case Common_Types::t_uint16: - return go(t_oper, t_lhs); - case Common_Types::t_int16: - return go(t_oper, t_lhs); - case Common_Types::t_uint32: - return go(t_oper, t_lhs); - case Common_Types::t_uint64: - return go(t_oper, t_lhs); - case Common_Types::t_int64: - return go(t_oper, t_lhs); - case Common_Types::t_double: - return go(t_oper, t_lhs); - case Common_Types::t_float: - return go(t_oper, t_lhs); - case Common_Types::t_long_double: - return go(t_oper, t_lhs); - } + auto unary_operator = [t_oper, &t_lhs](const auto &c_lhs){ + auto *lhs = static_cast *>(t_lhs.get_ptr()); - throw chaiscript::detail::exception::bad_any_cast(); + if (lhs) { + switch (t_oper) { + case Operators::Opers::pre_increment: + ++(*lhs); + return t_lhs; + case Operators::Opers::pre_decrement: + --(*lhs); + return t_lhs; + } + } + + switch (t_oper) { + case Operators::Opers::unary_minus: + return const_var(-c_lhs); + case Operators::Opers::unary_plus: + return const_var(+c_lhs); + } + + if constexpr (!std::is_floating_point_v>) { + switch (t_oper) { + case Operators::Opers::bitwise_complement: + return const_var(~c_lhs); + } + } + + throw chaiscript::detail::exception::bad_any_cast(); + }; + + return visit(t_lhs, unary_operator); } inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) { - switch (get_common_type(t_lhs)) { - case Common_Types::t_int32: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint8: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_int8: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint16: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_int16: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint32: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_uint64: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_int64: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_double: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_float: - return oper_rhs(t_oper, t_lhs, t_rhs); - case Common_Types::t_long_double: - return oper_rhs(t_oper, t_lhs, t_rhs); - } - throw chaiscript::detail::exception::bad_any_cast(); + auto lhs_visit = [t_oper, &t_lhs, &t_rhs](const auto &c_lhs){ + auto *lhs = t_lhs.is_return_value()?nullptr:static_cast *>(t_lhs.get_ptr()); + + auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](const auto &c_rhs) { + return go(t_oper, t_lhs, lhs, c_lhs, c_rhs); + }; + + return visit(t_rhs, rhs_visit); + }; + + return visit(t_lhs, lhs_visit); } template @@ -529,11 +383,11 @@ namespace chaiscript { const Type_Info &inp_ = t_bv.get_type_info(); - if (inp_ == typeid(double)) { + if (inp_ == user_type()) { return true; - } else if (inp_ == typeid(long double)) { + } else if (inp_ == user_type()) { return true; - } else if (inp_ == typeid(float)) { + } else if (inp_ == user_type()) { return true; } else { return false; @@ -542,49 +396,49 @@ namespace chaiscript Boxed_Number get_as(const Type_Info &inp_) const { - if (inp_.bare_equal_type_info(typeid(int))) { + if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(double))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(float))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(long double))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(char))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(unsigned char))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(wchar_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(char16_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(char32_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(unsigned int))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(long))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(long long))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(unsigned long))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(unsigned long long))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(int8_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(int16_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(int32_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(int64_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(uint8_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(uint16_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(uint32_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); - } else if (inp_.bare_equal_type_info(typeid(uint64_t))) { + } else if (inp_.bare_equal(user_type())) { return Boxed_Number(get_as()); } else { throw chaiscript::detail::exception::bad_any_cast(); @@ -716,7 +570,7 @@ namespace chaiscript static void validate_boxed_number(const Boxed_Value &v) { const Type_Info &inp_ = v.get_type_info(); - if (inp_ == typeid(bool)) + if (inp_ == user_type()) { throw chaiscript::detail::exception::bad_any_cast(); } diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 5b9e600d..c8ee236e 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -208,14 +208,14 @@ namespace chaiscript Boxed_Value(const Boxed_Value&) = default; Boxed_Value& operator=(const Boxed_Value&) = default; - void swap(Boxed_Value &rhs) + void swap(Boxed_Value &rhs) noexcept { std::swap(m_data, rhs.m_data); } /// Copy the values stored in rhs.m_data to m_data. /// m_data pointers are not shared in this case - Boxed_Value assign(const Boxed_Value &rhs) + Boxed_Value assign(const Boxed_Value &rhs) noexcept { (*m_data) = (*rhs.m_data); return *this; @@ -244,7 +244,7 @@ namespace chaiscript template - auto pointer_sentinel(std::shared_ptr &ptr) const + auto pointer_sentinel(std::shared_ptr &ptr) const noexcept { struct Sentinel { Sentinel(std::shared_ptr &t_ptr, Data &data) @@ -263,7 +263,7 @@ namespace chaiscript Sentinel& operator=(Sentinel&&s) = default; Sentinel(Sentinel &&s) = default; - operator std::shared_ptr&() const + operator std::shared_ptr&() const noexcept { return m_ptr.get(); } @@ -308,7 +308,7 @@ namespace chaiscript return !is_ref(); } - void *get_ptr() const noexcept + void *get_ptr() const noexcept { return m_data->m_data_ptr; } diff --git a/include/chaiscript/dispatchkit/dispatchkit.hpp b/include/chaiscript/dispatchkit/dispatchkit.hpp index 39630742..576b0f9d 100644 --- a/include/chaiscript/dispatchkit/dispatchkit.hpp +++ b/include/chaiscript/dispatchkit/dispatchkit.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -180,9 +181,9 @@ namespace chaiscript //Add a bit of ChaiScript to eval during module implementation - Module &eval(const std::string &str) + Module &eval(std::string str) { - m_evals.push_back(str); + m_evals.push_back(std::move(str)); return *this; } @@ -196,15 +197,15 @@ namespace chaiscript apply_globals(m_globals.begin(), m_globals.end(), t_engine); } - bool has_function(const Proxy_Function &new_f, const std::string &name) + bool has_function(const Proxy_Function &new_f, const std::string_view &name) noexcept { - return std::any_of(m_funcs.begin(), m_funcs.end(), + return std::any_of(m_funcs.begin(), m_funcs.end(), [&](const std::pair &existing_f) { return existing_f.second == name && *(existing_f.first) == *(new_f); } ); } - + private: std::vector> m_typeinfos; @@ -214,14 +215,14 @@ namespace chaiscript std::vector m_conversions; template - static void apply(InItr begin, const InItr end, T &t) + static void apply(InItr begin, const InItr end, T &t) { - for_each(begin, end, + for_each(begin, end, [&t](const auto &obj) { try { t.add(obj.first, obj.second); } catch (const chaiscript::exception::name_conflict_error &) { - /// \todo Should we throw an error if there's a name conflict + /// \todo Should we throw an error if there's a name conflict /// while applying a module? } } @@ -260,12 +261,12 @@ namespace chaiscript }; /// Convenience typedef for Module objects to be added to the ChaiScript runtime - typedef std::shared_ptr ModulePtr; + using ModulePtr = std::shared_ptr; namespace detail { /// A Proxy_Function implementation that is able to take - /// a vector of Proxy_Functions and perform a dispatch on them. It is + /// a vector of Proxy_Functions and perform a dispatch on them. It is /// used specifically in the case of dealing with Function object variables class Dispatch_Function final : public dispatch::Proxy_Function_Base { @@ -276,7 +277,7 @@ namespace chaiscript { } - bool operator==(const dispatch::Proxy_Function_Base &rhs) const override + bool operator==(const dispatch::Proxy_Function_Base &rhs) const noexcept override { try { const auto &dispatch_fun = dynamic_cast(rhs); @@ -292,7 +293,7 @@ namespace chaiscript } - static int calculate_arity(const std::vector &t_funcs) + static int calculate_arity(const std::vector &t_funcs) noexcept { if (t_funcs.empty()) { return -1; @@ -312,7 +313,7 @@ namespace chaiscript return arity; } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override { return std::any_of(std::begin(m_funcs), std::end(m_funcs), [&vals, &t_conversions](const Proxy_Function &f){ return f->call_match(vals, t_conversions); }); @@ -385,13 +386,13 @@ namespace chaiscript template using SmallVector = std::vector; - - typedef SmallVector> Scope; - typedef SmallVector StackData; - typedef SmallVector Stacks; - typedef SmallVector Call_Param_List; - typedef SmallVector Call_Params; + + using Scope = SmallVector>; + using StackData = SmallVector; + using Stacks = SmallVector; + using Call_Param_List = SmallVector; + using Call_Params = SmallVector; Stack_Holder() { @@ -438,16 +439,16 @@ namespace chaiscript { public: - typedef std::map Type_Name_Map; - typedef std::vector> Scope; - typedef Stack_Holder::StackData StackData; + using Type_Name_Map = std::map; + using Scope = std::vector>; + using StackData = Stack_Holder::StackData; struct State { std::vector>>> m_functions; std::vector> m_function_objects; std::vector> m_boxed_functions; - std::map m_global_objects; + std::map m_global_objects; Type_Name_Map m_types; }; @@ -515,8 +516,7 @@ namespace chaiscript throw chaiscript::exception::name_conflict_error(t_name); } - stack_elem.emplace_back(t_name, std::move(obj)); - return stack_elem.back().second; + return stack_elem.emplace_back(t_name, std::move(obj)).second; } @@ -654,7 +654,7 @@ namespace chaiscript /// Searches the current stack for an object of the given name /// includes a special overload for the _ place holder object to /// ensure that it is always in scope. - Boxed_Value get_object(const std::string &name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const + Boxed_Value get_object(const std::string_view &name, std::atomic_uint_fast32_t &t_loc, Stack_Holder &t_holder) const { enum class Loc : uint_fast32_t { located = 0x80000000, @@ -719,7 +719,7 @@ namespace chaiscript } /// Returns the type info for a named type - Type_Info get_type(const std::string &name, bool t_throw = true) const + Type_Info get_type(std::string_view name, bool t_throw = true) const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -731,7 +731,7 @@ namespace chaiscript } if (t_throw) { - throw std::range_error("Type Not Known: " + name); + throw std::range_error("Type Not Known: " + std::string(name)); } else { return Type_Info(); } @@ -776,7 +776,7 @@ namespace chaiscript /// Return a function by name - std::pair>> get_function(const std::string &t_name, const size_t t_hint) const + std::pair>> get_function(const std::string_view &t_name, const size_t t_hint) const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -804,7 +804,7 @@ namespace chaiscript /// \returns a function object (Boxed_Value wrapper) if it exists /// \throws std::range_error if it does not /// \warn does not obtain a mutex lock. \sa get_function_object for public version - std::pair get_function_object_int(const std::string &t_name, const size_t t_hint) const + std::pair get_function_object_int(const std::string_view &t_name, const size_t t_hint) const { const auto &funs = get_boxed_functions_int(); @@ -814,13 +814,13 @@ namespace chaiscript { return std::make_pair(std::distance(funs.begin(), itr), itr->second); } else { - throw std::range_error("Object not found: " + t_name); + throw std::range_error("Object not found: " + std::string(t_name)); } } /// Return true if a function exists - bool function_exists(const std::string &name) const + bool function_exists(const std::string_view &name) const { chaiscript::detail::threading::shared_lock l(m_mutex); @@ -930,13 +930,13 @@ namespace chaiscript } - const Type_Conversions &conversions() const + const Type_Conversions &conversions() const noexcept { return m_conversions; } static bool is_attribute_call(const std::vector &t_funs, const std::vector &t_params, - bool t_has_params, const Type_Conversions_State &t_conversions) + bool t_has_params, const Type_Conversions_State &t_conversions) noexcept { if (!t_has_params || t_params.empty()) { return false; @@ -1049,7 +1049,7 @@ namespace chaiscript if (!functions.empty()) { try { if (is_no_param) { - std::vector tmp_params(params); + auto tmp_params(params); tmp_params.insert(tmp_params.begin() + 1, var(t_name)); return do_attribute_call(2, tmp_params, functions, t_conversions); } else { @@ -1076,14 +1076,13 @@ namespace chaiscript - Boxed_Value call_function(const std::string &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, + Boxed_Value call_function(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc, const std::vector ¶ms, const Type_Conversions_State &t_conversions) const { uint_fast32_t loc = t_loc; - const auto funs = get_function(t_name, loc); - if (funs.first != loc) { t_loc = uint_fast32_t(funs.first); -} - return dispatch::dispatch(*funs.second, params, t_conversions); + const auto [func_loc, func] = get_function(t_name, loc); + if (func_loc != loc) { t_loc = uint_fast32_t(func_loc); } + return dispatch::dispatch(*func, params, t_conversions); } @@ -1102,12 +1101,12 @@ namespace chaiscript /// Dump function to stdout void dump_function(const std::pair &f) const { - std::vector params = f.second->get_param_types(); + const auto params = f.second->get_param_types(); dump_type(params.front()); std::cout << " " << f.first << "("; - for (std::vector::const_iterator itr = params.begin() + 1; + for (auto itr = params.begin() + 1; itr != params.end(); ) { @@ -1132,7 +1131,7 @@ namespace chaiscript throw chaiscript::exception::arity_error(static_cast(params.size()), 1); } - const Const_Proxy_Function &f = this->boxed_cast(params[0]); + const auto &f = this->boxed_cast(params[0]); const Type_Conversions_State convs(m_conversions, m_conversions.conversion_saves()); return const_var(f->call_match(std::vector(params.begin() + 1, params.end()), convs)); @@ -1142,15 +1141,15 @@ namespace chaiscript void dump_system() const { std::cout << "Registered Types: \n"; - for (auto const &type: get_types()) + for (const auto &[type_name, type] : get_types() ) { - std::cout << type.first << ": " << type.second.bare_name() << '\n'; + std::cout << type_name << ": " << type.bare_name() << '\n'; } - std::cout << '\n'; + std::cout << '\n'; std::cout << "Functions: \n"; - for (auto const &func: get_functions()) + for (const auto &func : get_functions()) { dump_function(func); } @@ -1158,7 +1157,7 @@ namespace chaiscript } /// return true if the Boxed_Value matches the registered type by name - bool is_type(const Boxed_Value &r, const std::string &user_typename) const + bool is_type(const Boxed_Value &r, const std::string_view &user_typename) const noexcept { try { if (get_type(user_typename).bare_equal(r.get_type_info())) @@ -1264,66 +1263,66 @@ namespace chaiscript pop_function_call(*m_stack_holder, m_conversions.conversion_saves()); } - Stack_Holder &get_stack_holder() + Stack_Holder &get_stack_holder() noexcept { return *m_stack_holder; } /// Returns the current stack /// make const/non const versions - const StackData &get_stack_data() const + const StackData &get_stack_data() const noexcept { return m_stack_holder->stacks.back(); } - static StackData &get_stack_data(Stack_Holder &t_holder) + static StackData &get_stack_data(Stack_Holder &t_holder) noexcept { return t_holder.stacks.back(); } - StackData &get_stack_data() + StackData &get_stack_data() noexcept { return m_stack_holder->stacks.back(); } - parser::ChaiScript_Parser_Base &get_parser() + parser::ChaiScript_Parser_Base &get_parser() noexcept { return m_parser.get(); } private: - const std::vector> &get_boxed_functions_int() const + const std::vector> &get_boxed_functions_int() const noexcept { return m_state.m_boxed_functions; } - std::vector> &get_boxed_functions_int() + std::vector> &get_boxed_functions_int() noexcept { return m_state.m_boxed_functions; } - const std::vector> &get_function_objects_int() const + const std::vector> &get_function_objects_int() const noexcept { return m_state.m_function_objects; } - std::vector> &get_function_objects_int() + std::vector> &get_function_objects_int() noexcept { return m_state.m_function_objects; } - const std::vector>>> &get_functions_int() const + const std::vector>>> &get_functions_int() const noexcept { return m_state.m_functions; } - std::vector>>> &get_functions_int() + std::vector>>> &get_functions_int() noexcept { return m_state.m_functions; } - static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) + static bool function_less_than(const Proxy_Function &lhs, const Proxy_Function &rhs) noexcept { auto dynamic_lhs(std::dynamic_pointer_cast(lhs)); @@ -1355,8 +1354,8 @@ namespace chaiscript const auto lhssize = lhsparamtypes.size(); const auto rhssize = rhsparamtypes.size(); - static const auto boxed_type = user_type(); - static const auto boxed_pod_type = user_type(); + constexpr const auto boxed_type = user_type(); + constexpr const auto boxed_pod_type = user_type(); for (size_t i = 1; i < lhssize && i < rhssize; ++i) { @@ -1418,13 +1417,13 @@ namespace chaiscript t_c.reserve(t_c.size() + 1); // tightly control growth of memory usage here t_c.emplace_back(t_key, std::forward(t_value)); } else { - typedef typename Container::value_type value_type; + using value_type = typename Container::value_type; *itr = value_type(t_key, std::forward(t_value)); } } template - static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) + static typename Container::iterator find_keyed_value(Container &t_c, const Key &t_key) noexcept { return std::find_if(t_c.begin(), t_c.end(), [&t_key](const typename Container::value_type &o) { @@ -1433,16 +1432,16 @@ namespace chaiscript } template - static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) + static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key) noexcept { return std::find_if(t_c.begin(), t_c.end(), [&t_key](const typename Container::value_type &o) { - return o.first == t_key; + return std::equal(o.first.begin(), o.first.end(), t_key.begin(), t_key.end()); }); } template - static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) + static typename Container::const_iterator find_keyed_value(const Container &t_c, const Key &t_key, const size_t t_hint) noexcept { if (t_c.size() > t_hint && t_c[t_hint].first == t_key) { return std::next(t_c.begin(), static_cast::difference_type>(t_hint)); @@ -1519,23 +1518,23 @@ namespace chaiscript { } - Dispatch_Engine *operator->() const { + Dispatch_Engine *operator->() const noexcept { return &m_engine.get(); } - Dispatch_Engine &operator*() const { + Dispatch_Engine &operator*() const noexcept { return m_engine.get(); } - Stack_Holder &stack_holder() const { + Stack_Holder &stack_holder() const noexcept { return m_stack_holder.get(); } - const Type_Conversions_State &conversions() const { + const Type_Conversions_State &conversions() const noexcept { return m_conversions; } - Type_Conversions::Conversion_Saves &conversion_saves() const { + Type_Conversions::Conversion_Saves &conversion_saves() const noexcept { return m_conversions.saves(); } @@ -1547,7 +1546,7 @@ namespace chaiscript return m_engine.get().add_object(t_name, std::move(obj), m_stack_holder.get()); } - Boxed_Value get_object(const std::string &t_name, std::atomic_uint_fast32_t &t_loc) const { + Boxed_Value get_object(const std::string_view &t_name, std::atomic_uint_fast32_t &t_loc) const { return m_engine.get().get_object(t_name, t_loc, m_stack_holder.get()); } diff --git a/include/chaiscript/dispatchkit/dynamic_object.hpp b/include/chaiscript/dispatchkit/dynamic_object.hpp index 91514724..cd41b4b4 100644 --- a/include/chaiscript/dispatchkit/dynamic_object.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object.hpp @@ -50,17 +50,17 @@ namespace chaiscript Dynamic_Object() = default; - bool is_explicit() const + bool is_explicit() const noexcept { return m_option_explicit; } - void set_explicit(const bool t_explicit) + void set_explicit(const bool t_explicit) noexcept { m_option_explicit = t_explicit; } - std::string get_type_name() const + const std::string &get_type_name() const noexcept { return m_type_name; } diff --git a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp index 4a983746..a9034ed1 100644 --- a/include/chaiscript/dispatchkit/dynamic_object_detail.hpp +++ b/include/chaiscript/dispatchkit/dynamic_object_detail.hpp @@ -71,7 +71,7 @@ namespace chaiscript Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete; Dynamic_Object_Function(Dynamic_Object_Function &) = delete; - bool operator==(const Proxy_Function_Base &f) const override + bool operator==(const Proxy_Function_Base &f) const noexcept override { if (const auto *df = dynamic_cast(&f)) { @@ -81,9 +81,9 @@ namespace chaiscript } } - bool is_attribute_function() const override { return m_is_attribute; } + bool is_attribute_function() const noexcept override { return m_is_attribute; } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override { if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions)) { @@ -109,7 +109,7 @@ namespace chaiscript } } - bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const override + bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept override { return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions); } @@ -127,7 +127,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const noexcept { if (bv.get_type_info().bare_equal(m_doti)) { @@ -149,7 +149,7 @@ namespace chaiscript } bool dynamic_object_typename_match(const std::vector &bvs, const std::string &name, - const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const + const std::unique_ptr &ti, const Type_Conversions_State &t_conversions) const noexcept { if (!bvs.empty()) { @@ -199,7 +199,7 @@ namespace chaiscript return std::vector(begin, end); } - bool operator==(const Proxy_Function_Base &f) const override + bool operator==(const Proxy_Function_Base &f) const noexcept override { const Dynamic_Object_Constructor *dc = dynamic_cast(&f); return (dc != nullptr) && dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func); diff --git a/include/chaiscript/dispatchkit/exception_specification.hpp b/include/chaiscript/dispatchkit/exception_specification.hpp index 53ef3920..9b107cc3 100644 --- a/include/chaiscript/dispatchkit/exception_specification.hpp +++ b/include/chaiscript/dispatchkit/exception_specification.hpp @@ -46,7 +46,7 @@ namespace chaiscript { void handle(const Boxed_Value &bv, const Dispatch_Engine &t_engine) override { - (void)std::initializer_list{(throw_type(bv, t_engine), 0)...}; + (throw_type(bv, t_engine), ...); } }; } @@ -101,7 +101,7 @@ namespace chaiscript /// /// \sa chaiscript::exception_specification for creation of chaiscript::Exception_Handler objects /// \sa \ref exceptions - typedef std::shared_ptr Exception_Handler; + using Exception_Handler = std::shared_ptr; /// \brief creates a chaiscript::Exception_Handler which handles one type of exception unboxing /// \sa \ref exceptions diff --git a/include/chaiscript/dispatchkit/function_call.hpp b/include/chaiscript/dispatchkit/function_call.hpp index 33f08e5a..067158dd 100644 --- a/include/chaiscript/dispatchkit/function_call.hpp +++ b/include/chaiscript/dispatchkit/function_call.hpp @@ -18,7 +18,6 @@ #include "boxed_cast.hpp" #include "function_call_detail.hpp" #include "proxy_functions.hpp" -#include "callable_traits.hpp" namespace chaiscript { class Boxed_Value; @@ -32,6 +31,15 @@ namespace chaiscript { namespace dispatch { + namespace detail + { + template + constexpr auto arity(Ret (*)(Param...)) noexcept + { + return sizeof...(Param); + } + } + /// Build a function caller that knows how to dispatch on a set of functions /// example: /// std::function f = @@ -43,7 +51,7 @@ namespace chaiscript { const bool has_arity_match = std::any_of(funcs.begin(), funcs.end(), [](const Const_Proxy_Function &f) { - return f->get_arity() == -1 || size_t(f->get_arity()) == chaiscript::dispatch::detail::Arity::arity; + return f->get_arity() == -1 || size_t(f->get_arity()) == detail::arity(static_cast(nullptr)); }); if (!has_arity_match) { diff --git a/include/chaiscript/dispatchkit/function_call_detail.hpp b/include/chaiscript/dispatchkit/function_call_detail.hpp index 028ccbbc..e482a287 100644 --- a/include/chaiscript/dispatchkit/function_call_detail.hpp +++ b/include/chaiscript/dispatchkit/function_call_detail.hpp @@ -129,7 +129,7 @@ namespace chaiscript } template - static Boxed_Value box(Boxed_Value bv) + static Boxed_Value box(Boxed_Value bv) noexcept { return bv; } diff --git a/include/chaiscript/dispatchkit/function_signature.hpp b/include/chaiscript/dispatchkit/function_signature.hpp new file mode 100644 index 00000000..11c780a4 --- /dev/null +++ b/include/chaiscript/dispatchkit/function_signature.hpp @@ -0,0 +1,124 @@ +#ifndef CHAISCRIPT_FUNCTION_SIGNATURE_HPP +#define CHAISCRIPT_FUNCTION_SIGNATURE_HPP + +#include + +namespace chaiscript::dispatch::detail { + template + struct Function_Params + { + }; + + template + struct Function_Signature { + using Param_Types = Params; + using Return_Type = Ret; + constexpr static const bool is_object = IsObject; + constexpr static const bool is_member_object = IsMemberObject; + constexpr static const bool is_noexcept = IsNoExcept; + template + constexpr Function_Signature(T &&) noexcept {} + constexpr Function_Signature() noexcept = default; + }; + + // Free functions + + template + Function_Signature(Ret (*f)(Param...)) -> Function_Signature>; + + template + Function_Signature(Ret (*f)(Param...) noexcept) -> Function_Signature, true>; + + // no reference specifier + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile const) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile const noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) ) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) const) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) const noexcept) -> Function_Signature, true, true>; + + // & reference specifier + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile &) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile & noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile const &) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile const & noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) & ) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) & noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) const &) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) const & noexcept) -> Function_Signature, true, true>; + + // && reference specifier + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile &&) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile && noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile const &&) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) volatile const && noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) &&) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) && noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) const &&) -> Function_Signature, false, true>; + + template + Function_Signature(Ret (Class::*f)(Param ...) const && noexcept) -> Function_Signature, true, true>; + + template + Function_Signature(Ret (Class::*f)) -> Function_Signature, true, true, true>; + + template + Function_Signature(Func &&) -> Function_Signature< + typename decltype(Function_Signature{&std::decay_t::operator()})::Return_Type, + typename decltype(Function_Signature{&std::decay_t::operator()})::Param_Types, + decltype(Function_Signature{&std::decay_t::operator()})::is_noexcept, + false, + false, + true + >; +} + +#endif diff --git a/include/chaiscript/dispatchkit/handle_return.hpp b/include/chaiscript/dispatchkit/handle_return.hpp index ea6b4dff..7f611a6f 100644 --- a/include/chaiscript/dispatchkit/handle_return.hpp +++ b/include/chaiscript/dispatchkit/handle_return.hpp @@ -199,7 +199,7 @@ namespace chaiscript template<> struct Handle_Return { - static Boxed_Value handle(const Boxed_Value &r) + static Boxed_Value handle(const Boxed_Value &r) noexcept { return r; } @@ -226,7 +226,7 @@ namespace chaiscript template<> struct Handle_Return { - static Boxed_Value handle(const Boxed_Number &r) + static Boxed_Value handle(const Boxed_Number &r) noexcept { return r.bv; } diff --git a/include/chaiscript/dispatchkit/proxy_constructors.hpp b/include/chaiscript/dispatchkit/proxy_constructors.hpp index cfa5c775..721d18ec 100644 --- a/include/chaiscript/dispatchkit/proxy_constructors.hpp +++ b/include/chaiscript/dispatchkit/proxy_constructors.hpp @@ -19,14 +19,15 @@ namespace chaiscript { namespace detail { - template Proxy_Function build_constructor_(Class (*)(Params...)) { - auto call = dispatch::detail::Constructor(); + auto call = [](auto && ... param){ + return Class(std::forward(param)...); + }; return Proxy_Function( - chaiscript::make_shared (Params...), decltype(call)>>(call)); + chaiscript::make_shared>(call)); } } } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index fb9bc2d1..48a74125 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -41,7 +41,7 @@ namespace chaiscript class Boxed_Number; struct AST_Node; - typedef std::unique_ptr AST_NodePtr; + using AST_NodePtr = std::unique_ptr; namespace dispatch { @@ -52,14 +52,12 @@ namespace chaiscript { public: Param_Types() - : m_has_types(false), - m_doti(user_type()) + : m_has_types(false) {} explicit Param_Types(std::vector> t_types) : m_types(std::move(t_types)), - m_has_types(false), - m_doti(user_type()) + m_has_types(false) { update_has_types(); } @@ -70,20 +68,21 @@ namespace chaiscript update_has_types(); } - bool operator==(const Param_Types &t_rhs) const + bool operator==(const Param_Types &t_rhs) const noexcept { return m_types == t_rhs.m_types; } std::vector convert(std::vector vals, const Type_Conversions_State &t_conversions) const { + constexpr auto dynamic_object_type_info = user_type(); for (size_t i = 0; i < vals.size(); ++i) { const auto &name = m_types[i].first; if (!name.empty()) { const auto &bv = vals[i]; - if (!bv.get_type_info().bare_equal(m_doti)) + if (!bv.get_type_info().bare_equal(dynamic_object_type_info)) { const auto &ti = m_types[i].second; if (!ti.is_undef()) @@ -114,8 +113,9 @@ namespace chaiscript // first result: is a match // second result: needs conversions - std::pair match(const std::vector &vals, const Type_Conversions_State &t_conversions) const + std::pair match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept { + constexpr auto dynamic_object_type_info = user_type(); bool needs_conversion = false; if (!m_has_types) { return std::make_pair(true, needs_conversion); } @@ -127,7 +127,7 @@ namespace chaiscript if (!name.empty()) { const auto &bv = vals[i]; - if (bv.get_type_info().bare_equal(m_doti)) + if (bv.get_type_info().bare_equal(dynamic_object_type_info)) { try { const Dynamic_Object &d = boxed_cast(bv, &t_conversions); @@ -158,7 +158,7 @@ namespace chaiscript return std::make_pair(true, needs_conversion); } - const std::vector> &types() const + const std::vector> &types() const noexcept { return m_types; } @@ -180,7 +180,6 @@ namespace chaiscript std::vector> m_types; bool m_has_types; - Type_Info m_doti; }; @@ -210,14 +209,14 @@ namespace chaiscript /// if the function is variadic or takes no arguments (arity of 0 or -1), the returned /// value contains exactly 1 Type_Info object: the return type /// \returns the types of all parameters. - const std::vector &get_param_types() const { return m_types; } + const std::vector &get_param_types() const noexcept { return m_types; } - virtual bool operator==(const Proxy_Function_Base &) const = 0; + virtual bool operator==(const Proxy_Function_Base &) const noexcept = 0; virtual bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const = 0; - virtual bool is_attribute_function() const { return false; } + virtual bool is_attribute_function() const noexcept { return false; } - bool has_arithmetic_param() const + bool has_arithmetic_param() const noexcept { return m_has_arithmetic_param; } @@ -229,7 +228,7 @@ namespace chaiscript //! Return true if the function is a possible match //! to the passed in values - bool filter(const std::vector &vals, const Type_Conversions_State &t_conversions) const + bool filter(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept { assert(m_arity == -1 || (m_arity > 0 && static_cast(vals.size()) == m_arity)); @@ -244,19 +243,23 @@ namespace chaiscript } /// \returns the number of arguments the function takes or -1 if it is variadic - int get_arity() const + int get_arity() const noexcept { return m_arity; } - static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) + static bool compare_type_to_param(const Type_Info &ti, const Boxed_Value &bv, const Type_Conversions_State &t_conversions) noexcept { + constexpr auto boxed_value_ti = user_type(); + constexpr auto boxed_number_ti = user_type(); + constexpr auto function_ti = user_type>(); + if (ti.is_undef() - || ti.bare_equal(user_type()) + || ti.bare_equal(boxed_value_ti) || (!bv.get_type_info().is_undef() - && ( (ti.bare_equal(user_type()) && bv.get_type_info().is_arithmetic()) + && ( (ti.bare_equal(boxed_number_ti) && bv.get_type_info().is_arithmetic()) || ti.bare_equal(bv.get_type_info()) - || bv.get_type_info().bare_equal(user_type >()) + || bv.get_type_info().bare_equal(function_ti) || t_conversions->converts(ti, bv.get_type_info()) ) ) @@ -268,8 +271,9 @@ namespace chaiscript } } - virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const + virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions_State &t_conversions) const noexcept { + /// TODO is m_types guaranteed to be at least 2?? return compare_type_to_param(m_types[1], bv, t_conversions); } @@ -292,7 +296,7 @@ namespace chaiscript static bool compare_types(const std::vector &tis, const std::vector &bvs, - const Type_Conversions_State &t_conversions) + const Type_Conversions_State &t_conversions) noexcept { if (tis.size() - 1 != bvs.size()) { @@ -314,11 +318,11 @@ namespace chaiscript } /// \brief Common typedef used for passing of any registered function in ChaiScript - typedef std::shared_ptr Proxy_Function; + using Proxy_Function = std::shared_ptr; /// \brief Const version of Proxy_Function. Points to a const Proxy_Function. This is how most registered functions /// are handled internally. - typedef std::shared_ptr Const_Proxy_Function; + using Const_Proxy_Function = std::shared_ptr; namespace exception { @@ -358,7 +362,7 @@ namespace chaiscript } - bool operator==(const Proxy_Function_Base &rhs) const override + bool operator==(const Proxy_Function_Base &rhs) const noexcept override { const Dynamic_Proxy_Function *prhs = dynamic_cast(&rhs); @@ -374,13 +378,17 @@ namespace chaiscript return call_match_internal(vals, t_conversions).first; } + bool has_guard() const noexcept + { + return bool(m_guard); + } - Proxy_Function get_guard() const + Proxy_Function get_guard() const noexcept { return m_guard; } - bool has_parse_tree() const { + bool has_parse_tree() const noexcept { return static_cast(m_parsenode); } @@ -528,7 +536,7 @@ namespace chaiscript assert(m_f->get_arity() < 0 || m_f->get_arity() == static_cast(m_args.size())); } - bool operator==(const Proxy_Function_Base &t_f) const override + bool operator==(const Proxy_Function_Base &t_f) const noexcept override { return &t_f == this; } @@ -620,13 +628,13 @@ namespace chaiscript { } - bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool call_match(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override { return static_cast(vals.size()) == get_arity() && (compare_types(m_types, vals, t_conversions) && compare_types_with_cast(vals, t_conversions)); } - virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const = 0; + virtual bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept = 0; }; @@ -642,12 +650,12 @@ namespace chaiscript { } - bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override { return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } - bool operator==(const Proxy_Function_Base &t_func) const override + bool operator==(const Proxy_Function_Base &t_func) const noexcept override { return dynamic_cast *>(&t_func) != nullptr; } @@ -656,7 +664,7 @@ namespace chaiscript protected: Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override { - return detail::call_func(detail::Function_Signature(), m_f, params, t_conversions); + return detail::call_func(static_cast(nullptr), m_f, params, t_conversions); } private: @@ -686,12 +694,12 @@ namespace chaiscript assert(!m_shared_ptr_holder || m_shared_ptr_holder.get() == &m_f.get()); } - bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const override + bool compare_types_with_cast(const std::vector &vals, const Type_Conversions_State &t_conversions) const noexcept override { return detail::compare_types_cast(static_cast(nullptr), vals, t_conversions); } - bool operator==(const Proxy_Function_Base &t_func) const override + bool operator==(const Proxy_Function_Base &t_func) const noexcept override { return dynamic_cast *>(&t_func) != nullptr; } @@ -708,7 +716,7 @@ namespace chaiscript protected: Boxed_Value do_call(const std::vector ¶ms, const Type_Conversions_State &t_conversions) const override { - return detail::call_func(detail::Function_Signature(), m_f.get(), params, t_conversions); + return detail::call_func(static_cast(nullptr), m_f.get(), params, t_conversions); } @@ -729,9 +737,9 @@ namespace chaiscript { } - bool is_attribute_function() const override { return true; } + bool is_attribute_function() const noexcept override { return true; } - bool operator==(const Proxy_Function_Base &t_func) const override + bool operator==(const Proxy_Function_Base &t_func) const noexcept override { const Attribute_Access * aa = dynamic_cast *>(&t_func); @@ -743,14 +751,14 @@ namespace chaiscript } } - bool call_match(const std::vector &vals, const Type_Conversions_State &) const override + bool call_match(const std::vector &vals, const Type_Conversions_State &) const noexcept override { if (vals.size() != 1) { return false; } - - return vals[0].get_type_info().bare_equal(user_type()); + constexpr auto class_type_info = user_type(); + return vals[0].get_type_info().bare_equal(class_type_info); } protected: @@ -769,36 +777,32 @@ namespace chaiscript private: template - auto do_call_impl(Class *o) const -> std::enable_if_t::value, Boxed_Value> + auto do_call_impl(Class *o) const { - return detail::Handle_Return::handle(o->*m_attr); + if constexpr(std::is_pointer::value) { + return detail::Handle_Return::handle(o->*m_attr); + } else { + return detail::Handle_Return::type>::handle(o->*m_attr); + } } template - auto do_call_impl(const Class *o) const -> std::enable_if_t::value, Boxed_Value> + auto do_call_impl(const Class *o) const { - return detail::Handle_Return::handle(o->*m_attr); + if constexpr(std::is_pointer::value) { + return detail::Handle_Return::handle(o->*m_attr); + } else { + return detail::Handle_Return::type>::type>::handle(o->*m_attr); + } } - template - auto do_call_impl(Class *o) const -> std::enable_if_t::value, Boxed_Value> - { - return detail::Handle_Return::type>::handle(o->*m_attr); - } - - template - auto do_call_impl(const Class *o) const -> std::enable_if_t::value, Boxed_Value> - { - return detail::Handle_Return::type>::type>::handle(o->*m_attr); - } - - static std::vector param_types() { return {user_type(), user_type()}; } + std::vector m_param_types{user_type(), user_type()}; T Class::* m_attr; }; } @@ -841,7 +845,7 @@ namespace chaiscript { template bool types_match_except_for_arithmetic(const FuncType &t_func, const std::vector &plist, - const Type_Conversions_State &t_conversions) + const Type_Conversions_State &t_conversions) noexcept { const std::vector &types = t_func->get_param_types(); diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index f2c89bad..5f5d3ac8 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -21,7 +21,6 @@ #include "boxed_value.hpp" #include "handle_return.hpp" #include "type_info.hpp" -#include "callable_traits.hpp" namespace chaiscript { class Type_Conversions_State; @@ -78,14 +77,11 @@ namespace chaiscript */ template bool compare_types_cast(Ret (*)(Params...), - const std::vector ¶ms, const Type_Conversions_State &t_conversions) + const std::vector ¶ms, const Type_Conversions_State &t_conversions) noexcept { try { std::vector::size_type i = 0; - (void)i; - (void)params; (void)t_conversions; - // this is ok because the order of evaluation of initializer lists is well defined - (void)std::initializer_list{(boxed_cast(params[i++], &t_conversions), 0)...}; + ( boxed_cast(params[i++], &t_conversions), ... ); return true; } catch (const exception::bad_boxed_cast &) { return false; @@ -94,11 +90,11 @@ namespace chaiscript template - Ret call_func(const chaiscript::dispatch::detail::Function_Signature &, + Ret call_func(Ret (*)(Params...), std::index_sequence, const Callable &f, - const std::vector ¶ms, const Type_Conversions_State &t_conversions) + [[maybe_unused]] const std::vector ¶ms, + [[maybe_unused]] const Type_Conversions_State &t_conversions) { - (void)params; (void)t_conversions; return f(boxed_cast(params[I], &t_conversions)...); } @@ -108,26 +104,15 @@ namespace chaiscript /// if any unboxing fails the execution of the function fails and /// the bad_boxed_cast is passed up to the caller. template - Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature &sig, const Callable &f, + Boxed_Value call_func(Ret (*sig)(Params...), const Callable &f, const std::vector ¶ms, const Type_Conversions_State &t_conversions) { - return Handle_Return::handle(call_func(sig, std::index_sequence_for{}, f, params, t_conversions)); - } - - template - Boxed_Value call_func(const chaiscript::dispatch::detail::Function_Signature &sig, const Callable &f, - const std::vector ¶ms, const Type_Conversions_State &t_conversions) - { - call_func(sig, std::index_sequence_for{}, f, params, t_conversions); -#ifdef CHAISCRIPT_MSVC -#pragma warning(push) -#pragma warning(disable : 4702) -#endif - // MSVC is reporting that this is unreachable code - and it's wrong. - return Handle_Return::handle(); -#ifdef CHAISCRIPT_MSVC -#pragma warning(pop) -#endif + if constexpr (std::is_same_v) { + call_func(sig, std::index_sequence_for{}, f, params, t_conversions); + return Handle_Return::handle(); + } else { + return Handle_Return::handle(call_func(sig, std::index_sequence_for{}, f, params, t_conversions)); + } } } diff --git a/include/chaiscript/dispatchkit/register_function.hpp b/include/chaiscript/dispatchkit/register_function.hpp index 1fc44469..907b0035 100644 --- a/include/chaiscript/dispatchkit/register_function.hpp +++ b/include/chaiscript/dispatchkit/register_function.hpp @@ -15,9 +15,54 @@ #include "bind_first.hpp" #include "proxy_functions.hpp" +#include "function_signature.hpp" namespace chaiscript { + namespace dispatch::detail + { + template + Param1 get_first_param(Function_Params, Obj &&obj) + { + return static_cast(std::forward(obj)); + } + + template + auto make_callable_impl(Func &&func, Function_Signature, Is_Noexcept, Is_Member, Is_MemberObject, Is_Object>) + { + if constexpr (Is_MemberObject) { + // we now that the Param pack will have only one element, so we are safe expanding it here + return Proxy_Function(chaiscript::make_shared...>>(std::forward(func))); + } else if constexpr (Is_Member) { + auto call = [func = std::forward(func)](auto && obj, auto && ... param) noexcept(Is_Noexcept) -> decltype(auto) { + return (( get_first_param(Function_Params{}, obj).*func )(std::forward(param)...)); + }; + return Proxy_Function( + chaiscript::make_shared>(std::move(call)) + ); + } else { + return Proxy_Function( + chaiscript::make_shared>>(std::forward(func)) + ); + } + } + + // this version peels off the function object itself from the function signature, when used + // on a callable object + template + auto make_callable(Func &&func, Function_Signature, Is_Noexcept, false, false, true>) + { + return make_callable_impl(std::forward(func), Function_Signature, Is_Noexcept, false, false, true>{}); + } + + template + auto make_callable(Func &&func, Function_Signature, Is_Noexcept, Is_Member, Is_MemberObject, false> fs) + { + return make_callable_impl(std::forward(func), fs); + } + } /// \brief Creates a new Proxy_Function object from a free function, member function or data member /// \param[in] t Function / member to expose @@ -40,85 +85,12 @@ namespace chaiscript /// /// \sa \ref adding_functions template - Proxy_Function fun(const T &t) + Proxy_Function fun(T &&t) { - typedef typename dispatch::detail::Callable_Traits::Signature Signature; - - return Proxy_Function( - chaiscript::make_shared>(t)); + return dispatch::detail::make_callable(std::forward(t), dispatch::detail::Function_Signature{t}); } - template - Proxy_Function fun(Ret (*func)(Param...)) - { - auto fun_call = dispatch::detail::Fun_Caller(func); - - return Proxy_Function( - chaiscript::make_shared>(fun_call)); - - } - - template - Proxy_Function fun(Ret (Class::*t_func)(Param...) const) - { - auto call = dispatch::detail::Const_Caller(t_func); - - return Proxy_Function( - chaiscript::make_shared>(call)); - } - - template - Proxy_Function fun(Ret (Class::*t_func)(Param...)) - { - auto call = dispatch::detail::Caller(t_func); - - return Proxy_Function( - chaiscript::make_shared>(call)); - - } - - template::value>::type*/> - Proxy_Function fun(T Class::* m /*, typename std::enable_if::value>::type* = 0*/ ) - { - return Proxy_Function(chaiscript::make_shared>(m)); - } - -// only compile this bit if noexcept is part of the type system -// -#if (defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510) || (defined(_NOEXCEPT_TYPES_SUPPORTED) && _MSC_VER >= 1912) - template - Proxy_Function fun(Ret (*func)(Param...) noexcept) - { - auto fun_call = dispatch::detail::Fun_Caller(func); - - return Proxy_Function( - chaiscript::make_shared>(fun_call)); - - } - - template - Proxy_Function fun(Ret (Class::*t_func)(Param...) const noexcept) - { - auto call = dispatch::detail::Const_Caller(t_func); - - return Proxy_Function( - chaiscript::make_shared>(call)); - } - - template - Proxy_Function fun(Ret (Class::*t_func)(Param...) noexcept) - { - auto call = dispatch::detail::Caller(t_func); - - return Proxy_Function( - chaiscript::make_shared>(call)); - - } -#endif - - - /// \brief Creates a new Proxy_Function object from a free function, member function or data member and binds the first parameter of it /// \param[in] t Function / member to expose @@ -145,6 +117,7 @@ namespace chaiscript } + } diff --git a/include/chaiscript/dispatchkit/type_conversions.hpp b/include/chaiscript/dispatchkit/type_conversions.hpp index a333943c..8b57d79c 100644 --- a/include/chaiscript/dispatchkit/type_conversions.hpp +++ b/include/chaiscript/dispatchkit/type_conversions.hpp @@ -20,6 +20,7 @@ #include #include "../chaiscript_threading.hpp" +#include "../utility/static_string.hpp" #include "bad_boxed_cast.hpp" #include "boxed_cast_helper.hpp" #include "boxed_value.hpp" @@ -33,7 +34,7 @@ namespace chaiscript { public: bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, - const std::string &t_what) noexcept + const utility::Static_String &t_what) noexcept : bad_boxed_cast(t_from, t_to, t_what) { } @@ -43,7 +44,7 @@ namespace chaiscript { } - explicit bad_boxed_dynamic_cast(const std::string &w) noexcept + explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept : bad_boxed_cast(w) { } @@ -57,7 +58,7 @@ namespace chaiscript { public: bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to, - const std::string &t_what) noexcept + const utility::Static_String &t_what) noexcept : bad_boxed_cast(t_from, t_to, t_what) { } @@ -67,7 +68,7 @@ namespace chaiscript { } - explicit bad_boxed_type_cast(const std::string &w) noexcept + explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept : bad_boxed_cast(w) { } @@ -87,16 +88,16 @@ namespace chaiscript virtual Boxed_Value convert(const Boxed_Value &from) const = 0; virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0; - const Type_Info &to() const + const Type_Info &to() const noexcept { return m_to; } - const Type_Info &from() const + const Type_Info &from() const noexcept { return m_from; } - virtual bool bidir() const + virtual bool bidir() const noexcept { return true; } @@ -122,6 +123,7 @@ namespace chaiscript public: static Boxed_Value cast(const Boxed_Value &t_from) { + if (t_from.get_type_info().bare_equal(chaiscript::user_type())) { if (t_from.is_pointer()) @@ -272,7 +274,7 @@ namespace chaiscript "Unable to cast down inheritance hierarchy with non-polymorphic types"); } - bool bidir() const override + bool bidir() const noexcept override { return false; } @@ -306,7 +308,7 @@ namespace chaiscript return m_func(t_from); } - bool bidir() const override + bool bidir() const noexcept override { return false; } @@ -328,7 +330,7 @@ namespace chaiscript struct Less_Than { - bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const + bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept { return *t_lhs != *t_rhs && t_lhs->before(*t_rhs); } @@ -370,18 +372,19 @@ namespace chaiscript } template - bool convertable_type() const + bool convertable_type() const noexcept { - return thread_cache().count(user_type().bare_type_info()) != 0; + constexpr auto type = user_type().bare_type_info(); + return thread_cache().count(type) != 0; } template - bool converts() const + bool converts() const noexcept { return converts(user_type(), user_type()); } - bool converts(const Type_Info &to, const Type_Info &from) const + bool converts(const Type_Info &to, const Type_Info &from) const noexcept { const auto &types = thread_cache(); if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0) @@ -459,11 +462,11 @@ namespace chaiscript { return *itr; } else { - throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name()); + throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name()); } } - Conversion_Saves &conversion_saves() const { + Conversion_Saves &conversion_saves() const noexcept { return *m_conversion_saves; } @@ -518,15 +521,15 @@ namespace chaiscript { } - const Type_Conversions *operator->() const { + const Type_Conversions *operator->() const noexcept { return &m_conversions.get(); } - const Type_Conversions *get() const { + const Type_Conversions *get() const noexcept { return &m_conversions.get(); } - Type_Conversions::Conversion_Saves &saves() const { + Type_Conversions::Conversion_Saves &saves() const noexcept { return m_saves; } @@ -535,7 +538,7 @@ namespace chaiscript std::reference_wrapper m_saves; }; - typedef std::shared_ptr Type_Conversion; + using Type_Conversion = std::shared_ptr; /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you /// want automatic conversions up your inheritance hierarchy. @@ -559,23 +562,17 @@ namespace chaiscript /// \endcode /// template - Type_Conversion base_class(typename std::enable_if::value && std::is_polymorphic::value>::type* = nullptr) + Type_Conversion base_class() { //Can only be used with related polymorphic types //may be expanded some day to support conversions other than child -> parent static_assert(std::is_base_of::value, "Classes are not related by inheritance"); - return chaiscript::make_shared>(); - } - - template - Type_Conversion base_class(typename std::enable_if::value || !std::is_polymorphic::value>::type* = nullptr) - { - //Can only be used with related polymorphic types - //may be expanded some day to support conversions other than child -> parent - static_assert(std::is_base_of::value, "Classes are not related by inheritance"); - - return chaiscript::make_shared>(); + if constexpr(std::is_polymorphic::value && std::is_polymorphic::value) { + return chaiscript::make_shared>(); + } else { + return chaiscript::make_shared>(); + } } diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index b76b5493..a8c00d03 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -24,7 +24,7 @@ namespace chaiscript template struct Bare_Type { - typedef typename std::remove_cv::type>::type>::type type; + using type = typename std::remove_cv::type>::type>::type; }; } @@ -34,7 +34,7 @@ namespace chaiscript { public: constexpr Type_Info(const bool t_is_const, const bool t_is_reference, const bool t_is_pointer, const bool t_is_void, - const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) + const bool t_is_arithmetic, const std::type_info *t_ti, const std::type_info *t_bare_ti) noexcept : m_type_info(t_ti), m_bare_type_info(t_bare_ti), m_flags((static_cast(t_is_const) << is_const_flag) + (static_cast(t_is_reference) << is_reference_flag) @@ -44,7 +44,7 @@ namespace chaiscript { } - constexpr Type_Info() = default; + constexpr Type_Info() noexcept = default; bool operator<(const Type_Info &ti) const noexcept { @@ -90,7 +90,7 @@ namespace chaiscript constexpr bool is_undef() const noexcept { return (m_flags & (1 << is_undef_flag)) != 0; } constexpr bool is_pointer() const noexcept { return (m_flags & (1 << is_pointer_flag)) != 0; } - std::string name() const + const char * name() const noexcept { if (!is_undef()) { @@ -100,7 +100,7 @@ namespace chaiscript } } - std::string bare_name() const + const char * bare_name() const noexcept { if (!is_undef()) { @@ -110,7 +110,7 @@ namespace chaiscript } } - constexpr const std::type_info *bare_type_info() const + constexpr const std::type_info *bare_type_info() const noexcept { return m_bare_type_info; } @@ -135,7 +135,7 @@ namespace chaiscript template struct Get_Type_Info { - static constexpr Type_Info get() + constexpr static Type_Info get() noexcept { return Type_Info(std::is_const::type>::type>::value, std::is_reference::value, std::is_pointer::value, @@ -152,7 +152,7 @@ namespace chaiscript { // typedef T type; - static constexpr Type_Info get() + constexpr static Type_Info get() noexcept { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, @@ -170,7 +170,7 @@ namespace chaiscript template struct Get_Type_Info &> { - static constexpr Type_Info get() + constexpr static Type_Info get() noexcept { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, @@ -183,7 +183,7 @@ namespace chaiscript template struct Get_Type_Info > { - static constexpr Type_Info get() + constexpr static Type_Info get() noexcept { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, @@ -196,7 +196,7 @@ namespace chaiscript template struct Get_Type_Info &> { - static constexpr Type_Info get() + constexpr static Type_Info get() noexcept { return Type_Info(std::is_const::value, std::is_reference::value, std::is_pointer::value, std::is_void::value, @@ -218,7 +218,7 @@ namespace chaiscript /// chaiscript::Type_Info ti = chaiscript::user_type(i); /// \endcode template - constexpr Type_Info user_type(const T &/*t*/) + constexpr Type_Info user_type(const T &/*t*/) noexcept { return detail::Get_Type_Info::get(); } @@ -233,7 +233,7 @@ namespace chaiscript /// chaiscript::Type_Info ti = chaiscript::user_type(); /// \endcode template - constexpr Type_Info user_type() + constexpr Type_Info user_type() noexcept { return detail::Get_Type_Info::get(); } diff --git a/include/chaiscript/language/chaiscript_algebraic.hpp b/include/chaiscript/language/chaiscript_algebraic.hpp index 8f4a1b27..d153fe67 100644 --- a/include/chaiscript/language/chaiscript_algebraic.hpp +++ b/include/chaiscript/language/chaiscript_algebraic.hpp @@ -11,7 +11,7 @@ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_ -#include "../utility/fnv1a.hpp" +#include "../utility/hash.hpp" #include @@ -21,23 +21,18 @@ namespace chaiscript struct Operators { enum class Opers { - boolean_flag, equals, less_than, greater_than, less_than_equal, greater_than_equal, not_equal, - non_const_flag, assign, pre_increment, pre_decrement, assign_product, assign_sum, assign_quotient, assign_difference, - non_const_int_flag, assign_bitwise_and, assign_bitwise_or, assign_shift_left, assign_shift_right, assign_remainder, assign_bitwise_xor, - const_int_flag, shift_left, shift_right, remainder, bitwise_and, bitwise_or, bitwise_xor, bitwise_complement, - const_flag, sum, quotient, product, difference, unary_plus, unary_minus, invalid }; - static const char *to_string(Opers t_oper) { - static const char *opers[] = { + constexpr static const char *to_string(Opers t_oper) noexcept { + constexpr const char *opers[] = { "", "==", "<", ">", "<=", ">=", "!=", "", @@ -55,44 +50,44 @@ namespace chaiscript return opers[static_cast(t_oper)]; } - static Opers to_operator(const std::string &t_str, bool t_is_unary = false) + constexpr static Opers to_operator(const std::string_view &t_str, bool t_is_unary = false) noexcept { #ifdef CHAISCRIPT_MSVC #pragma warning(push) #pragma warning(disable : 4307) #endif - const auto op_hash = utility::fnv1a_32(t_str.c_str()); + const auto op_hash = utility::hash(t_str); switch (op_hash) { - case utility::fnv1a_32("=="): { return Opers::equals; } - case utility::fnv1a_32("<"): { return Opers::less_than; } - case utility::fnv1a_32(">"): { return Opers::greater_than; } - case utility::fnv1a_32("<="): { return Opers::less_than_equal; } - case utility::fnv1a_32(">="): { return Opers::greater_than_equal; } - case utility::fnv1a_32("!="): { return Opers::not_equal; } - case utility::fnv1a_32("="): { return Opers::assign; } - case utility::fnv1a_32("++"): { return Opers::pre_increment; } - case utility::fnv1a_32("--"): { return Opers::pre_decrement; } - case utility::fnv1a_32("*="): { return Opers::assign_product; } - case utility::fnv1a_32("+="): { return Opers::assign_sum; } - case utility::fnv1a_32("-="): { return Opers::assign_difference; } - case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; } - case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; } - case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; } - case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; } - case utility::fnv1a_32("%="): { return Opers::assign_remainder; } - case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; } - case utility::fnv1a_32("<<"): { return Opers::shift_left; } - case utility::fnv1a_32(">>"): { return Opers::shift_right; } - case utility::fnv1a_32("%"): { return Opers::remainder; } - case utility::fnv1a_32("&"): { return Opers::bitwise_and; } - case utility::fnv1a_32("|"): { return Opers::bitwise_or; } - case utility::fnv1a_32("^"): { return Opers::bitwise_xor; } - case utility::fnv1a_32("~"): { return Opers::bitwise_complement; } - case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } - case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } - case utility::fnv1a_32("/"): { return Opers::quotient; } - case utility::fnv1a_32("*"): { return Opers::product; } + case utility::hash("=="): { return Opers::equals; } + case utility::hash("<"): { return Opers::less_than; } + case utility::hash(">"): { return Opers::greater_than; } + case utility::hash("<="): { return Opers::less_than_equal; } + case utility::hash(">="): { return Opers::greater_than_equal; } + case utility::hash("!="): { return Opers::not_equal; } + case utility::hash("="): { return Opers::assign; } + case utility::hash("++"): { return Opers::pre_increment; } + case utility::hash("--"): { return Opers::pre_decrement; } + case utility::hash("*="): { return Opers::assign_product; } + case utility::hash("+="): { return Opers::assign_sum; } + case utility::hash("-="): { return Opers::assign_difference; } + case utility::hash("&="): { return Opers::assign_bitwise_and; } + case utility::hash("|="): { return Opers::assign_bitwise_or; } + case utility::hash("<<="): { return Opers::assign_shift_left; } + case utility::hash(">>="): { return Opers::assign_shift_right; } + case utility::hash("%="): { return Opers::assign_remainder; } + case utility::hash("^="): { return Opers::assign_bitwise_xor; } + case utility::hash("<<"): { return Opers::shift_left; } + case utility::hash(">>"): { return Opers::shift_right; } + case utility::hash("%"): { return Opers::remainder; } + case utility::hash("&"): { return Opers::bitwise_and; } + case utility::hash("|"): { return Opers::bitwise_or; } + case utility::hash("^"): { return Opers::bitwise_xor; } + case utility::hash("~"): { return Opers::bitwise_complement; } + case utility::hash("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } + case utility::hash("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } + case utility::hash("/"): { return Opers::quotient; } + case utility::hash("*"): { return Opers::product; } default: { return Opers::invalid; } } #ifdef CHAISCRIPT_MSVC diff --git a/include/chaiscript/language/chaiscript_common.hpp b/include/chaiscript/language/chaiscript_common.hpp index 4e107efb..06ad8e0b 100644 --- a/include/chaiscript/language/chaiscript_common.hpp +++ b/include/chaiscript/language/chaiscript_common.hpp @@ -23,6 +23,7 @@ #include "../dispatchkit/dispatchkit.hpp" #include "../dispatchkit/proxy_functions.hpp" #include "../dispatchkit/type_info.hpp" +#include namespace chaiscript { struct AST_Node; @@ -31,34 +32,59 @@ struct AST_Node; namespace chaiscript { struct Name_Validator { - static bool is_reserved_word(const std::string &name) + template + static bool is_reserved_word(const T &s) noexcept { - static const std::set m_reserved_words - = {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto", - "return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_", - "__LINE__", "__FILE__", "__FUNC__", "__CLASS__"}; - return m_reserved_words.count(name) > 0; + const static std::unordered_set words{ + utility::hash("def"), + utility::hash("fun"), + utility::hash("while"), + utility::hash("for"), + utility::hash("if"), + utility::hash("else"), + utility::hash("&&"), + utility::hash("||"), + utility::hash(","), + utility::hash("auto"), + utility::hash("return"), + utility::hash("break"), + utility::hash("true"), + utility::hash("false"), + utility::hash("class"), + utility::hash("attr"), + utility::hash("var"), + utility::hash("global"), + utility::hash("GLOBAL"), + utility::hash("_"), + utility::hash("__LINE__"), + utility::hash("__FILE__"), + utility::hash("__FUNC__"), + utility::hash("__CLASS__")}; + + return words.count(utility::hash(s)) == 1; } - static bool valid_object_name(const std::string &name) + template + static bool valid_object_name(const T &name) noexcept { return name.find("::") == std::string::npos && !is_reserved_word(name); } - static void validate_object_name(const std::string &name) + template + static void validate_object_name(const T &name) { if (is_reserved_word(name)) { - throw exception::reserved_word_error(name); + throw exception::reserved_word_error(std::string(name)); } if (name.find("::") != std::string::npos) { - throw exception::illegal_name_error(name); + throw exception::illegal_name_error(std::string(name)); } } }; /// Signature of module entry point that all binary loadable modules must implement. - typedef ModulePtr (*Create_Module_Func)(); + using Create_Module_Func = ModulePtr (*)(); /// Types of AST nodes available to the parser and eval @@ -76,8 +102,8 @@ namespace chaiscript namespace { /// Helper lookup to get the name of each node type - inline const char *ast_node_type_to_string(AST_Node_Type ast_node_type) { - static const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", + constexpr const char *ast_node_type_to_string(AST_Node_Type ast_node_type) noexcept { + constexpr const char * const ast_node_types[] = { "Id", "Fun_Call", "Unused_Return_Fun_Call", "Arg_List", "Equation", "Var_Decl", "Assign_Decl", "Array_Call", "Dot_Access", "Lambda", "Block", "Scopeless_Block", "Def", "While", "If", "For", "Ranged_For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range", "Inline_Range", "Try", "Catch", "Finally", "Method", "Attr_Decl", @@ -89,13 +115,13 @@ namespace chaiscript /// \brief Convenience type for file positions struct File_Position { - int line; - int column; + int line = 0; + int column = 0; - File_Position(int t_file_line, int t_file_column) + constexpr File_Position(int t_file_line, int t_file_column) noexcept : line(t_file_line), column(t_file_column) { } - File_Position() : line(0), column(0) { } + constexpr File_Position() noexcept = default; }; struct Parse_Location { @@ -124,8 +150,8 @@ namespace chaiscript /// \brief Typedef for pointers to AST_Node objects. Used in building of the AST_Node tree - typedef std::unique_ptr AST_NodePtr; - typedef std::unique_ptr AST_NodePtr_Const; + using AST_NodePtr = std::unique_ptr; + using AST_NodePtr_Const = std::unique_ptr; struct AST_Node_Trace; @@ -136,7 +162,7 @@ namespace chaiscript /// \brief Thrown if an error occurs while attempting to load a binary module struct load_module_error : std::runtime_error { - explicit load_module_error(const std::string &t_reason) noexcept + explicit load_module_error(const std::string &t_reason) : std::runtime_error(t_reason) { } @@ -228,7 +254,7 @@ namespace chaiscript private: template - static AST_Node_Type id(const T& t) + static AST_Node_Type id(const T& t) noexcept { return t.identifier; } @@ -240,7 +266,7 @@ namespace chaiscript } template - static const std::string &fname(const T& t) + static const std::string &fname(const T& t) noexcept { return t.filename(); } @@ -479,7 +505,7 @@ namespace chaiscript /// Errors generated when loading a file struct file_not_found_error : std::runtime_error { - explicit file_not_found_error(const std::string &t_filename) noexcept + explicit file_not_found_error(const std::string &t_filename) : std::runtime_error("File Not Found: " + t_filename), filename(t_filename) { } @@ -500,15 +526,15 @@ namespace chaiscript const std::string text; Parse_Location location; - const std::string &filename() const { + const std::string &filename() const noexcept { return *location.filename; } - const File_Position &start() const { + const File_Position &start() const noexcept { return location.start; } - const File_Position &end() const { + const File_Position &end() const noexcept { return location.end; } @@ -553,7 +579,7 @@ namespace chaiscript } - virtual ~AST_Node() = default; + virtual ~AST_Node() noexcept = default; AST_Node(AST_Node &&) = default; AST_Node &operator=(AST_Node &&) = default; AST_Node(const AST_Node &) = delete; @@ -576,15 +602,15 @@ namespace chaiscript const std::string text; Parse_Location location; - const std::string &filename() const { + const std::string &filename() const noexcept { return *location.filename; } - const File_Position &start() const { + const File_Position &start() const noexcept { return location.start; } - const File_Position &end() const { + const File_Position &end() const noexcept { return location.end; } @@ -632,7 +658,7 @@ namespace chaiscript ChaiScript_Parser_Base &operator=(const ChaiScript_Parser_Base &&) = delete; template - T &get_tracer() + T &get_tracer() noexcept { // to do type check this somehow? return *static_cast(get_tracer_ptr()); @@ -655,13 +681,11 @@ namespace chaiscript /// Special type indicating a call to 'break' struct Break_Loop { - Break_Loop() = default; }; /// Special type indicating a call to 'continue' struct Continue_Loop { - Continue_Loop() = default; }; diff --git a/include/chaiscript/language/chaiscript_engine.hpp b/include/chaiscript/language/chaiscript_engine.hpp index 404b836c..51d9f408 100644 --- a/include/chaiscript/language/chaiscript_engine.hpp +++ b/include/chaiscript/language/chaiscript_engine.hpp @@ -98,7 +98,7 @@ namespace chaiscript /// Evaluates the given file and looks in the 'use' paths - const Boxed_Value internal_eval_file(const std::string &t_filename) { + Boxed_Value internal_eval_file(const std::string &t_filename) { for (const auto &path : m_use_paths) { try { @@ -119,7 +119,7 @@ namespace chaiscript /// Evaluates the given string, used during eval() inside of a script - const Boxed_Value internal_eval(const std::string &t_e) { + Boxed_Value internal_eval(const std::string &t_e) { try { return do_eval(t_e, "__EVAL__", true); } catch (const exception::eval_error &t_ee) { @@ -128,7 +128,7 @@ namespace chaiscript } /// Returns the current evaluation m_engine - chaiscript::detail::Dispatch_Engine &get_eval_engine() { + chaiscript::detail::Dispatch_Engine &get_eval_engine() noexcept { return m_engine; } @@ -343,13 +343,13 @@ namespace chaiscript } } #else // CHAISCRIPT_NO_DYNLOAD -explicit ChaiScript_Basic(std::unique_ptr &&parser, - std::vector t_module_paths = {}, - std::vector t_use_paths = {}, - const std::vector &t_opts = chaiscript::default_options()) = delete; + explicit ChaiScript_Basic(std::unique_ptr &&parser, + std::vector t_module_paths = {}, + std::vector t_use_paths = {}, + const std::vector &t_opts = chaiscript::default_options()) = delete; #endif - parser::ChaiScript_Parser_Base &get_parser() + parser::ChaiScript_Parser_Base &get_parser() noexcept { return *m_parser; } @@ -594,7 +594,6 @@ explicit ChaiScript_Basic(std::unique_ptr &&pars std::string load_module(const std::string &t_module_name) { #ifdef CHAISCRIPT_NO_DYNLOAD - (void)t_module_name; // -Wunused-parameter throw chaiscript::exception::load_module_error("Loadable module support was disabled (CHAISCRIPT_NO_DYNLOAD)"); #else std::vector errors; diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index 83d00403..f9a3c9bb 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -34,11 +34,9 @@ #include "chaiscript_algebraic.hpp" #include "chaiscript_common.hpp" -namespace chaiscript { -namespace exception { +namespace chaiscript::exception { class bad_boxed_cast; -} // namespace exception -} // namespace chaiscript +} // namespace chaiscript::exception namespace chaiscript { @@ -57,8 +55,9 @@ namespace chaiscript chaiscript::detail::Dispatch_State state(t_ss); const Boxed_Value *thisobj = [&]() -> const Boxed_Value *{ - auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); - if (!stack.empty() && stack.back().first == "__this") { + if (auto &stack = t_ss.get_stack_data(state.stack_holder()).back(); + !stack.empty() && stack.back().first == "__this") + { return &stack.back().second; } else if (!t_vals.empty()) { return &t_vals[0]; @@ -71,8 +70,8 @@ namespace chaiscript if (thisobj && !has_this_capture) { state.add_object("this", *thisobj); } if (t_locals) { - for (const auto &local : *t_locals) { - state.add_object(local.first, local.second); + for (const auto &[name, value] : *t_locals) { + state.add_object(name, value); } } @@ -126,7 +125,7 @@ namespace chaiscript std::vector> get_children() const final { std::vector> retval; retval.reserve(children.size()); - for (auto &&child : children) { + for (auto &child : children) { retval.emplace_back(*child); } @@ -706,7 +705,7 @@ namespace chaiscript ); } - static bool has_this_capture(const std::vector> &children) { + static bool has_this_capture(const std::vector> &children) noexcept { return std::any_of(std::begin(children), std::end(children), [](const auto &child){ return child->children[0]->text == "this"; @@ -782,7 +781,7 @@ namespace chaiscript return std::move(vec.back()); } - static bool has_guard(const std::vector> &t_children, const std::size_t offset) + static bool has_guard(const std::vector> &t_children, const std::size_t offset) noexcept { if ((t_children.size() > 2 + offset) && (t_children[1+offset]->identifier == AST_Node_Type::Arg_List)) { if (t_children.size() > 3 + offset) { @@ -909,9 +908,9 @@ namespace chaiscript Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override{ const auto get_function = [&t_ss](const std::string &t_name, auto &t_hint){ uint_fast32_t hint = t_hint; - auto funs = t_ss->get_function(t_name, hint); - if (funs.first != hint) { t_hint = uint_fast32_t(funs.first); } - return std::move(funs.second); + auto [funs_loc, funs] = t_ss->get_function(t_name, hint); + if (funs_loc != hint) { t_hint = uint_fast32_t(funs_loc); } + return std::move(funs); }; const auto call_function = [&t_ss](const auto &t_funcs, const Boxed_Value &t_param) { diff --git a/include/chaiscript/language/chaiscript_optimizer.hpp b/include/chaiscript/language/chaiscript_optimizer.hpp index 53fdc833..04ae9725 100644 --- a/include/chaiscript/language/chaiscript_optimizer.hpp +++ b/include/chaiscript/language/chaiscript_optimizer.hpp @@ -24,13 +24,13 @@ namespace chaiscript { template auto optimize(eval::AST_Node_Impl_Ptr p) { - (void)std::initializer_list{ (p = static_cast(*this).optimize(std::move(p)), 0)... }; + ( (p = static_cast(*this).optimize(std::move(p))), ... ); return p; } }; template - eval::AST_Node_Impl &child_at(eval::AST_Node_Impl &node, const size_t offset) { + eval::AST_Node_Impl &child_at(eval::AST_Node_Impl &node, const size_t offset) noexcept { if (node.children[offset]->identifier == AST_Node_Type::Compiled) { return *(dynamic_cast &>(*node.children[offset]).m_original_node); } else { @@ -39,7 +39,7 @@ namespace chaiscript { } template - const eval::AST_Node_Impl &child_at(const eval::AST_Node_Impl &node, const size_t offset) { + const eval::AST_Node_Impl &child_at(const eval::AST_Node_Impl &node, const size_t offset) noexcept { if (node.children[offset]->identifier == AST_Node_Type::Compiled) { return *(dynamic_cast &>(*node.children[offset]).m_original_node); } else { @@ -57,7 +57,7 @@ namespace chaiscript { } template - auto child_count(const eval::AST_Node_Impl &node) { + auto child_count(const eval::AST_Node_Impl &node) noexcept { if (node.identifier == AST_Node_Type::Compiled) { return dynamic_cast&>(node).m_original_node->children.size(); } else { @@ -95,7 +95,7 @@ namespace chaiscript { }; template - bool contains_var_decl_in_scope(const eval::AST_Node_Impl &node) + bool contains_var_decl_in_scope(const eval::AST_Node_Impl &node) noexcept { if (node.identifier == AST_Node_Type::Var_Decl || node.identifier == AST_Node_Type::Assign_Decl || node.identifier == AST_Node_Type::Reference) { return true; @@ -469,3 +469,4 @@ namespace chaiscript { #endif + diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 1a401316..2c818abd 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -27,7 +27,7 @@ #include "chaiscript_common.hpp" #include "chaiscript_optimizer.hpp" #include "chaiscript_tracer.hpp" -#include "../utility/fnv1a.hpp" +#include "../utility/hash.hpp" #include "../utility/static_string.hpp" #if defined(CHAISCRIPT_UTF16_UTF32) @@ -76,7 +76,7 @@ namespace chaiscript // common for all implementations static std::string u8str_from_ll(long long val) { - typedef std::string::value_type char_type; + using char_type = std::string::value_type; char_type c[2]; c[1] = char_type(val); @@ -92,7 +92,7 @@ namespace chaiscript static string_type str_from_ll(long long val) { - typedef typename string_type::value_type target_char_type; + using target_char_type = typename string_type::value_type; #if defined (CHAISCRIPT_UTF16_UTF32) // prepare converter std::wstring_convert, target_char_type> converter; @@ -120,7 +120,7 @@ namespace chaiscript template class ChaiScript_Parser final : public ChaiScript_Parser_Base { - void *get_tracer_ptr() override { + void *get_tracer_ptr() noexcept override { return &m_tracer; } @@ -146,97 +146,147 @@ namespace chaiscript ChaiScript_Parser *parser; }; - static std::array, detail::max_alphabet> build_alphabet() + template + constexpr static void set_alphabet(Array2D &array, const First first, const Second second) noexcept { - std::array, detail::max_alphabet> alphabet; + auto *first_ptr = &std::get<0>(array) + static_cast(first); + auto *second_ptr = &std::get<0>(*first_ptr) + static_cast(second); + *second_ptr = true; + } - for (auto &alpha : alphabet) { - alpha.fill(false); - } + constexpr static std::array, detail::max_alphabet> build_alphabet() noexcept + { + std::array, detail::max_alphabet> alphabet{}; - alphabet[detail::symbol_alphabet][static_cast('?')]=true; - alphabet[detail::symbol_alphabet][static_cast('+')]=true; - alphabet[detail::symbol_alphabet][static_cast('-')]=true; - alphabet[detail::symbol_alphabet][static_cast('*')]=true; - alphabet[detail::symbol_alphabet][static_cast('/')]=true; - alphabet[detail::symbol_alphabet][static_cast('|')]=true; - alphabet[detail::symbol_alphabet][static_cast('&')]=true; - alphabet[detail::symbol_alphabet][static_cast('^')]=true; - alphabet[detail::symbol_alphabet][static_cast('=')]=true; - alphabet[detail::symbol_alphabet][static_cast('.')]=true; - alphabet[detail::symbol_alphabet][static_cast('<')]=true; - alphabet[detail::symbol_alphabet][static_cast('>')]=true; + set_alphabet(alphabet, detail::symbol_alphabet, '?'); - for ( size_t c = 'a' ; c <= 'z' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; } - for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; } - for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; } - alphabet[detail::keyword_alphabet][static_cast('_')]=true; + set_alphabet(alphabet, detail::symbol_alphabet, '?'); + set_alphabet(alphabet, detail::symbol_alphabet, '+'); + set_alphabet(alphabet, detail::symbol_alphabet, '-'); + set_alphabet(alphabet, detail::symbol_alphabet, '*'); + set_alphabet(alphabet, detail::symbol_alphabet, '/'); + set_alphabet(alphabet, detail::symbol_alphabet, '|'); + set_alphabet(alphabet, detail::symbol_alphabet, '&'); + set_alphabet(alphabet, detail::symbol_alphabet, '^'); + set_alphabet(alphabet, detail::symbol_alphabet, '='); + set_alphabet(alphabet, detail::symbol_alphabet, '.'); + set_alphabet(alphabet, detail::symbol_alphabet, '<'); + set_alphabet(alphabet, detail::symbol_alphabet, '>'); - for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::int_alphabet][c]=true; } - for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::float_alphabet][c]=true; } - alphabet[detail::float_alphabet][static_cast('.')]=true; + for ( size_t c = 'a' ; c <= 'z' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); } + for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); } + for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::keyword_alphabet, c); } + set_alphabet(alphabet, detail::keyword_alphabet, '_'); - for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; } - for ( size_t c = 'a' ; c <= 'f' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; } - for ( size_t c = 'A' ; c <= 'F' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; } + for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::int_alphabet, c); } + for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::float_alphabet, c); } + set_alphabet(alphabet, detail::float_alphabet, '.'); - alphabet[detail::x_alphabet][static_cast('x')]=true; - alphabet[detail::x_alphabet][static_cast('X')]=true; + for ( size_t c = '0' ; c <= '9' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); } + for ( size_t c = 'a' ; c <= 'f' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); } + for ( size_t c = 'A' ; c <= 'F' ; ++c ) { set_alphabet(alphabet, detail::hex_alphabet, c); } - for ( size_t c = '0' ; c <= '1' ; ++c ) { alphabet[detail::bin_alphabet][c]=true; } - alphabet[detail::b_alphabet][static_cast('b')]=true; - alphabet[detail::b_alphabet][static_cast('B')]=true; + set_alphabet(alphabet, detail::x_alphabet, 'x'); + set_alphabet(alphabet, detail::x_alphabet, 'X'); - for ( size_t c = 'a' ; c <= 'z' ; ++c ) { alphabet[detail::id_alphabet][c]=true; } - for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { alphabet[detail::id_alphabet][c]=true; } - alphabet[detail::id_alphabet][static_cast('_')] = true; + for ( size_t c = '0' ; c <= '1' ; ++c ) { set_alphabet(alphabet, detail::bin_alphabet, c); } + set_alphabet(alphabet, detail::b_alphabet, 'b'); + set_alphabet(alphabet, detail::b_alphabet, 'B'); - alphabet[detail::white_alphabet][static_cast(' ')]=true; - alphabet[detail::white_alphabet][static_cast('\t')]=true; + for ( size_t c = 'a' ; c <= 'z' ; ++c ) { set_alphabet(alphabet, detail::id_alphabet, c); } + for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { set_alphabet(alphabet, detail::id_alphabet, c); } + set_alphabet(alphabet, detail::id_alphabet, '_'); - alphabet[detail::int_suffix_alphabet][static_cast('l')] = true; - alphabet[detail::int_suffix_alphabet][static_cast('L')] = true; - alphabet[detail::int_suffix_alphabet][static_cast('u')] = true; - alphabet[detail::int_suffix_alphabet][static_cast('U')] = true; + set_alphabet(alphabet, detail::white_alphabet, ' '); + set_alphabet(alphabet, detail::white_alphabet, '\t'); - alphabet[detail::float_suffix_alphabet][static_cast('l')] = true; - alphabet[detail::float_suffix_alphabet][static_cast('L')] = true; - alphabet[detail::float_suffix_alphabet][static_cast('f')] = true; - alphabet[detail::float_suffix_alphabet][static_cast('F')] = true; + set_alphabet(alphabet, detail::int_suffix_alphabet, 'l'); + set_alphabet(alphabet, detail::int_suffix_alphabet, 'L'); + set_alphabet(alphabet, detail::int_suffix_alphabet, 'u'); + set_alphabet(alphabet, detail::int_suffix_alphabet, 'U'); + + set_alphabet(alphabet, detail::float_suffix_alphabet, 'l'); + set_alphabet(alphabet, detail::float_suffix_alphabet, 'L'); + set_alphabet(alphabet, detail::float_suffix_alphabet, 'f'); + set_alphabet(alphabet, detail::float_suffix_alphabet, 'F'); return alphabet; } - static const std::array, detail::max_alphabet> &create_alphabet() + + struct Operator_Matches { - static const auto alpha = build_alphabet(); - return alpha; - } + using SS = utility::Static_String; - - static const std::vector> &create_operator_matches() { - static const std::vector> operator_matches { - {"?"}, - {"||"}, - {"&&"}, - {"|"}, - {"^"}, - {"&"}, - {"==", "!="}, - {"<", "<=", ">", ">="}, - {"<<", ">>"}, + std::array m_0 {{SS("?")}}; + std::array m_1 {{SS("||")}}; + std::array m_2 {{SS("&&")}}; + std::array m_3 {{SS("|")}}; + std::array m_4 {{SS("^")}}; + std::array m_5 {{SS("&")}}; + std::array m_6 {{SS("=="), SS("!=")}}; + std::array m_7 {{SS("<"), SS("<="), SS(">"), SS(">=")}}; + std::array m_8 {{SS("<<"), SS(">>")}}; //We share precedence here but then separate them later - {"+", "-"}, - {"*", "/", "%"}, - {"++", "--", "-", "+", "!", "~"} - }; + std::array m_9 {{SS("+"), SS("-")}}; + std::array m_10 {{SS("*"), SS("/"), SS("%")}}; + std::array m_11 {{SS("++"), SS("--"), SS("-"), SS("+"), SS("!"), SS("~")}}; - return operator_matches; - } + bool is_match(const std::string_view &t_str) const noexcept { + constexpr std::array groups{{0,1,2,3,4,5,6,7,8,9,10,11}}; + return std::any_of(groups.begin(), groups.end(), [&t_str, this](const std::size_t group){ return is_match(group, t_str); }); + } + template + bool any_of(const std::size_t t_group, Predicate &&predicate) const + { + auto match = [&predicate](const auto &array) { + return std::any_of(array.begin(), array.end(), predicate); + }; - static const std::array &create_operators() { - static const std::array operators = { { + switch (t_group) { + case 0: return match(m_0); + case 1: return match(m_1); + case 2: return match(m_2); + case 3: return match(m_3); + case 4: return match(m_4); + case 5: return match(m_5); + case 6: return match(m_6); + case 7: return match(m_7); + case 8: return match(m_8); + case 9: return match(m_9); + case 10: return match(m_10); + case 11: return match(m_11); + default: return false; + } + } + + constexpr bool is_match(const std::size_t t_group, const std::string_view &t_str) const noexcept { + auto match = [&t_str](const auto &array) { + return std::any_of(array.begin(), array.end(), [&t_str](const auto &v){ return v == t_str; }); + }; + + switch (t_group) { + case 0: return match(m_0); + case 1: return match(m_1); + case 2: return match(m_2); + case 3: return match(m_3); + case 4: return match(m_4); + case 5: return match(m_5); + case 6: return match(m_6); + case 7: return match(m_7); + case 8: return match(m_8); + case 9: return match(m_9); + case 10: return match(m_10); + case 11: return match(m_11); + default: return false; + } + } + + }; + + constexpr static std::array create_operators() noexcept { + std::array operators = { { Operator_Precidence::Ternary_Cond, Operator_Precidence::Logical_Or, Operator_Precidence::Logical_And, @@ -253,39 +303,12 @@ namespace chaiscript return operators; } - static const utility::Static_String &multiline_comment_end() - { - static const utility::Static_String s("*/"); - return s; - } - - static const utility::Static_String &multiline_comment_begin() - { - static const utility::Static_String s("/*"); - return s; - } - - static const utility::Static_String &singleline_comment() - { - static const utility::Static_String s("//"); - return s; - } - - static const utility::Static_String &annotation() - { - static const utility::Static_String s("#"); - return s; - } - - static const utility::Static_String &cr_lf() - { - static const utility::Static_String s("\r\n"); - return s; - } - - const std::array, detail::max_alphabet> &m_alphabet = create_alphabet(); - const std::vector> &m_operator_matches = create_operator_matches(); - const std::array &m_operators = create_operators(); + constexpr static utility::Static_String m_multiline_comment_end{"*/"}; + constexpr static utility::Static_String m_multiline_comment_begin{"/*"}; + constexpr static utility::Static_String m_singleline_comment{"//"}; + constexpr static utility::Static_String m_annotation{"#"}; + constexpr static utility::Static_String m_cr_lf{"\r\n"}; + constexpr static auto m_operators = create_operators(); std::shared_ptr m_filename; std::vector> m_match_stack; @@ -293,22 +316,27 @@ namespace chaiscript struct Position { - Position() = default; + constexpr Position() = default; - Position(std::string::const_iterator t_pos, std::string::const_iterator t_end) + constexpr Position(const char * t_pos, const char * t_end) noexcept : line(1), col(1), m_pos(t_pos), m_end(t_end), m_last_col(1) { } - static std::string str(const Position &t_begin, const Position &t_end) { - return std::string(t_begin.m_pos, t_end.m_pos); + static std::string_view str(const Position &t_begin, const Position &t_end) noexcept { + if (t_begin.m_pos != nullptr && t_end.m_pos != nullptr) { + return std::string_view(t_begin.m_pos, std::distance(t_begin.m_pos, t_end.m_pos)); + } else { + return {}; + } } - Position &operator++() { + constexpr Position &operator++() noexcept { if (m_pos != m_end) { if (*m_pos == '\n') { ++line; - m_last_col = std::exchange(col, 1); + m_last_col = col; + col = 1; } else { ++col; } @@ -318,7 +346,7 @@ namespace chaiscript return *this; } - Position &operator--() { + constexpr Position &operator--() noexcept { --m_pos; if (*m_pos == '\n') { --line; @@ -329,12 +357,12 @@ namespace chaiscript return *this; } - Position &operator+=(size_t t_distance) { + constexpr Position &operator+=(size_t t_distance) noexcept { *this = (*this) + t_distance; return *this; } - Position operator+(size_t t_distance) const { + constexpr Position operator+(size_t t_distance) const noexcept { Position ret(*this); for (size_t i = 0; i < t_distance; ++i) { ++ret; @@ -342,12 +370,12 @@ namespace chaiscript return ret; } - Position &operator-=(size_t t_distance) { + constexpr Position &operator-=(size_t t_distance) noexcept { *this = (*this) - t_distance; return *this; } - Position operator-(size_t t_distance) const { + constexpr Position operator-(size_t t_distance) const noexcept { Position ret(*this); for (size_t i = 0; i < t_distance; ++i) { --ret; @@ -355,26 +383,25 @@ namespace chaiscript return ret; } - bool operator==(const Position &t_rhs) const { + constexpr bool operator==(const Position &t_rhs) const noexcept { return m_pos == t_rhs.m_pos; } - bool operator!=(const Position &t_rhs) const { + constexpr bool operator!=(const Position &t_rhs) const noexcept { return m_pos != t_rhs.m_pos; } - bool has_more() const { + constexpr bool has_more() const noexcept { return m_pos != m_end; } - size_t remaining() const { - return static_cast(std::distance(m_pos, m_end)); + constexpr size_t remaining() const noexcept { + return static_cast(m_end - m_pos); } - const char& operator*() const { + constexpr const char& operator*() const noexcept { if (m_pos == m_end) { - static const char ktmp ='\0'; - return ktmp; + return ""[0]; } else { return *m_pos; } @@ -384,8 +411,8 @@ namespace chaiscript int col = -1; private: - std::string::const_iterator m_pos; - std::string::const_iterator m_end; + const char *m_pos = nullptr; + const char *m_end = nullptr; int m_last_col = -1; }; @@ -394,14 +421,14 @@ namespace chaiscript Tracer m_tracer; Optimizer m_optimizer; - void validate_object_name(const std::string &name) const + void validate_object_name(const std::string_view &name) const { if (!Name_Validator::valid_object_name(name)) { - throw exception::eval_error("Invalid Object Name: " + name, File_Position(m_position.line, m_position.col), *m_filename); + throw exception::eval_error("Invalid Object Name: " + std::string(name), File_Position(m_position.line, m_position.col), *m_filename); } } - public: + public: explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer=Optimizer()) : m_tracer(std::move(tracer)), m_optimizer(std::move(optimizer)) @@ -409,12 +436,12 @@ namespace chaiscript m_match_stack.reserve(2); } - Tracer &get_tracer() + Tracer &get_tracer() noexcept { return m_tracer; } - Optimizer &get_optimizer() + Optimizer &get_optimizer() noexcept { return m_optimizer; } @@ -424,8 +451,13 @@ namespace chaiscript ChaiScript_Parser(ChaiScript_Parser &&) = default; ChaiScript_Parser &operator=(ChaiScript_Parser &&) = delete; + constexpr static auto m_alphabet = build_alphabet(); + constexpr static Operator_Matches m_operator_matches{}; + /// test a char in an m_alphabet - bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } + constexpr bool char_in_alphabet(char c, detail::Alphabet a) const noexcept { + return m_alphabet[a][static_cast(c)]; + } /// Prints the parsed ast_nodes as a tree void debug_print(const AST_Node &t, std::string prepend = "") const override { @@ -483,7 +515,7 @@ namespace chaiscript /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - inline auto Symbol_(const utility::Static_String &sym) + inline auto Symbol_(const utility::Static_String &sym) noexcept { const auto len = sym.size(); if (m_position.remaining() >= len) { @@ -500,18 +532,18 @@ namespace chaiscript /// Skips any multi-line or single-line comment bool SkipComment() { - if (Symbol_(multiline_comment_begin())) { + if (Symbol_(m_multiline_comment_begin)) { while (m_position.has_more()) { - if (Symbol_(multiline_comment_end())) { + if (Symbol_(m_multiline_comment_end)) { break; } else if (!Eol_()) { ++m_position; } } return true; - } else if (Symbol_(singleline_comment())) { + } else if (Symbol_(m_singleline_comment)) { while (m_position.has_more()) { - if (Symbol_(cr_lf())) { + if (Symbol_(m_cr_lf)) { m_position -= 2; break; } else if (Char_('\n')) { @@ -522,9 +554,9 @@ namespace chaiscript } } return true; - } else if (Symbol_(annotation())) { + } else if (Symbol_(m_annotation)) { while (m_position.has_more()) { - if (Symbol_(cr_lf())) { + if (Symbol_(m_cr_lf)) { m_position -= 2; break; } else if (Char_('\n')) { @@ -575,7 +607,7 @@ namespace chaiscript } /// Reads the optional exponent (scientific notation) and suffix for a Float - bool read_exponent_and_suffix() { + bool read_exponent_and_suffix() noexcept { // Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19 if (m_position.has_more() && (std::tolower(*m_position) == 'e')) { ++m_position; @@ -603,7 +635,7 @@ namespace chaiscript /// Reads a floating point value from input, without skipping initial whitespace - bool Float_() { + bool Float_() noexcept { if (m_position.has_more() && char_in_alphabet(*m_position,detail::float_alphabet) ) { while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) { ++m_position; @@ -631,7 +663,7 @@ namespace chaiscript } /// Reads a hex value from input, without skipping initial whitespace - bool Hex_() { + bool Hex_() noexcept { if (m_position.has_more() && (*m_position == '0')) { ++m_position; @@ -692,7 +724,7 @@ namespace chaiscript } /// Parses a floating point value and returns a Boxed_Value representation of it - static Boxed_Value buildFloat(const std::string &t_val) + static Boxed_Value buildFloat(const std::string_view &t_val) { bool float_ = false; bool long_ = false; @@ -725,7 +757,7 @@ namespace chaiscript - static Boxed_Value buildInt(const int base, const std::string &t_val, const bool prefixed) + static Boxed_Value buildInt(const int base, std::string_view t_val, const bool prefixed) { bool unsigned_ = false; bool long_ = false; @@ -752,7 +784,7 @@ namespace chaiscript } } - const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val; + if (prefixed) { t_val.remove_prefix(2); }; #ifdef __GNUC__ #pragma GCC diagnostic push @@ -766,7 +798,8 @@ namespace chaiscript #endif try { - auto u = std::stoll(val,nullptr,base); + /// TODO fix this to use from_chars + auto u = std::stoll(std::string(t_val),nullptr,base); if (!unsigned_ && !long_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { @@ -789,7 +822,8 @@ namespace chaiscript } catch (const std::out_of_range &) { // too big to be signed try { - auto u = std::stoull(val,nullptr,base); + /// TODO fix this to use from_chars + auto u = std::stoull(std::string(t_val),nullptr,base); if (!longlong_ && u >= std::numeric_limits::min() && u <= std::numeric_limits::max()) { return const_var(static_cast(u)); @@ -809,9 +843,9 @@ namespace chaiscript } template - std::unique_ptr> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param) + std::unique_ptr> make_node(std::string_view t_match, const int t_prev_line, const int t_prev_col, Param && ...param) { - return chaiscript::make_unique, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward(param)...); + return chaiscript::make_unique, T>(std::string(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward(param)...); } /// Reads a number from the input, detecting if it's an integer or floating point @@ -824,20 +858,20 @@ namespace chaiscript if (Hex_()) { auto match = Position::str(start, m_position); auto bv = buildInt(16, match, true); - m_match_stack.emplace_back(make_node>(std::move(match), start.line, start.col, std::move(bv))); + m_match_stack.emplace_back(make_node>(match, start.line, start.col, std::move(bv))); return true; } if (Binary_()) { auto match = Position::str(start, m_position); auto bv = buildInt(2, match, true); - m_match_stack.push_back(make_node>(std::move(match), start.line, start.col, std::move(bv))); + m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); return true; } if (Float_()) { auto match = Position::str(start, m_position); auto bv = buildFloat(match); - m_match_stack.push_back(make_node>(std::move(match), start.line, start.col, std::move(bv))); + m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); return true; } else { @@ -845,11 +879,11 @@ namespace chaiscript auto match = Position::str(start, m_position); if (!match.empty() && (match[0] == '0')) { auto bv = buildInt(8, match, false); - m_match_stack.push_back(make_node>(std::move(match), start.line, start.col, std::move(bv))); + m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); } else if (!match.empty()) { auto bv = buildInt(10, match, false); - m_match_stack.push_back(make_node>(std::move(match), start.line, start.col, std::move(bv))); + m_match_stack.push_back(make_node>(match, start.line, start.col, std::move(bv))); } else { return false; } @@ -908,7 +942,7 @@ namespace chaiscript if (Id_()) { auto text = Position::str(start, m_position); - const auto text_hash = utility::fnv1a_32(text.c_str()); + const auto text_hash = utility::hash(text); if (validate) { validate_object_name(text); @@ -920,29 +954,29 @@ namespace chaiscript #endif switch (text_hash) { - case utility::fnv1a_32("true"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(true))); + case utility::hash("true"): { + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(true))); } break; - case utility::fnv1a_32("false"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(false))); + case utility::hash("false"): { + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(false))); } break; - case utility::fnv1a_32("Infinity"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + case utility::hash("Infinity"): { + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(std::numeric_limits::infinity()))); } break; - case utility::fnv1a_32("NaN"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + case utility::hash("NaN"): { + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(std::numeric_limits::quiet_NaN()))); } break; - case utility::fnv1a_32("__LINE__"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + case utility::hash("__LINE__"): { + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(start.line))); } break; - case utility::fnv1a_32("__FILE__"): { - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + case utility::hash("__FILE__"): { + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(m_filename))); } break; - case utility::fnv1a_32("__FUNC__"): { + case utility::hash("__FUNC__"): { std::string fun_name = "NOT_IN_FUNCTION"; for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 0; --idx) { @@ -952,10 +986,10 @@ namespace chaiscript } } - m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(fun_name))); } break; - case utility::fnv1a_32("__CLASS__"): { + case utility::hash("__CLASS__"): { std::string fun_name = "NOT_IN_CLASS"; for (size_t idx = m_match_stack.empty() ? 0 : m_match_stack.size() - 1; idx > 1; --idx) { @@ -969,15 +1003,16 @@ namespace chaiscript m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(fun_name))); } break; - case utility::fnv1a_32("_"): { + case utility::hash("_"): { m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, Boxed_Value(std::make_shared()))); } break; default: { - std::string val = std::move(text); + auto val = text; if (*start == '`') { // 'escaped' literal, like an operator name val = Position::str(start+1, m_position-1); + // val.remove_prefix(1); val.remove_suffix(1); } m_match_stack.push_back(make_node>(val, start.line, start.col)); } break; @@ -1060,7 +1095,7 @@ namespace chaiscript struct Char_Parser { string_type &match; - typedef typename string_type::value_type char_type; + using char_type = typename string_type::value_type; bool is_escaped = false; bool is_interpolated = false; bool saw_interpolation_marker = false; @@ -1456,14 +1491,8 @@ namespace chaiscript return retval; } - bool is_operator(const std::string &t_s) const { - return std::any_of(m_operator_matches.begin(), m_operator_matches.end(), - [t_s](const std::vector &opers) { - return std::any_of(opers.begin(), opers.end(), - [t_s](const utility::Static_String &s) { - return t_s == s.c_str(); - }); - }); + bool is_operator(const std::string_view &t_s) const noexcept { + return m_operator_matches.is_match(t_s); } /// Reads (and potentially captures) a symbol group from input if it matches the parameter @@ -1490,7 +1519,7 @@ namespace chaiscript bool Eol_(const bool t_eos = false) { bool retval = false; - if (m_position.has_more() && (Symbol_(cr_lf()) || Char_('\n'))) { + if (m_position.has_more() && (Symbol_(m_cr_lf) || Char_('\n'))) { retval = true; //++m_position.line; m_position.col = 1; @@ -2381,7 +2410,7 @@ namespace chaiscript Depth_Counter dc{this}; const auto prev_stack_top = m_match_stack.size(); using SS = utility::Static_String; - constexpr const std::array prefix_opers{{ + const std::array prefix_opers{{ SS{"++"}, SS{"--"}, SS{"-"}, @@ -2414,16 +2443,19 @@ namespace chaiscript } bool Operator_Helper(const size_t t_precedence, std::string &oper) { - Depth_Counter dc{this}; - for (auto & elem : m_operator_matches[t_precedence]) { - if (Symbol(elem)) { - oper = elem.c_str(); - return true; - } - } - return false; + return m_operator_matches.any_of(t_precedence, + [&oper, this](const auto &elem){ + if (Symbol(elem)) { + oper = elem.c_str(); + return true; + } else { + return false; + } + } + ); } + bool Operator(const size_t t_precedence = 0) { Depth_Counter dc{this}; bool retval = false; @@ -2661,7 +2693,9 @@ namespace chaiscript /// Parses the given input string, tagging parsed ast_nodes with the given m_filename. AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) { - m_position = Position(t_input.begin(), t_input.end()); + const auto begin = t_input.empty() ? nullptr : &t_input.front(); + const auto end = begin == nullptr ? nullptr : begin + t_input.size(); + m_position = Position(begin, end); m_filename = std::make_shared(std::move(t_fname)); if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { diff --git a/include/chaiscript/language/chaiscript_posix.hpp b/include/chaiscript/language/chaiscript_posix.hpp index b909347a..d26c8aa2 100644 --- a/include/chaiscript/language/chaiscript_posix.hpp +++ b/include/chaiscript/language/chaiscript_posix.hpp @@ -49,6 +49,19 @@ namespace chaiscript } } + static T cast_symbol(void *p) noexcept + { + union cast_union + { + T func_ptr; + void *in_ptr; + }; + + cast_union c; + c.in_ptr = p; + return c.func_ptr; + } + T m_symbol; }; diff --git a/include/chaiscript/language/chaiscript_tracer.hpp b/include/chaiscript/language/chaiscript_tracer.hpp index a19b0bc8..95fd386c 100644 --- a/include/chaiscript/language/chaiscript_tracer.hpp +++ b/include/chaiscript/language/chaiscript_tracer.hpp @@ -14,7 +14,7 @@ namespace chaiscript { struct Noop_Tracer_Detail { template - void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl *) + constexpr void trace(const chaiscript::detail::Dispatch_State &, const AST_Node_Impl *) noexcept { } }; @@ -23,13 +23,13 @@ namespace chaiscript { struct Tracer : T... { Tracer() = default; - explicit Tracer(T ... t) + constexpr explicit Tracer(T ... t) : T(std::move(t))... { } void do_trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { - (void)std::initializer_list{ (static_cast(*this).trace(ds, node), 0)... }; + (static_cast(*this).trace(ds, node), ... ); } static void trace(const chaiscript::detail::Dispatch_State &ds, const AST_Node_Impl> *node) { diff --git a/include/chaiscript/utility/hash.hpp b/include/chaiscript/utility/hash.hpp new file mode 100644 index 00000000..cffd2142 --- /dev/null +++ b/include/chaiscript/utility/hash.hpp @@ -0,0 +1,101 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2017, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ +#define CHAISCRIPT_UTILITY_FNV1A_HPP_ + + +#include +#include "../chaiscript_defines.hpp" + + +namespace chaiscript +{ + namespace utility + { + namespace fnv1a { + template + static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#ifdef CHAISCRIPT_MSVC +#pragma warning(push) +#pragma warning(disable : 4307) +#endif + std::uint32_t h = 0x811c9dc5; + + while (begin != end) { + h = (h ^ (*begin)) * 0x01000193; + ++begin; + } + return h; + +#ifdef CHAISCRIPT_MSVC +#pragma warning(pop) +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + } + + + template + static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { + return hash(std::begin(str), std::end(str)-1); + } + + static constexpr std::uint32_t hash(const std::string_view &sv) noexcept { + return hash(sv.begin(), sv.end()); + } + + static inline std::uint32_t hash(const std::string &s) noexcept { + return hash(s.begin(), s.end()); + } + } + + namespace jenkins_one_at_a_time { + template + static constexpr std::uint32_t hash(Itr begin, Itr end) noexcept { + std::uint32_t hash = 0; + + while (begin != end) { + hash += *begin; + hash += hash << 10; + hash ^= hash >> 6; + ++begin; + } + + hash += hash << 3; + hash ^= hash >> 11; + hash += hash << 15; + return hash; + } + + template + static constexpr std::uint32_t hash(const char (&str)[N]) noexcept { + return hash(std::begin(str), std::end(str)-1); + } + + static constexpr std::uint32_t hash(const std::string_view &sv) noexcept { + return hash(sv.begin(), sv.end()); + } + + static inline std::uint32_t hash(const std::string &s) noexcept { + return hash(s.begin(), s.end()); + } + } + + using fnv1a::hash; + } + +} + +#endif diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index c6988d54..139cd665 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -3,7 +3,6 @@ // -#pragma once #ifndef SIMPLEJSON_HPP #define SIMPLEJSON_HPP @@ -19,7 +18,9 @@ #include #include #include +#include #include "../chaiscript_defines.hpp" +#include "quick_flat_map.hpp" namespace json { @@ -37,7 +38,7 @@ class JSON { public: enum class Class { - Null, + Null = 0, Object, Array, String, @@ -48,155 +49,97 @@ class JSON private: - struct QuickFlatMap + + using Data = std::variant, std::vector, std::string, double, std::int64_t, bool>; + + struct Internal { - auto find(const std::string &s) { - return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + Internal(std::nullptr_t) : d(nullptr) { } + Internal() : d(nullptr) { } + Internal(Class c) : d(make_type(c)) { } + template Internal(T t) : d(std::move(t)) { } + + static Data make_type(Class c) { + switch (c) { + case Class::Null: return nullptr; + case Class::Object: return chaiscript::utility::QuickFlatMap{}; + case Class::Array: return std::vector{}; + case Class::String: return std::string{}; + case Class::Floating: return double{}; + case Class::Integral: return std::int64_t{}; + case Class::Boolean: return bool{}; + } + throw std::runtime_error("unknown type"); } - auto find(const std::string &s) const { - return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); - } - - auto size() const { - return data.size(); - } - - auto begin() const { - return data.begin(); - } - - auto end() const { - return data.end(); - } - - - auto begin() { - return data.begin(); - } - - auto end() { - return data.end(); - } - - - JSON &operator[](const std::string &s) { - const auto itr = find(s); - if (itr != data.end()) { - return itr->second; - } else { - data.emplace_back(s, JSON()); - return data.back().second; + void set_type(Class c) { + if (type() != c) { + d = make_type(c); } } - JSON &at(const std::string &s) { - const auto itr = find(s); - if (itr != data.end()) { - return itr->second; + Class type() const noexcept { + return Class(d.index()); + } + + + template + decltype(auto) visit_or(Visitor &&visitor, Or &&other) const + { + if (type() == Class(ClassValue)) { + return visitor(std::get(ClassValue)>(d)); } else { - throw std::out_of_range("Unknown key: " + s); + return other(); } } - const JSON &at(const std::string &s) const { - const auto itr = find(s); - if (itr != data.end()) { - return itr->second; - } else { - throw std::out_of_range("Unknown key: " + s); - } + template + auto &get_set_type() { + set_type(ClassValue); + return std::get(ClassValue)>(d); } - size_t count(const std::string &s) const { - return (find(s) != data.end())?1:0; + auto &Map() { + return get_set_type(); + } + auto &Vector() { + return get_set_type(); + } + auto &String() { + return get_set_type(); + } + auto &Int() { + return get_set_type(); + } + auto &Float() { + return get_set_type(); + } + auto &Bool() { + return get_set_type(); } - std::vector> data; - - using iterator = decltype(data)::iterator; - using const_iterator = decltype(data)::const_iterator; - + auto Map() const noexcept { + return std::get_if(Class::Object)>(&d); + } + auto Vector() const noexcept { + return std::get_if(Class::Array)>(&d); + } + auto String() const noexcept { + return std::get_if(Class::String)>(&d); + } + auto Int() const noexcept { + return std::get_if(Class::Integral)>(&d); + } + auto Float() const noexcept { + return std::get_if(Class::Floating)>(&d); + } + auto Bool() const noexcept { + return std::get_if(Class::Boolean)>(&d); + } + Data d; }; - struct Internal { - template - auto clone(const std::unique_ptr &ptr) { - if (ptr != nullptr) { - return std::make_unique(*ptr); - } else { - return std::unique_ptr(nullptr); - } - } - - Internal( double d ) : Float( d ), Type(Class::Floating) {} - Internal( int64_t l ) : Int( l ), Type(Class::Integral) {} - Internal( bool b ) : Bool( b ), Type(Class::Boolean) {} - Internal( std::string s ) : String(std::make_unique(std::move(s))), Type(Class::String) {} - Internal() : Type(Class::Null) {} - - Internal(Class t_type) { - set_type(t_type); - } - - Internal(const Internal &other) - : List(clone(other.List)), - Map(clone(other.Map)), - String(clone(other.String)), - Float(other.Float), - Int(other.Int), - Bool(other.Bool), - Type(other.Type) - { - } - - Internal &operator=(const Internal &other) - { - List = clone(other.List); - Map = clone(other.Map); - String = clone(other.String); - Float = other.Float; - Int = other.Int; - Bool = other.Bool; - Type = other.Type; - return *this; - } - - void set_type( Class type ) { - if( type == Type ) { - return; - } - - Map.reset(); - List.reset(); - String.reset(); - - switch( type ) { - case Class::Object: Map = std::make_unique(); break; - case Class::Array: List = std::make_unique>(); break; - case Class::String: String = std::make_unique(); break; - case Class::Floating: Float = 0.0; break; - case Class::Integral: Int = 0; break; - case Class::Boolean: Bool = false; break; - case Class::Null: break; - } - - Type = type; - } - - Internal(Internal &&) = default; - Internal &operator=(Internal &&) = default; - - std::unique_ptr> List; - std::unique_ptr Map; - std::unique_ptr String; - double Float = 0; - int64_t Int = 0; - bool Bool = false; - - Class Type = Class::Null; - }; Internal internal; @@ -224,8 +167,8 @@ class JSON JSONConstWrapper( const Container *val ) : object( val ) {} JSONConstWrapper( std::nullptr_t ) {} - typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); } - typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); } + typename Container::const_iterator begin() const noexcept { return object ? object->begin() : typename Container::const_iterator(); } + typename Container::const_iterator end() const noexcept { return object ? object->end() : typename Container::const_iterator(); } }; JSON() = default; @@ -245,13 +188,13 @@ class JSON } template - explicit JSON( T b, typename enable_if::value>::type* = nullptr ) : internal( static_cast(b) ) {} + explicit JSON( T b, typename enable_if::value>::type* = nullptr ) noexcept : internal( static_cast(b) ) {} template - explicit JSON( T i, typename enable_if::value && !is_same::value>::type* = nullptr ) : internal( static_cast(i) ) {} + explicit JSON( T i, typename enable_if::value && !is_same::value>::type* = nullptr ) noexcept : internal( static_cast(i) ) {} template - explicit JSON( T f, typename enable_if::value>::type* = nullptr ) : internal( static_cast(f) ) {} + explicit JSON( T f, typename enable_if::value>::type* = nullptr ) noexcept : internal( static_cast(f) ) {} template explicit JSON( T s, typename enable_if::value>::type* = nullptr ) : internal( static_cast(s) ) {} @@ -261,17 +204,16 @@ class JSON static JSON Load( const std::string & ); JSON& operator[]( const std::string &key ) { - internal.set_type( Class::Object ); - return internal.Map->operator[]( key ); + return internal.Map().operator[]( key ); } JSON& operator[]( const size_t index ) { - internal.set_type( Class::Array ); - if( index >= internal.List->size() ) { - internal.List->resize( index + 1 ); + auto &vec = internal.Vector(); + if( index >= vec.size() ) { + vec.resize( index + 1 ); } - return internal.List->operator[]( index ); + return vec.operator[]( index ); } @@ -280,7 +222,10 @@ class JSON } const JSON &at( const std::string &key ) const { - return internal.Map->at( key ); + return internal.visit_or( + [&](const auto &m)->const JSON &{ return m.at(key); }, + []()->const JSON &{ throw std::range_error("Not an object, no keys"); } + ); } JSON &at( size_t index ) { @@ -288,100 +233,84 @@ class JSON } const JSON &at( size_t index ) const { - return internal.List->at( index ); + return internal.visit_or( + [&](const auto &m)->const JSON&{ return m.at(index); }, + []()->const JSON &{ throw std::range_error("Not an array, no indexes"); } + ); } + auto length() const noexcept { + return internal.visit_or( + [&](const auto &m){ return static_cast(m.size()); }, + [](){ return -1; } + ); + } - long length() const { - if( internal.Type == Class::Array ) { - return static_cast(internal.List->size()); + bool has_key( const std::string &key ) const noexcept { + return internal.visit_or( + [&](const auto &m){ return m.count(key) != 0; }, + [](){ return false; } + ); + } + + int size() const noexcept { + if (auto m = internal.Map(); m != nullptr) { + return static_cast(m->size()); + } if (auto v = internal.Vector(); v != nullptr) { + return static_cast(v->size()); } else { return -1; } } - bool has_key( const std::string &key ) const { - if( internal.Type == Class::Object ) { - return internal.Map->count(key) != 0; - } - - return false; - } - - int size() const { - if( internal.Type == Class::Object ) { - return static_cast(internal.Map->size()); - } else if( internal.Type == Class::Array ) { - return static_cast(internal.List->size()); - } else { - return -1; - } - } - - Class JSONType() const { return internal.Type; } + Class JSONType() const noexcept { return internal.type(); } /// Functions for getting primitives from the JSON object. - bool is_null() const { return internal.Type == Class::Null; } + bool is_null() const noexcept { return internal.type() == Class::Null; } - std::string to_string() const { bool b; return to_string( b ); } - std::string to_string( bool &ok ) const { - ok = (internal.Type == Class::String); - return ok ? *internal.String : std::string(""); + std::string to_string() const noexcept { + return internal.visit_or( + [](const auto &o){ return o; }, + [](){ return std::string{}; } + ); + } + double to_float() const noexcept { + return internal.visit_or( + [](const auto &o){ return o; }, + [](){ return double{}; } + ); + } + std::int64_t to_int() const noexcept { + return internal.visit_or( + [](const auto &o){ return o; }, + [](){ return std::int64_t{}; } + ); + } + bool to_bool() const noexcept { + return internal.visit_or( + [](const auto &o){ return o; }, + [](){ return false; } + ); } - double to_float() const { bool b; return to_float( b ); } - double to_float( bool &ok ) const { - ok = (internal.Type == Class::Floating); - return ok ? internal.Float : 0.0; - } - - int64_t to_int() const { bool b; return to_int( b ); } - int64_t to_int( bool &ok ) const { - ok = (internal.Type == Class::Integral); - return ok ? internal.Int : 0; - } - - bool to_bool() const { bool b; return to_bool( b ); } - bool to_bool( bool &ok ) const { - ok = (internal.Type == Class::Boolean); - return ok ? internal.Bool : false; - } - - JSONWrapper object_range() { - if( internal.Type == Class::Object ) { - return JSONWrapper( internal.Map.get() ); - } else { - return JSONWrapper( nullptr ); - } + JSONWrapper> object_range() { + return std::get_if(Class::Object)>(&internal.d); } JSONWrapper> array_range() { - if( internal.Type == Class::Array ) { - return JSONWrapper>( internal.List.get() ); - } else { - return JSONWrapper>( nullptr ); - } + return std::get_if(Class::Array)>(&internal.d); } - JSONConstWrapper object_range() const { - if( internal.Type == Class::Object ) { - return JSONConstWrapper( internal.Map.get() ); - } else { - return JSONConstWrapper( nullptr ); - } + JSONConstWrapper> object_range() const { + return std::get_if(Class::Object)>(&internal.d); } - JSONConstWrapper> array_range() const { - if( internal.Type == Class::Array ) { - return JSONConstWrapper>( internal.List.get() ); - } else { - return JSONConstWrapper>( nullptr ); - } + return std::get_if(Class::Array)>(&internal.d); } std::string dump( long depth = 1, std::string tab = " ") const { - switch( internal.Type ) { + switch( internal.type() ) { case Class::Null: return "null"; case Class::Object: { @@ -390,7 +319,7 @@ class JSON std::string s = "{\n"; bool skip = true; - for( auto &p : *internal.Map ) { + for( auto &p : *internal.Map() ) { if( !skip ) { s += ",\n"; } s += ( pad + "\"" + json_escape(p.first) + "\" : " + p.second.dump( depth + 1, tab ) ); skip = false; @@ -401,7 +330,7 @@ class JSON case Class::Array: { std::string s = "["; bool skip = true; - for( auto &p : *internal.List ) { + for( auto &p : *internal.Vector() ) { if( !skip ) { s += ", "; } s += p.dump( depth + 1, tab ); skip = false; @@ -410,13 +339,13 @@ class JSON return s; } case Class::String: - return "\"" + json_escape( *internal.String ) + "\""; + return "\"" + json_escape( *internal.String() ) + "\""; case Class::Floating: - return std::to_string( internal.Float ); + return std::to_string( *internal.Float() ); case Class::Integral: - return std::to_string( internal.Int ); + return std::to_string( *internal.Int() ); case Class::Boolean: - return internal.Bool ? "true" : "false"; + return *internal.Bool() ? "true" : "false"; } throw std::runtime_error("Unhandled JSON type"); @@ -447,7 +376,7 @@ class JSON struct JSONParser { - static bool isspace(const char c) + static bool isspace(const char c) noexcept { #ifdef CHAISCRIPT_MSVC // MSVC warns on these line in some circumstances @@ -568,7 +497,7 @@ struct JSONParser { char c = '\0'; bool isDouble = false; bool isNegative = false; - int64_t exp = 0; + std::int64_t exp = 0; bool isExpNegative = false; if( offset < str.size() && str.at(offset) == '-' ) { isNegative = true; @@ -606,7 +535,7 @@ struct JSONParser { break; } } - exp = chaiscript::parse_num( exp_str ) * (isExpNegative?-1:1); + exp = chaiscript::parse_num( exp_str ) * (isExpNegative?-1:1); } else if( offset < str.size() && (!isspace( c ) && c != ',' && c != ']' && c != '}' )) { throw std::runtime_error(std::string("JSON ERROR: Number: unexpected character '") + c + "'"); @@ -617,9 +546,9 @@ struct JSONParser { return JSON((isNegative?-1:1) * chaiscript::parse_num( val ) * std::pow( 10, exp )); } else { if( !exp_str.empty() ) { - return JSON((isNegative?-1:1) * static_cast(chaiscript::parse_num( val )) * std::pow( 10, exp )); + return JSON((isNegative?-1:1) * static_cast(chaiscript::parse_num( val )) * std::pow( 10, exp )); } else { - return JSON((isNegative?-1:1) * chaiscript::parse_num( val )); + return JSON((isNegative?-1:1) * chaiscript::parse_num( val )); } } } diff --git a/include/chaiscript/utility/quick_flat_map.hpp b/include/chaiscript/utility/quick_flat_map.hpp new file mode 100644 index 00000000..1d3be2bb --- /dev/null +++ b/include/chaiscript/utility/quick_flat_map.hpp @@ -0,0 +1,81 @@ +#ifndef CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP +#define CHAISCRIPT_UTILITY_QUICK_FLAT_MAP_HPP + +namespace chaiscript::utility { + + template + struct QuickFlatMap + { + auto find(const Key &s) noexcept { + return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + } + + auto find(const Key &s) const noexcept { + return std::find_if(std::begin(data), std::end(data), [&s](const auto &d) { return d.first == s; }); + } + + auto size() const noexcept { + return data.size(); + } + + auto begin() const noexcept { + return data.begin(); + } + + auto end() const noexcept { + return data.end(); + } + + + auto begin() noexcept { + return data.begin(); + } + + auto end() noexcept { + return data.end(); + } + + + Value &operator[](const Key &s) { + const auto itr = find(s); + if (itr != data.end()) { + return itr->second; + } else { + return data.emplace_back(s, Value()).second; + } + } + + Value &at(const Key &s) { + const auto itr = find(s); + if (itr != data.end()) { + return itr->second; + } else { + throw std::out_of_range("Unknown key: " + s); + } + } + + const Value &at(const Key &s) const { + const auto itr = find(s); + if (itr != data.end()) { + return itr->second; + } else { + throw std::out_of_range("Unknown key: " + s); + } + } + + size_t count(const Key &s) const noexcept { + return (find(s) != data.end())?1:0; + } + + std::vector> data; + + using iterator = typename decltype(data)::iterator; + using const_iterator = typename decltype(data)::const_iterator; + + + }; + +} + +#endif + diff --git a/include/chaiscript/utility/static_string.hpp b/include/chaiscript/utility/static_string.hpp index 0d63fd9f..bc842915 100644 --- a/include/chaiscript/utility/static_string.hpp +++ b/include/chaiscript/utility/static_string.hpp @@ -15,19 +15,47 @@ namespace chaiscript struct Static_String { template - constexpr Static_String(const char (&str)[N]) + constexpr Static_String(const char (&str)[N]) noexcept : m_size(N-1), data(&str[0]) { } - constexpr size_t size() const { + constexpr size_t size() const noexcept { return m_size; } - constexpr const char *c_str() const { + constexpr const char *c_str() const noexcept { return data; } + constexpr auto begin() const noexcept { + return data; + } + + constexpr auto end() const noexcept { + return data + m_size; + } + + constexpr bool operator==(const std::string_view &other) const noexcept { + //return std::string_view(data, m_size) == other; + auto b1 = begin(); + const auto e1 = end(); + auto b2 = other.begin(); + const auto e2 = other.end(); + + if (e1 - b1 != e2 - b2) { return false; } + + while (b1 != e1) { + if (*b1 != *b2) { return false; } + ++b1; ++b2; + } + return true; + } + + bool operator==(const std::string &t_str) const noexcept { + return std::equal(begin(), end(), std::cbegin(t_str), std::cend(t_str)); + } + const size_t m_size; const char *data = nullptr; }; diff --git a/performance_tests/profile_cpp_calls_2.cpp b/performance_tests/profile_cpp_calls_2.cpp index 0424654b..aa87fc03 100644 --- a/performance_tests/profile_cpp_calls_2.cpp +++ b/performance_tests/profile_cpp_calls_2.cpp @@ -7,7 +7,7 @@ double f(const std::string &, double, bool) noexcept { int main() { - chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); + chaiscript::ChaiScript chai; chai.add(chaiscript::fun(&f), "f"); diff --git a/performance_tests/profile_fun_wrappers.cpp b/performance_tests/profile_fun_wrappers.cpp index fb96f483..119f6929 100644 --- a/performance_tests/profile_fun_wrappers.cpp +++ b/performance_tests/profile_fun_wrappers.cpp @@ -7,7 +7,7 @@ double f(const std::string &, double, bool) noexcept { int main() { - chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); + chaiscript::ChaiScript chai; chai.add(chaiscript::fun(&f), "f"); diff --git a/src/test_module.cpp b/src/test_module.cpp index 90a1154a..4216ee5b 100644 --- a/src/test_module.cpp +++ b/src/test_module.cpp @@ -12,8 +12,23 @@ class TestBaseType TestBaseType(int) : val(10), const_val(15), mdarray{} { } TestBaseType(int *) : val(10), const_val(15), mdarray{} { } - TestBaseType(const TestBaseType &) = default; - virtual ~TestBaseType() {} + TestBaseType(const TestBaseType &other) + : val(other.val), const_val(other.const_val), const_val_ptr(&const_val), + func_member(other.func_member) + { + } + + TestBaseType(TestBaseType &&other) + : val(other.val), const_val(other.const_val), const_val_ptr(&const_val), + func_member(std::move(other.func_member)) + { + } + + + TestBaseType &operator=(TestBaseType &&) = delete; + TestBaseType &operator=(const TestBaseType &) = delete; + + virtual ~TestBaseType() = default; virtual int func() { return 0; } int base_only_func() { return -9; } @@ -36,8 +51,6 @@ class TestBaseType t_str = "42"; } - private: - TestBaseType &operator=(const TestBaseType &) = delete; }; class Type2 @@ -78,22 +91,14 @@ int to_int(TestEnum t) class TestDerivedType : public TestBaseType { public: - ~TestDerivedType() override {} - TestDerivedType(const TestDerivedType &) = default; - TestDerivedType() = default; virtual int func() override { return 1; } int derived_only_func() { return 19; } - private: - TestDerivedType &operator=(const TestDerivedType &) = delete; }; class TestMoreDerivedType : public TestDerivedType { public: - TestMoreDerivedType(const TestMoreDerivedType &) = default; - TestMoreDerivedType() = default; - virtual ~TestMoreDerivedType() {} }; std::shared_ptr derived_type_factory()