diff --git a/scripts/update_dependencies.sh b/scripts/update_dependencies.sh index 2f7953c6f..bb9fc1a00 100755 --- a/scripts/update_dependencies.sh +++ b/scripts/update_dependencies.sh @@ -10,13 +10,13 @@ set -o nounset # http://git.661346.n2.nabble.com/subtree-merges-lose-prefix-after-rebase-td7332850.html OSMIUM_REPO="https://github.com/osmcode/libosmium.git" -OSMIUM_TAG=v2.11.0 +OSMIUM_TAG=v2.11.3 VARIANT_REPO="https://github.com/mapbox/variant.git" -VARIANT_TAG=v1.1.0 +VARIANT_TAG=v1.1.3 SOL_REPO="https://github.com/ThePhD/sol2.git" -SOL_TAG=v2.15.8 +SOL_TAG=v2.17.5 RAPIDJSON_REPO="https://github.com/miloyip/rapidjson.git" RAPIDJSON_TAG=v1.1.0 diff --git a/third_party/libosmium/CHANGELOG.md b/third_party/libosmium/CHANGELOG.md index d12bb76cf..cc1fdcc8d 100644 --- a/third_party/libosmium/CHANGELOG.md +++ b/third_party/libosmium/CHANGELOG.md @@ -6,12 +6,36 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] - -### Added +### Fixed -### Changed +## [2.11.3] - 2017-05-03 ### Fixed +- Two bugs in area assembler affecting very complex multipolygons and + multipolygons with overlapping or nearly overlapping lines. +- Invalid use of iterators leading to undefined behaviour in area assembler + code. +- Read OPL file correctly even if trailing newline in file is missing. + + +## [2.11.2] - 2017-04-10 + +### Fixed + +- Use minimum size of 64 bytes for buffers. This fixes an infinite loop + when buffer size is zero. + + +## [2.11.1] - 2017-03-07 + +### Fixed + +- Terminate called on full non-auto-growing buffer. (Issue #189.) +- When file formats were used that were not compiled into the binary, it + terminated instead of throwing. (Issue #197.) +- The `Filter::count()` method didn't compile at all. + ## [2.11.0] - 2017-01-14 @@ -525,7 +549,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). Doxygen (up to version 1.8.8). This version contains a workaround to fix this. -[unreleased]: https://github.com/osmcode/libosmium/compare/v2.10.3...HEAD +[unreleased]: https://github.com/osmcode/libosmium/compare/v2.11.3...HEAD +[2.11.3]: https://github.com/osmcode/libosmium/compare/v2.11.2...v2.11.3 +[2.11.2]: https://github.com/osmcode/libosmium/compare/v2.11.1...v2.11.2 +[2.11.1]: https://github.com/osmcode/libosmium/compare/v2.11.0...v2.11.1 +[2.11.0]: https://github.com/osmcode/libosmium/compare/v2.10.3...v2.11.0 [2.10.3]: https://github.com/osmcode/libosmium/compare/v2.10.2...v2.10.3 [2.10.2]: https://github.com/osmcode/libosmium/compare/v2.10.1...v2.10.2 [2.10.1]: https://github.com/osmcode/libosmium/compare/v2.10.0...v2.10.1 diff --git a/third_party/libosmium/CMakeLists.txt b/third_party/libosmium/CMakeLists.txt index 21478ec8d..e536c3469 100644 --- a/third_party/libosmium/CMakeLists.txt +++ b/third_party/libosmium/CMakeLists.txt @@ -25,7 +25,7 @@ project(libosmium) set(LIBOSMIUM_VERSION_MAJOR 2) set(LIBOSMIUM_VERSION_MINOR 11) -set(LIBOSMIUM_VERSION_PATCH 0) +set(LIBOSMIUM_VERSION_PATCH 3) set(LIBOSMIUM_VERSION "${LIBOSMIUM_VERSION_MAJOR}.${LIBOSMIUM_VERSION_MINOR}.${LIBOSMIUM_VERSION_PATCH}") diff --git a/third_party/libosmium/include/osmium/area/assembler.hpp b/third_party/libosmium/include/osmium/area/assembler.hpp index 3509b57bc..78a9d09d7 100644 --- a/third_party/libosmium/include/osmium/area/assembler.hpp +++ b/third_party/libosmium/include/osmium/area/assembler.hpp @@ -474,17 +474,17 @@ namespace osmium { class rings_stack_element { - int32_t m_y; + double m_y; detail::ProtoRing* m_ring_ptr; public: - rings_stack_element(int32_t y, detail::ProtoRing* ring_ptr) : + rings_stack_element(double y, detail::ProtoRing* ring_ptr) : m_y(y), m_ring_ptr(ring_ptr) { } - int32_t y() const noexcept { + double y() const noexcept { return m_y; } @@ -504,7 +504,7 @@ namespace osmium { return m_y < rhs.m_y; } - }; // class ring_stack_element + }; // class rings_stack_element using rings_stack = std::vector; @@ -592,7 +592,7 @@ namespace osmium { if (debug()) { std::cerr << " Segment belongs to outer ring\n"; } - const int32_t y = int32_t(ay + (by - ay) * (lx - ax) / (bx - ax)); + const double y = ay + (by - ay) * (lx - ax) / double(bx - ax); outer_rings.emplace_back(y, segment->ring()); } } @@ -859,8 +859,8 @@ namespace osmium { } void merge_two_rings(open_ring_its_type& open_ring_its, const location_to_ring_map& m1, const location_to_ring_map& m2) { - auto& r1 = *m1.ring_it; - auto& r2 = *m2.ring_it; + std::list::iterator r1 = *m1.ring_it; + std::list::iterator r2 = *m2.ring_it; if (r1->get_node_ref_stop().location() == r2->get_node_ref_start().location()) { r1->join_forward(*r2); @@ -876,11 +876,11 @@ namespace osmium { assert(false); } + open_ring_its.erase(std::find(open_ring_its.begin(), open_ring_its.end(), r2)); m_rings.erase(r2); - open_ring_its.remove(r2); if (r1->closed()) { - open_ring_its.remove(r1); + open_ring_its.erase(std::find(open_ring_its.begin(), open_ring_its.end(), r1)); } } @@ -988,6 +988,7 @@ namespace osmium { } loc_done.insert(c.stop_location); find_candidates(candidates, loc_done, xrings, c); + loc_done.erase(c.stop_location); if (debug()) { std::cerr << " ...back\n"; } @@ -1085,12 +1086,13 @@ namespace osmium { // Join all (open) rings in the candidate to get one closed ring. assert(chosen_cand->rings.size() > 1); const auto& first_ring = chosen_cand->rings.front().first; - for (auto it = chosen_cand->rings.begin() + 1; it != chosen_cand->rings.end(); ++it) { + const detail::ProtoRing& remaining_ring = first_ring.ring(); + for (auto it = std::next(chosen_cand->rings.begin()); it != chosen_cand->rings.end(); ++it) { merge_two_rings(open_ring_its, first_ring, it->first); } if (debug()) { - std::cerr << " Merged to " << first_ring.ring() << "\n"; + std::cerr << " Merged to " << remaining_ring << "\n"; } return true; diff --git a/third_party/libosmium/include/osmium/builder/builder.hpp b/third_party/libosmium/include/osmium/builder/builder.hpp index 107f4a9d0..d4358843b 100644 --- a/third_party/libosmium/include/osmium/builder/builder.hpp +++ b/third_party/libosmium/include/osmium/builder/builder.hpp @@ -167,6 +167,20 @@ namespace osmium { return length; } + /** + * Append data to buffer and append an additional \0. + * + * @param data Pointer to data. + * @param length Length of data in bytes. + * @returns The number of bytes appended (length + 1). + */ + osmium::memory::item_size_type append_with_zero(const char* data, const osmium::memory::item_size_type length) { + unsigned char* target = reserve_space(length + 1); + std::copy_n(reinterpret_cast(data), length, target); + target[length] = '\0'; + return length + 1; + } + /** * Append \0-terminated string to buffer. * @@ -180,9 +194,11 @@ namespace osmium { /** * Append '\0' to the buffer. * + * @deprecated Use append_with_zero() instead. + * * @returns The number of bytes appended (always 1). */ - osmium::memory::item_size_type append_zero() { + OSMIUM_DEPRECATED osmium::memory::item_size_type append_zero() { *reserve_space(1) = '\0'; return 1; } diff --git a/third_party/libosmium/include/osmium/builder/osm_object_builder.hpp b/third_party/libosmium/include/osmium/builder/osm_object_builder.hpp index 1dd5f972f..d4483b192 100644 --- a/third_party/libosmium/include/osmium/builder/osm_object_builder.hpp +++ b/third_party/libosmium/include/osmium/builder/osm_object_builder.hpp @@ -99,7 +99,8 @@ namespace osmium { if (std::strlen(value) > osmium::max_osm_string_length) { throw std::length_error("OSM tag value is too long"); } - add_size(append(key) + append(value)); + add_size(append(key)); + add_size(append(value)); } /** @@ -117,8 +118,8 @@ namespace osmium { if (value_length > osmium::max_osm_string_length) { throw std::length_error("OSM tag value is too long"); } - add_size(append(key, osmium::memory::item_size_type(key_length)) + append_zero() + - append(value, osmium::memory::item_size_type(value_length)) + append_zero()); + add_size(append_with_zero(key, osmium::memory::item_size_type(key_length))); + add_size(append_with_zero(value, osmium::memory::item_size_type(value_length))); } /** @@ -134,8 +135,8 @@ namespace osmium { if (value.size() > osmium::max_osm_string_length) { throw std::length_error("OSM tag value is too long"); } - add_size(append(key.data(), osmium::memory::item_size_type(key.size()) + 1) + - append(value.data(), osmium::memory::item_size_type(value.size()) + 1)); + add_size(append(key.data(), osmium::memory::item_size_type(key.size()) + 1)); + add_size(append(value.data(), osmium::memory::item_size_type(value.size()) + 1)); } /** @@ -144,7 +145,8 @@ namespace osmium { * @param tag Tag. */ void add_tag(const osmium::Tag& tag) { - add_size(append(tag.key()) + append(tag.value())); + add_size(append(tag.key())); + add_size(append(tag.value())); } /** @@ -226,7 +228,7 @@ namespace osmium { throw std::length_error("OSM relation member role is too long"); } member.set_role_size(osmium::string_size_type(length) + 1); - add_size(append(role, osmium::memory::item_size_type(length)) + append_zero()); + add_size(append_with_zero(role, osmium::memory::item_size_type(length))); add_padding(true); } @@ -310,7 +312,7 @@ namespace osmium { throw std::length_error("OSM user name is too long"); } comment.set_user_size(osmium::string_size_type(length) + 1); - add_size(append(user, osmium::memory::item_size_type(length)) + append_zero()); + add_size(append_with_zero(user, osmium::memory::item_size_type(length))); } void add_text(osmium::ChangesetComment& comment, const char* text, const size_t length) { @@ -322,7 +324,7 @@ namespace osmium { throw std::length_error("OSM changeset comment is too long"); } comment.set_text_size(osmium::string_size_type(length) + 1); - add_size(append(text, osmium::memory::item_size_type(length)) + append_zero()); + add_size(append_with_zero(text, osmium::memory::item_size_type(length))); add_padding(true); } diff --git a/third_party/libosmium/include/osmium/io/detail/opl_input_format.hpp b/third_party/libosmium/include/osmium/io/detail/opl_input_format.hpp index 135f1a5e0..62598f706 100644 --- a/third_party/libosmium/include/osmium/io/detail/opl_input_format.hpp +++ b/third_party/libosmium/include/osmium/io/detail/opl_input_format.hpp @@ -123,6 +123,11 @@ namespace osmium { rest = input.substr(ppos); } + if (!rest.empty()) { + m_data = rest.data(); + parse_line(); + } + if (m_buffer.committed() > 0) { send_to_output_queue(std::move(m_buffer)); } diff --git a/third_party/libosmium/include/osmium/io/reader.hpp b/third_party/libosmium/include/osmium/io/reader.hpp index c39eaaa62..825cb41ce 100644 --- a/third_party/libosmium/include/osmium/io/reader.hpp +++ b/third_party/libosmium/include/osmium/io/reader.hpp @@ -92,6 +92,8 @@ namespace osmium { osmium::io::File m_file; + detail::ParserFactory::create_parser_type m_creator; + enum class status { okay = 0, // normal reading error = 1, // some error occurred while reading @@ -128,13 +130,12 @@ namespace osmium { } // This function will run in a separate thread. - static void parser_thread(const osmium::io::File& file, + static void parser_thread(const detail::ParserFactory::create_parser_type& creator, detail::future_string_queue_type& input_queue, detail::future_buffer_queue_type& osmdata_queue, std::promise&& header_promise, osmium::io::detail::reader_options options) { std::promise promise = std::move(header_promise); - const auto creator = detail::ParserFactory::instance().get_creator_function(file); const auto parser = creator(input_queue, osmdata_queue, promise, options); parser->parse(); } @@ -236,6 +237,7 @@ namespace osmium { template explicit Reader(const osmium::io::File& file, TArgs&&... args) : m_file(file.check()), + m_creator(detail::ParserFactory::instance().get_creator_function(m_file)), m_status(status::okay), m_childpid(0), m_input_queue(detail::get_input_queue_size(), "raw_input"), @@ -256,7 +258,7 @@ namespace osmium { std::promise header_promise; m_header_future = header_promise.get_future(); - m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_options}; + m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_creator), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), m_options}; } template diff --git a/third_party/libosmium/include/osmium/memory/buffer.hpp b/third_party/libosmium/include/osmium/memory/buffer.hpp index 370d01e0b..1b75b4fa5 100644 --- a/third_party/libosmium/include/osmium/memory/buffer.hpp +++ b/third_party/libosmium/include/osmium/memory/buffer.hpp @@ -119,6 +119,15 @@ namespace osmium { auto_grow m_auto_grow{auto_grow::no}; std::function m_full; + static size_t calculate_capacity(size_t capacity) noexcept { + // The majority of all Nodes will fit into this size. + constexpr static const size_t min_capacity = 64; + if (capacity < min_capacity) { + return min_capacity; + } + return capacity; + } + public: /** @@ -198,13 +207,13 @@ namespace osmium { * of the alignment. */ explicit Buffer(size_t capacity, auto_grow auto_grow = auto_grow::yes) : - m_memory(new unsigned char[capacity]), + m_memory(new unsigned char[calculate_capacity(capacity)]), m_data(m_memory.get()), - m_capacity(capacity), + m_capacity(calculate_capacity(capacity)), m_written(0), m_committed(0), m_auto_grow(auto_grow) { - if (capacity % align_bytes != 0) { + if (m_capacity % align_bytes != 0) { throw std::invalid_argument("buffer capacity needs to be multiple of alignment"); } } diff --git a/third_party/libosmium/include/osmium/tags/filter.hpp b/third_party/libosmium/include/osmium/tags/filter.hpp index 22abb1430..797565db8 100644 --- a/third_party/libosmium/include/osmium/tags/filter.hpp +++ b/third_party/libosmium/include/osmium/tags/filter.hpp @@ -140,7 +140,7 @@ namespace osmium { * Return the number of rules in this filter. */ size_t count() const { - return m_rules.count(); + return m_rules.size(); } /** diff --git a/third_party/libosmium/include/osmium/version.hpp b/third_party/libosmium/include/osmium/version.hpp index d32641a55..a36a4d900 100644 --- a/third_party/libosmium/include/osmium/version.hpp +++ b/third_party/libosmium/include/osmium/version.hpp @@ -35,8 +35,8 @@ DEALINGS IN THE SOFTWARE. #define LIBOSMIUM_VERSION_MAJOR 2 #define LIBOSMIUM_VERSION_MINOR 11 -#define LIBOSMIUM_VERSION_PATCH 0 +#define LIBOSMIUM_VERSION_PATCH 3 -#define LIBOSMIUM_VERSION_STRING "2.11.0" +#define LIBOSMIUM_VERSION_STRING "2.11.3" #endif // OSMIUM_VERSION_HPP diff --git a/third_party/libosmium/test/CMakeLists.txt b/third_party/libosmium/test/CMakeLists.txt index db0e93485..68f8887c4 100644 --- a/third_party/libosmium/test/CMakeLists.txt +++ b/third_party/libosmium/test/CMakeLists.txt @@ -167,9 +167,10 @@ add_unit_test(io test_compression_factory) add_unit_test(io test_bzip2 ENABLE_IF ${BZIP2_FOUND} LIBS ${BZIP2_LIBRARIES}) add_unit_test(io test_file_formats) add_unit_test(io test_reader LIBS "${OSMIUM_XML_LIBRARIES};${OSMIUM_PBF_LIBRARIES}") +add_unit_test(io test_reader_fileformat ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT}) add_unit_test(io test_reader_with_mock_decompression ENABLE_IF ${Threads_FOUND} LIBS ${OSMIUM_XML_LIBRARIES}) add_unit_test(io test_reader_with_mock_parser ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT}) -add_unit_test(io test_opl_parser) +add_unit_test(io test_opl_parser ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT}) add_unit_test(io test_output_utils) add_unit_test(io test_output_iterator ENABLE_IF ${Threads_FOUND} LIBS ${CMAKE_THREAD_LIBS_INIT}) add_unit_test(io test_string_table) diff --git a/third_party/libosmium/test/t/io/data-nonl.opl b/third_party/libosmium/test/t/io/data-nonl.opl new file mode 100644 index 000000000..db2354439 --- /dev/null +++ b/third_party/libosmium/test/t/io/data-nonl.opl @@ -0,0 +1 @@ +n1 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x1.02 y1.02 \ No newline at end of file diff --git a/third_party/libosmium/test/t/io/data.opl b/third_party/libosmium/test/t/io/data.opl new file mode 100644 index 000000000..2c7e2a35f --- /dev/null +++ b/third_party/libosmium/test/t/io/data.opl @@ -0,0 +1 @@ +n1 v1 dV c1 t2014-01-01T00:00:00Z i1 utest T x1.02 y1.02 diff --git a/third_party/libosmium/test/t/io/test_opl_parser.cpp b/third_party/libosmium/test/t/io/test_opl_parser.cpp index 9ad6eeb75..dad223865 100644 --- a/third_party/libosmium/test/t/io/test_opl_parser.cpp +++ b/third_party/libosmium/test/t/io/test_opl_parser.cpp @@ -3,8 +3,10 @@ #include #include "catch.hpp" +#include "utils.hpp" #include +#include #include namespace oid = osmium::io::detail; @@ -1073,3 +1075,23 @@ TEST_CASE("Parse line with external interface") { } +TEST_CASE("Parse OPL using Reader") { + osmium::io::File file{with_data_dir("t/io/data.opl")}; + osmium::io::Reader reader{file}; + + const auto buffer = reader.read(); + REQUIRE(buffer); + const auto& node = buffer.get(0); + REQUIRE(node.id() == 1); +} + +TEST_CASE("Parse OPL with missing newline using Reader") { + osmium::io::File file{with_data_dir("t/io/data-nonl.opl")}; + osmium::io::Reader reader{file}; + + const auto buffer = reader.read(); + REQUIRE(buffer); + const auto& node = buffer.get(0); + REQUIRE(node.id() == 1); +} + diff --git a/third_party/libosmium/test/t/io/test_reader_fileformat.cpp b/third_party/libosmium/test/t/io/test_reader_fileformat.cpp new file mode 100644 index 000000000..a64932e70 --- /dev/null +++ b/third_party/libosmium/test/t/io/test_reader_fileformat.cpp @@ -0,0 +1,10 @@ + +#include "catch.hpp" +#include "utils.hpp" + +#include + +TEST_CASE("Reader throws on unsupported file format") { + REQUIRE_THROWS_AS(osmium::io::Reader{with_data_dir("t/io/data.osm")}, osmium::unsupported_file_format_error); +} + diff --git a/third_party/libosmium/test/t/memory/test_buffer_basics.cpp b/third_party/libosmium/test/t/memory/test_buffer_basics.cpp index ffe725168..d9d174b0f 100644 --- a/third_party/libosmium/test/t/memory/test_buffer_basics.cpp +++ b/third_party/libosmium/test/t/memory/test_buffer_basics.cpp @@ -6,8 +6,8 @@ TEST_CASE("Buffer basics") { osmium::memory::Buffer invalid_buffer1; osmium::memory::Buffer invalid_buffer2; - osmium::memory::Buffer empty_buffer1(1024); - osmium::memory::Buffer empty_buffer2(2048); + osmium::memory::Buffer empty_buffer1{1024}; + osmium::memory::Buffer empty_buffer2{2048}; REQUIRE(!invalid_buffer1); REQUIRE(!invalid_buffer2); @@ -32,3 +32,18 @@ TEST_CASE("Buffer basics") { } +TEST_CASE("Buffer with zero size") { + osmium::memory::Buffer buffer{0}; + REQUIRE(buffer.capacity() == 64); +} + +TEST_CASE("Buffer with less than minimum size") { + osmium::memory::Buffer buffer{63}; + REQUIRE(buffer.capacity() == 64); +} + +TEST_CASE("Buffer with minimum size") { + osmium::memory::Buffer buffer{64}; + REQUIRE(buffer.capacity() == 64); +} + diff --git a/third_party/sol2/sol2/sol.hpp b/third_party/sol2/sol2/sol.hpp index ff868d73c..a349ea9d1 100644 --- a/third_party/sol2/sol2/sol.hpp +++ b/third_party/sol2/sol2/sol.hpp @@ -1,6 +1,6 @@ // The MIT License (MIT) -// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors +// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-02-19 09:59:38.638408 UTC -// This header was generated with sol v2.15.8 (revision 0c8ec82) +// Generated 2017-06-13 20:34:08.313723 UTC +// This header was generated with sol v2.17.5 (revision 51a03b2) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -47,6 +47,9 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wconversion" +#if __GNUC__ > 6 +#pragma GCC diagnostic ignored "-Wnoexcept-type" +#endif #elif defined _MSC_VER #pragma warning( push ) #pragma warning( disable : 4324 ) // structure was padded due to alignment specifier @@ -381,6 +384,7 @@ namespace sol { #include #include #include +#include namespace sol { template @@ -671,6 +675,12 @@ namespace sol { template using is_string_constructible = any, const char*>, std::is_same, char>, std::is_same, std::string>, std::is_same, std::initializer_list>>; + template + struct is_pair : std::false_type {}; + + template + struct is_pair> : std::true_type {}; + template using is_c_str = any< std::is_same>, const char*>, @@ -704,7 +714,19 @@ namespace sol { decltype(auto) tuplefy(X&&... x) { return std::tuple_cat(meta_detail::force_tuple(std::forward(x))...); } + + template + struct iterator_tag { + using type = std::input_iterator_tag; + }; + + template + struct iterator_tag> { + using type = typename T::iterator_category; + }; + } // meta + namespace detail { template decltype(auto) forward_get(Tuple&& tuple) { @@ -799,7 +821,7 @@ namespace sol { #include #else #include -#endif // C++-compiler Lua +#endif // C++ Mangling for Lua #if defined(_WIN32) || defined(_MSC_VER) #ifndef SOL_CODECVT_SUPPORT @@ -890,9 +912,34 @@ namespace sol { #ifndef SOL_NO_COMPAT -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(SOL_USING_CXX_LUA) extern "C" { #endif +// beginning of sol/compatibility/5.2.0.h + +#ifndef SOL_5_2_0_H +#define SOL_5_2_0_H + +#if SOL_LUA_VERSION < 503 + +inline int lua_isinteger(lua_State* L, int idx) { + if (lua_type(L, idx) != LUA_TNUMBER) + return 0; + // This is a very slipshod way to do the testing + // but lua_totingerx doesn't play ball nicely + // on older versions... + lua_Number n = lua_tonumber(L, idx); + lua_Integer i = lua_tointeger(L, idx); + if (i != n) + return 0; + // it's DEFINITELY an integer + return 1; +} + +#endif // SOL_LUA_VERSION == 502 +#endif // SOL_5_2_0_H +// end of sol/compatibility/5.2.0.h + // beginning of sol/compatibility/5.1.0.h #ifndef SOL_5_1_0_H @@ -921,7 +968,7 @@ extern "C" { /* LuaJIT does not have the updated error codes for thread status/function returns */ #ifndef LUA_ERRGCMM -#define LUA_ERRGCMM (LUA_ERRERR + 1) +#define LUA_ERRGCMM (LUA_ERRERR + 2) #endif // LUA_ERRGCMM /* LuaJIT does not support continuation contexts / return error codes? */ @@ -1086,8 +1133,15 @@ inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const c #define lua_pushglobaltable(L) \ lua_pushvalue(L, LUA_GLOBALSINDEX) +#ifndef SOL_LUAJIT #define luaL_newlib(L, l) \ (lua_newtable((L)),luaL_setfuncs((L), (l), 0)) +#else +#if SOL_LUAJIT_VERSION < 20100 +#define luaL_newlib(L, l) \ + (lua_newtable((L)),luaL_setfuncs((L), (l), 0)) +#endif // LuaJIT-2.1.0-beta3 added this in itself +#endif // LuaJIT Compatibility void luaL_checkversion(lua_State *L); @@ -1115,32 +1169,7 @@ int luaL_fileresult(lua_State *L, int stat, const char *fname); #ifndef SOL_5_X_X_INL #define SOL_5_X_X_INL -// beginning of sol/compatibility/5.2.0.h - -#ifndef SOL_5_2_0_H -#define SOL_5_2_0_H - -#if SOL_LUA_VERSION < 503 - -inline int lua_isinteger(lua_State* L, int idx) { - if (lua_type(L, idx) != LUA_TNUMBER) - return 0; - // This is a very slipshod way to do the testing - // but lua_totingerx doesn't play ball nicely - // on older versions... - lua_Number n = lua_tonumber(L, idx); - lua_Integer i = lua_tointeger(L, idx); - if (i != n) - return 0; - // it's DEFINITELY an integer - return 1; -} - -#endif // SOL_LUA_VERSION == 502 -#endif // SOL_5_2_0_H -// end of sol/compatibility/5.2.0.h - -#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501 +#if SOL_LUA_VERSION < 502 #include @@ -1812,7 +1841,7 @@ inline void luaL_pushresult(luaL_Buffer_52 *B) { #endif // SOL_5_X_X_INL // end of sol/compatibility/5.x.x.inl -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(SOL_USING_CXX_LUA) } #endif @@ -2576,15 +2605,12 @@ namespace sol { } constexpr T& value() const { - return ref ? - *ref #ifdef SOL_NO_EXCEPTIONS - // we can't abort here - // because there's no constexpr abort - : *(T*)nullptr; + return *ref; #else - : throw bad_optional_access("bad optional access"); -#endif + return ref ? *ref + : (throw bad_optional_access("bad optional access"), *ref); +#endif // Exceptions } explicit constexpr operator bool() const noexcept { @@ -2941,6 +2967,12 @@ namespace sol { const nullopt_t nullopt = boost::none; #endif // Boost vs. Better optional + namespace meta { + template + struct is_optional : std::false_type {}; + template + struct is_optional> : std::true_type {}; + } // meta } // sol // end of sol/optional.hpp @@ -3041,6 +3073,7 @@ namespace sol { } #if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) catch (...) { + std::exception_ptr eptr = std::current_exception(); lua_pushstring(L, "caught (...) exception"); } #endif @@ -3086,6 +3119,9 @@ namespace sol { return std::addressof(item); } }; + + struct unchecked_t {}; + const unchecked_t unchecked = unchecked_t{}; } // detail struct lua_nil_t {}; @@ -3097,8 +3133,11 @@ namespace sol { const nil_t nil{}; #endif - struct metatable_key_t {}; - const metatable_key_t metatable_key = {}; + struct metatable_t {}; + const metatable_t metatable_key = {}; + + struct env_t {}; + const env_t env_key = {}; struct no_metatable_t {}; const no_metatable_t no_metatable = {}; @@ -3160,26 +3199,46 @@ namespace sol { struct upvalue_index { int index; - upvalue_index(int idx) : index(lua_upvalueindex(idx)) {} - operator int() const { return index; } + upvalue_index(int idx) : index(lua_upvalueindex(idx)) { + + } + + operator int() const { + return index; + } }; struct raw_index { int index; - raw_index(int i) : index(i) {} - operator int() const { return index; } + raw_index(int i) : index(i) { + + } + + operator int() const { + return index; + } }; struct absolute_index { int index; - absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) {} - operator int() const { return index; } + absolute_index(lua_State* L, int idx) : index(lua_absindex(L, idx)) { + + } + + operator int() const { + return index; + } }; struct ref_index { int index; - ref_index(int idx) : index(idx) {} - operator int() const { return index; } + ref_index(int idx) : index(idx) { + + } + + operator int() const { + return index; + } }; struct lightuserdata_value { @@ -3289,6 +3348,18 @@ namespace sol { } }; + template + struct nested { + T source; + + template + nested(Args&&... args) : source(std::forward(args)...) {} + + operator std::add_lvalue_reference_t() { + return source; + } + }; + template as_table_t as_table(T&& container) { return as_table_t(std::forward(container)); @@ -3304,6 +3375,19 @@ namespace sol { } }; + struct new_table { + int sequence_hint = 0; + int map_hint = 0; + + new_table() = default; + new_table(const new_table&) = default; + new_table(new_table&&) = default; + new_table& operator=(const new_table&) = default; + new_table& operator=(new_table&&) = default; + + new_table(int sequence_hint, int map_hint = 0) : sequence_hint(sequence_hint), map_hint(map_hint) {} + }; + enum class call_syntax { dot = 0, colon = 1 @@ -3315,7 +3399,9 @@ namespace sol { runtime = LUA_ERRRUN, memory = LUA_ERRMEM, handler = LUA_ERRERR, - gc = LUA_ERRGCMM + gc = LUA_ERRGCMM, + syntax = LUA_ERRSYNTAX, + file = LUA_ERRFILE, }; enum class thread_status : int { @@ -3354,6 +3440,61 @@ namespace sol { table | boolean | function | userdata | lightuserdata }; + inline const std::string& to_string(call_status c) { + static const std::array names{{ + "ok", + "yielded", + "runtime", + "memory", + "handler", + "gc", + "syntax", + "file", + }}; + switch (c) { + case call_status::ok: + return names[0]; + case call_status::yielded: + return names[1]; + case call_status::runtime: + return names[2]; + case call_status::memory: + return names[3]; + case call_status::handler: + return names[4]; + case call_status::gc: + return names[5]; + case call_status::syntax: + return names[6]; + case call_status::file: + return names[7]; + } + return names[0]; + } + + inline const std::string& to_string(load_status c) { + static const std::array names{ { + "ok", + "memory", + "gc", + "syntax", + "file", + } }; + switch (c) { + case load_status::ok: + return names[0]; + case load_status::memory: + return names[1]; + case load_status::gc: + return names[2]; + case load_status::syntax: + return names[3]; + case load_status::file: + return names[4]; + } + return names[0]; + } + enum class meta_function { construct, index, @@ -3390,54 +3531,52 @@ namespace sol { typedef meta_function meta_method; - const std::array meta_variable_names = { { - "__index", - "__newindex", - } }; + inline const std::array& meta_function_names() { + static const std::array names = { { + "new", + "__index", + "__newindex", + "__mode", + "__call", + "__mt", + "__tostring", + "__len", + "__unm", + "__add", + "__sub", + "__mul", + "__div", + "__mod", + "__pow", + "__concat", + "__eq", + "__lt", + "__le", + "__gc", - const std::array meta_function_names = { { - "new", - "__index", - "__newindex", - "__mode", - "__call", - "__mt", - "__tostring", - "__len", - "__unm", - "__add", - "__sub", - "__mul", - "__div", - "__mod", - "__pow", - "__concat", - "__eq", - "__lt", - "__le", - "__gc", - - "__idiv", - "__shl", - "__shr", - "__bnot", - "__band", - "__bor", - "__bxor", + "__idiv", + "__shl", + "__shr", + "__bnot", + "__band", + "__bor", + "__bxor", - "__pairs", - "__next" - } }; + "__pairs", + "__next" + } }; + return names; + } - inline const std::string& name_of(meta_function mf) { - return meta_function_names[static_cast(mf)]; + inline const std::string& to_string(meta_function mf) { + return meta_function_names()[static_cast(mf)]; } inline type type_of(lua_State* L, int index) { return static_cast(lua_type(L, index)); } - inline int type_panic(lua_State* L, int index, type expected, type actual) { + inline int type_panic(lua_State* L, int index, type expected, type actual) noexcept(false) { return luaL_error(L, "stack index %d, expected %s, received %s", index, expected == type::poly ? "anything" : lua_typename(L, static_cast(expected)), expected == type::poly ? "anything" : lua_typename(L, static_cast(actual)) @@ -3449,15 +3588,15 @@ namespace sol { return 0; } - inline void type_error(lua_State* L, int expected, int actual) { + inline void type_error(lua_State* L, int expected, int actual) noexcept(false) { luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual)); } - inline void type_error(lua_State* L, type expected, type actual) { + inline void type_error(lua_State* L, type expected, type actual) noexcept(false) { type_error(L, static_cast(expected), static_cast(actual)); } - inline void type_assert(lua_State* L, int index, type expected, type actual) { + inline void type_assert(lua_State* L, int index, type expected, type actual) noexcept(false) { if (expected != type::poly && expected != actual) { type_panic(L, index, expected, actual); } @@ -3484,22 +3623,33 @@ namespace sol { using table_core = basic_table_core; template using stack_table_core = basic_table_core; + template + using basic_table = basic_table_core; typedef table_core table; typedef table_core global_table; typedef stack_table_core stack_table; typedef stack_table_core stack_global_table; + template + struct basic_environment; + using environment = basic_environment; + using stack_environment = basic_environment; template class basic_function; template class basic_protected_function; - using function = basic_function; using protected_function = basic_protected_function; - using stack_function = basic_function; using stack_protected_function = basic_protected_function; using unsafe_function = basic_function; using safe_function = basic_protected_function; using stack_unsafe_function = basic_function; using stack_safe_function = basic_protected_function; +#ifdef SOL_SAFE_FUNCTIONS + using function = protected_function; + using stack_function = stack_protected_function; +#else + using function = unsafe_function; + using stack_function = stack_unsafe_function; +#endif template class basic_object; template @@ -3517,6 +3667,7 @@ namespace sol { class thread; struct variadic_args; struct this_state; + struct this_environment; namespace detail { template @@ -3588,6 +3739,21 @@ namespace sol { template struct lua_type_of> : std::integral_constant { }; + template <> + struct lua_type_of : std::integral_constant { }; + + template + struct lua_type_of> : std::integral_constant { }; + + template <> + struct lua_type_of : std::integral_constant { }; + + template <> + struct lua_type_of : std::integral_constant { }; + + template + struct lua_type_of> : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; @@ -3654,6 +3820,9 @@ namespace sol { template <> struct lua_type_of : std::integral_constant {}; + template <> + struct lua_type_of : std::integral_constant {}; + template <> struct lua_type_of : std::integral_constant {}; @@ -3669,6 +3838,18 @@ namespace sol { template struct is_container : std::false_type {}; + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + + template <> + struct is_container : std::false_type {}; + template struct is_container>::value>> : std::true_type {}; @@ -3686,10 +3867,14 @@ namespace sol { struct is_unique_usertype : std::integral_constant::value> {}; template - struct lua_type_of : detail::lua_type_of {}; + struct lua_type_of : detail::lua_type_of { + typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; + }; template - struct lua_size : std::integral_constant { }; + struct lua_size : std::integral_constant { + typedef int SOL_INTERNAL_UNSPECIALIZED_MARKER_; + }; template struct lua_size> : std::integral_constant::value + lua_size::value> { }; @@ -3697,10 +3882,24 @@ namespace sol { template struct lua_size> : std::integral_constant::value> { }; + namespace detail { + template + struct void_ { typedef void type; }; + template + struct has_internal_marker_impl : std::false_type {}; + template + struct has_internal_marker_impl::type> : std::true_type {}; + + template + struct has_internal_marker : has_internal_marker_impl {}; + } + template struct is_lua_primitive : std::integral_constant>::value - || (lua_size::value > 1) + || ((type::userdata == lua_type_of>::value) + && detail::has_internal_marker>>::value + && !detail::has_internal_marker>>::value) || std::is_base_of>::value || std::is_base_of>::value || meta::is_specialization_of>::value @@ -3740,6 +3939,9 @@ namespace sol { template <> struct is_transparent_argument : std::true_type {}; + template <> + struct is_transparent_argument : std::true_type {}; + template <> struct is_transparent_argument : std::true_type {}; @@ -3780,6 +3982,9 @@ namespace sol { template struct is_userdata> : std::true_type {}; + template + struct is_environment : std::integral_constant::value || is_table::value> {}; + template struct is_container : detail::is_container{}; @@ -3787,6 +3992,14 @@ namespace sol { inline type type_of() { return lua_type_of>::value; } + + namespace detail { + template + struct lua_type_of, std::enable_if_t<::sol::is_container::value>> : std::integral_constant {}; + + template + struct lua_type_of, std::enable_if_t::value>> : lua_type_of {}; + } // detail } // sol // end of sol/types.hpp @@ -3862,12 +4075,59 @@ namespace sol { inline bool operator!= (const stack_reference& l, const stack_reference& r) { return !operator==(l, r); } + + inline bool operator==(const stack_reference& lhs, const lua_nil_t&) { + return !lhs.valid(); + } + + inline bool operator==(const lua_nil_t&, const stack_reference& rhs) { + return !rhs.valid(); + } + + inline bool operator!=(const stack_reference& lhs, const lua_nil_t&) { + return lhs.valid(); + } + + inline bool operator!=(const lua_nil_t&, const stack_reference& rhs) { + return rhs.valid(); + } } // sol // end of sol/stack_reference.hpp namespace sol { namespace stack { + inline void remove(lua_State* L, int rawindex, int count) { + if (count < 1) + return; + int top = lua_gettop(L); + if (rawindex == -count || top == rawindex) { + // Slice them right off the top + lua_pop(L, static_cast(count)); + return; + } + + // Remove each item one at a time using stack operations + // Probably slower, maybe, haven't benchmarked, + // but necessary + int index = lua_absindex(L, rawindex); + if (index < 0) { + index = lua_gettop(L) + (index + 1); + } + int last = index + count; + for (int i = index; i < last; ++i) { + lua_remove(L, index); + } + } + + struct push_popper_at { + lua_State* L; + int index; + int count; + push_popper_at(lua_State* luastate, int index = -1, int count = 1) : L(luastate), index(index), count(count) { } + ~push_popper_at() { remove(L, index, count); } + }; + template struct push_popper_n { lua_State* L; @@ -3894,6 +4154,12 @@ namespace sol { push_popper push_pop(T&& x) { return push_popper(std::forward(x)); } + template + push_popper_at push_pop_at(T&& x) { + int c = x.push(); + lua_State* L = x.lua_state(); + return push_popper_at(L, lua_absindex(L, -c), c); + } template push_popper_n pop_n(lua_State* L, int x) { return push_popper_n(L, x); @@ -3902,6 +4168,7 @@ namespace sol { namespace detail { struct global_tag { } const global_{}; + struct no_safety_tag {} const no_safety{}; } // detail class reference { @@ -4030,6 +4297,22 @@ namespace sol { inline bool operator!= (const reference& l, const reference& r) { return !operator==(l, r); } + + inline bool operator==(const reference& lhs, const lua_nil_t&) { + return !lhs.valid(); + } + + inline bool operator==(const lua_nil_t&, const reference& rhs) { + return !rhs.valid(); + } + + inline bool operator!=(const reference& lhs, const lua_nil_t&) { + return lhs.valid(); + } + + inline bool operator!=(const lua_nil_t&, const reference& rhs) { + return rhs.valid(); + } } // sol // end of sol/reference.hpp @@ -4038,81 +4321,6 @@ namespace sol { // beginning of sol/stack_core.hpp -// beginning of sol/userdata.hpp - -namespace sol { - template - class basic_userdata : public base_t { - public: - basic_userdata() noexcept = default; - template , basic_userdata>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_userdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_userdata>::value) { - auto pp = stack::push_pop(*this); - type_assert(base_t::lua_state(), -1, type::userdata); - } -#endif // Safety - } - basic_userdata(const basic_userdata&) = default; - basic_userdata(basic_userdata&&) = default; - basic_userdata& operator=(const basic_userdata&) = default; - basic_userdata& operator=(basic_userdata&&) = default; - basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {} - basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> - basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} - basic_userdata(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::userdata); -#endif // Safety - } - basic_userdata(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - type_assert(L, -1, type::userdata); -#endif // Safety - } - }; - - template - class basic_lightuserdata : public base_t { - public: - basic_lightuserdata() noexcept = default; - template , basic_lightuserdata>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_lightuserdata(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_userdata>::value) { - auto pp = stack::push_pop(*this); - type_assert(base_t::lua_state(), -1, type::lightuserdata); - } -#endif // Safety - } - basic_lightuserdata(const basic_lightuserdata&) = default; - basic_lightuserdata(basic_lightuserdata&&) = default; - basic_lightuserdata& operator=(const basic_lightuserdata&) = default; - basic_lightuserdata& operator=(basic_lightuserdata&&) = default; - basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} - basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> - basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} - basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::lightuserdata); -#endif // Safety - } - basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - auto pp = stack::push_pop(*this); - type_assert(L, -1, type::lightuserdata); -#endif // Safety - } - }; - -} // sol - -// end of sol/userdata.hpp - // beginning of sol/tie.hpp namespace sol { @@ -4349,6 +4557,7 @@ namespace sol { }; template using strip_t = typename strip::type; + const bool default_check_arguments = #ifdef SOL_CHECK_ARGUMENTS true; @@ -4359,6 +4568,17 @@ namespace sol { inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { return getter>{}.get(L, index, tracking); } + + template + inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + typedef meta::all< + std::is_lvalue_reference, + meta::neg>, + meta::neg>>, + meta::neg>> + > use_reference_tag; + return pusher>>{}.push(L, std::forward(arg), std::forward(args)...); + } } // stack_detail inline bool maybe_indexable(lua_State* L, int index = -1) { @@ -4379,13 +4599,12 @@ namespace sol { template inline int push_reference(lua_State* L, T&& t, Args&&... args) { - typedef meta::all< - std::is_lvalue_reference, - meta::neg>, - meta::neg>>, - meta::neg>> - > use_reference_tag; - return pusher>>{}.push(L, std::forward(t), std::forward(args)...); + return stack_detail::push_reference(L, std::forward(t), std::forward(args)...); + } + + template + inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + return stack_detail::push_reference(L, std::forward(arg), std::forward(args)...); } inline int multi_push(lua_State*) { @@ -4614,6 +4833,7 @@ namespace sol { // beginning of sol/demangle.hpp #include +#include namespace sol { namespace detail { @@ -4984,6 +5204,15 @@ namespace sol { } }; + template + struct checker { + template + static bool check(lua_State*, int, Handler&&, record& tracking) { + tracking.use(0); + return true; + } + }; + template struct checker { template @@ -5046,6 +5275,14 @@ namespace sol { } }; + template + struct checker, type::userdata, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + return stack::check(L, index, std::forward(handler), tracking); + } + }; + template struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; @@ -5074,7 +5311,7 @@ namespace sol { return false; } // Do advanced check for call-style userdata? - static const auto& callkey = name_of(meta_function::call); + static const auto& callkey = to_string(meta_function::call); if (lua_getmetatable(L, index) == 0) { // No metatable, no __call key possible handler(L, index, type::function, t); @@ -5107,7 +5344,73 @@ namespace sol { return true; } if (t != type::userdata) { - handler(L, index, type::function, t); + handler(L, index, type::table, t); + return false; + } + return true; + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, expected, t); + return false; + } + return true; + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, type::table, t); + return false; + } + return true; + } + }; + + template + struct checker, type::poly, C> { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, type::table, t); return false; } return true; @@ -5179,11 +5482,26 @@ namespace sol { } }; - template - struct checker::value>> { + template + struct checker::value>> { + typedef typename unique_usertype_traits::type T; template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return checker::type, type::userdata>{}.check(L, index, std::forward(handler), tracking); + const type indextype = type_of(L, index); + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype); + return false; + } + if (lua_getmetatable(L, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L); + if (stack_detail::check_metatable>(L, metatableindex)) + return true; + lua_pop(L, 1); + handler(L, index, type::userdata, indextype); + return false; } }; @@ -5258,7 +5576,6 @@ namespace sol { #ifdef SOL_CODECVT_SUPPORT #include -#include #endif namespace sol { @@ -5305,53 +5622,55 @@ namespace sol { template struct getter, std::enable_if_t>::value>> { - static T get(lua_State* L, int index, record& tracking) { + static T get(lua_State* L, int relindex, record& tracking) { typedef typename T::value_type V; + return get(types(), L, relindex, tracking); + } + + template + static T get(types, lua_State* L, int relindex, record& tracking) { tracking.use(1); - index = lua_absindex(L, index); + int index = lua_absindex(L, relindex); T arr; - get_field(L, static_cast(-1), index); - int isnum; - std::size_t sizehint = static_cast(lua_tointegerx(L, -1, &isnum)); - if (isnum != 0) { - detail::reserve(arr, sizehint); - } - lua_pop(L, 1); #if SOL_LUA_VERSION >= 503 // This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3 for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { + bool isnil = false; for (int vi = 0; vi < lua_size::value; ++vi) { type t = static_cast(lua_geti(L, index, i + vi)); - if (t == type::lua_nil) { + isnil = t == type::lua_nil; + if (isnil) { if (i == 0) { - continue; - } - else { - lua_pop(L, (vi + 1)); - return arr; + break; } + lua_pop(L, (vi + 1)); + return arr; } } + if (isnil) + continue; arr.push_back(stack::get(L, -lua_size::value)); } #else // Zzzz slower but necessary thanks to the lower version API and missing functions qq for (lua_Integer i = 0; ; i += lua_size::value, lua_pop(L, lua_size::value)) { + bool isnil = false; for (int vi = 0; vi < lua_size::value; ++vi) { lua_pushinteger(L, i); lua_gettable(L, index); type t = type_of(L, -1); - if (t == type::lua_nil) { + isnil = t == type::lua_nil; + if (isnil) { if (i == 0) { - continue; - } - else { - lua_pop(L, (vi + 1)); - return arr; + break; } + lua_pop(L, (vi + 1)); + return arr; } } + if (isnil) + continue; arr.push_back(stack::get(L, -1)); } #endif @@ -5365,10 +5684,15 @@ namespace sol { typedef typename T::value_type P; typedef typename P::first_type K; typedef typename P::second_type V; + return get(types(), L, index, tracking); + } + + template + static T get(types, lua_State* L, int relindex, record& tracking) { tracking.use(1); T associative; - index = lua_absindex(L, index); + int index = lua_absindex(L, relindex); lua_pushnil(L); while (lua_next(L, index) != 0) { decltype(auto) key = stack::check_get(L, -2); @@ -5383,6 +5707,40 @@ namespace sol { } }; + template + struct getter, std::enable_if_t::value>> { + static T get(lua_State* L, int index, record& tracking) { + getter g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(L, index, tracking); + } + }; + + template + struct getter, std::enable_if_t, meta::neg>>>::value>> { + static T get(lua_State* L, int index, record& tracking) { + typedef typename T::value_type V; + getter> g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(types>(), L, index, tracking); + } + }; + + template + struct getter, std::enable_if_t, meta::has_key_value_pair>>::value>> { + static T get(lua_State* L, int index, record& tracking) { + typedef typename T::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + getter> g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(types>(), L, index, tracking); + } + }; + template struct getter::value || std::is_base_of::value>> { static T get(lua_State* L, int index, record& tracking) { @@ -5497,7 +5855,7 @@ namespace sol { if (sizeof(wchar_t) == 2) { static std::wstring_convert> convert; std::wstring r = convert.from_bytes(str, str + len); -#ifdef __MINGW32__ +#if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ < 7 // Fuck you, MinGW, and fuck you libstdc++ for introducing this absolutely asinine bug // https://sourceforge.net/p/mingw-w64/bugs/538/ // http://chat.stackoverflow.com/transcript/message/32271369#32271369 @@ -5586,8 +5944,9 @@ namespace sol { static meta_function get(lua_State *L, int index, record& tracking) { tracking.use(1); const char* name = getter{}.get(L, index, tracking); - for (std::size_t i = 0; i < meta_function_names.size(); ++i) - if (meta_function_names[i] == name) + const auto& mfnames = meta_function_names(); + for (std::size_t i = 0; i < mfnames.size(); ++i) + if (mfnames[i] == name) return static_cast(i); return meta_function::construct; } @@ -5696,35 +6055,50 @@ namespace sol { tracking.use(1); return nullptr; } - return getter>::get_no_lua_nil(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get_no_lua_nil(L, index, tracking); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { - return getter>::get_no_lua_nil(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get_no_lua_nil(L, index, tracking); } }; template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter>::get(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get(L, index, tracking); } }; template struct getter> { static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); + getter g; + // Avoid VC++ warning + (void)g; + return g.get(L, index, tracking); } }; template struct getter { static T* get(lua_State* L, int index, record& tracking) { - return getter>::get(L, index, tracking); + getter> g; + // Avoid VC++ warning + (void)g; + return g.get(L, index, tracking); } }; @@ -5770,7 +6144,6 @@ namespace sol { return std::pair(L, index)), decltype(stack::get(L, index))>{stack::get(L, index, tracking), stack::get(L, index + tracking.used, tracking)}; } }; - } // stack } // sol @@ -5979,6 +6352,27 @@ namespace sol { namespace sol { namespace stack { + inline int push_environment_of(lua_State* L, int index = -1) { +#if SOL_LUA_VERSION < 502 + // Use lua_setfenv + lua_getfenv(L, index); + return 1; +#else + // Use upvalues as explained in Lua 5.2 and beyond's manual + if (lua_getupvalue(L, index, 1) == nullptr) { + push(L, lua_nil); + return 1; + } +#endif + return 1; + } + + template + int push_environment_of(const T& target) { + target.push(); + return push_environment_of(target.lua_state(), -1) + 1; + } + template struct pusher> { template @@ -6068,8 +6462,6 @@ namespace sol { template >> = meta::enabler> static int push(lua_State* L, Arg&& arg) { - if (unique_usertype_traits::is_null(arg)) - return stack::push(L, lua_nil); return push_deep(L, std::forward(arg)); } @@ -6215,8 +6607,8 @@ namespace sol { }; template<> - struct pusher { - static int push(lua_State* L, metatable_key_t) { + struct pusher { + static int push(lua_State* L, metatable_t) { lua_pushlstring(L, "__mt", 4); return 1; } @@ -6305,7 +6697,7 @@ namespace sol { return 1; } - template , no_metatable_t, metatable_key_t>> = meta::enabler> + template , no_metatable_t, metatable_t>> = meta::enabler> static int push(lua_State* L, Arg&& arg, Args&&... args) { const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, std::forward(arg), std::forward(args)...); @@ -6318,7 +6710,7 @@ namespace sol { } template - static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) { + static int push(lua_State* L, metatable_t, Key&& key, Args&&... args) { const auto name = &key[0]; return push_with(L, name, std::forward(args)...); } @@ -6412,7 +6804,7 @@ namespace sol { template<> struct pusher { static int push(lua_State* L, meta_function m) { - const std::string& str = name_of(m); + const std::string& str = to_string(m); lua_pushlstring(L, str.c_str(), str.size()); return 1; } @@ -6634,6 +7026,14 @@ namespace sol { return 0; } }; + + template<> + struct pusher { + static int push(lua_State* L, const new_table& nt) { + lua_createtable(L, nt.sequence_hint, nt.map_hint); + return 1; + } + }; } // stack } // sol @@ -6685,13 +7085,28 @@ namespace sol { }; template - struct field_getter { - void get(lua_State* L, metatable_key_t, int tableindex = -1) { + struct field_getter { + void get(lua_State* L, metatable_t, int tableindex = -1) { if (lua_getmetatable(L, tableindex) == 0) push(L, lua_nil); } }; + template + struct field_getter { + void get(lua_State* L, env_t, int tableindex = -1) { +#if SOL_LUA_VERSION < 502 + // Use lua_setfenv + lua_getfenv(L, tableindex); +#else + // Use upvalues as explained in Lua 5.2 and beyond's manual + if (lua_getupvalue(L, tableindex, 1) == nullptr) { + push(L, lua_nil); + } +#endif + } + }; + template struct field_getter::value>> { template @@ -6710,7 +7125,7 @@ namespace sol { #if SOL_LUA_VERSION >= 503 template - struct field_getter::value>> { + struct field_getter::value && !std::is_same::value>> { template void get(lua_State* L, Key&& key, int tableindex = -1) { lua_geti(L, tableindex, static_cast(key)); @@ -6728,7 +7143,7 @@ namespace sol { #endif // Lua 5.3.x template - struct field_getter::value>> { + struct field_getter::value && !std::is_same::value>> { template void get(lua_State* L, Key&& key, int tableindex = -1) { lua_rawgeti(L, tableindex, static_cast(key)); @@ -6799,9 +7214,9 @@ namespace sol { }; template - struct field_setter { + struct field_setter { template - void set(lua_State* L, metatable_key_t, Value&& value, int tableindex = -2) { + void set(lua_State* L, metatable_t, Value&& value, int tableindex = -2) { push(L, std::forward(value)); lua_setmetatable(L, tableindex); } @@ -6827,7 +7242,7 @@ namespace sol { #if SOL_LUA_VERSION >= 503 template - struct field_setter::value>> { + struct field_setter::value && !std::is_same::value>> { template void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { push(L, std::forward(value)); @@ -6837,7 +7252,7 @@ namespace sol { #endif // Lua 5.3.x template - struct field_setter::value>> { + struct field_setter::value && !std::is_same::value>> { template void set(lua_State* L, Key&& key, Value&& value, int tableindex = -2) { push(L, std::forward(value)); @@ -6983,7 +7398,7 @@ namespace sol { } template - inline std::pair get_as_upvalues(lua_State* L, int index = 1) { + inline std::pair get_as_upvalues(lua_State* L, int index = 2) { const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); typedef std::array data_t; data_t voiddata{ {} }; @@ -7032,28 +7447,6 @@ namespace sol { return luaL_ref(L, tableindex); } - inline void remove(lua_State* L, int index, int count) { - if (count < 1) - return; - int top = lua_gettop(L); - if (index == -1 || top == index) { - // Slice them right off the top - lua_pop(L, static_cast(count)); - return; - } - - // Remove each item one at a time using stack operations - // Probably slower, maybe, haven't benchmarked, - // but necessary - if (index < 0) { - index = lua_gettop(L) + (index + 1); - } - int last = index + count; - for (int i = index; i < last; ++i) { - lua_remove(L, index); - } - } - template ::value>> inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { typedef std::make_index_sequence args_indices; @@ -7155,6 +7548,140 @@ namespace sol { // end of sol/stack.hpp +// beginning of sol/object_base.hpp + +namespace sol { + + template + class basic_object_base : public base_t { + private: + template + decltype(auto) as_stack(std::true_type) const { + return stack::get(base_t::lua_state(), base_t::stack_index()); + } + + template + decltype(auto) as_stack(std::false_type) const { + base_t::push(); + return stack::pop(base_t::lua_state()); + } + + template + bool is_stack(std::true_type) const { + return stack::check(base_t::lua_state(), base_t::stack_index(), no_panic); + } + + template + bool is_stack(std::false_type) const { + int r = base_t::registry_index(); + if (r == LUA_REFNIL) + return meta::any_same, lua_nil_t, nullopt_t, std::nullptr_t>::value ? true : false; + if (r == LUA_NOREF) + return false; + auto pp = stack::push_pop(*this); + return stack::check(base_t::lua_state(), -1, no_panic); + } + + public: + basic_object_base() noexcept = default; + basic_object_base(const basic_object_base&) = default; + basic_object_base(basic_object_base&&) = default; + basic_object_base& operator=(const basic_object_base&) = default; + basic_object_base& operator=(basic_object_base&&) = default; + template , basic_object_base>>> = meta::enabler> + basic_object_base(T&& arg, Args&&... args) : base_t(std::forward(arg), std::forward(args)...) { } + + template + decltype(auto) as() const { + return as_stack(std::is_same()); + } + + template + bool is() const { + return is_stack(std::is_same()); + } + }; +} // sol + +// end of sol/object_base.hpp + +// beginning of sol/userdata.hpp + +namespace sol { + template + class basic_userdata : public basic_table { + typedef basic_table base_t; + public: + basic_userdata() noexcept = default; + template , basic_userdata>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_userdata(T&& r) noexcept : base_t(std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_userdata>::value) { + auto pp = stack::push_pop(*this); + type_assert(base_t::lua_state(), -1, type::userdata); + } +#endif // Safety + } + basic_userdata(const basic_userdata&) = default; + basic_userdata(basic_userdata&&) = default; + basic_userdata& operator=(const basic_userdata&) = default; + basic_userdata& operator=(basic_userdata&&) = default; + basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {} + basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {} + template >>, meta::neg, ref_index>>> = meta::enabler> + basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {} + basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_userdata(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, index, type_panic); +#endif // Safety + } + }; + + template + class basic_lightuserdata : public basic_object_base { + typedef basic_object_base base_t; + public: + basic_lightuserdata() noexcept = default; + template , basic_lightuserdata>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_lightuserdata(T&& r) noexcept : base_t(std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_lightuserdata>::value) { + auto pp = stack::push_pop(*this); + type_assert(base_t::lua_state(), -1, type::lightuserdata); + } +#endif // Safety + } + basic_lightuserdata(const basic_lightuserdata&) = default; + basic_lightuserdata(basic_lightuserdata&&) = default; + basic_lightuserdata& operator=(const basic_lightuserdata&) = default; + basic_lightuserdata& operator=(basic_lightuserdata&&) = default; + basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} + basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {} + template >>, meta::neg, ref_index>>> = meta::enabler> + basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {} + basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_lightuserdata(lua_State* L, ref_index index) : base_t(L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, index, type_panic); +#endif // Safety + } + }; + +} // sol + +// end of sol/userdata.hpp + // beginning of sol/as_args.hpp namespace sol { @@ -7195,8 +7722,10 @@ namespace sol { // beginning of sol/proxy_base.hpp namespace sol { + struct proxy_base_tag {}; + template - struct proxy_base { + struct proxy_base : proxy_base_tag { operator std::string() const { const Super& super = *static_cast(static_cast(this)); return super.template get(); @@ -7349,9 +7878,14 @@ namespace sol { typedef types free_args_list; typedef typename traits_type::returns_list returns_list; - template - static decltype(auto) invoke(object_type& mem, Args&&... args) { - return (mem.*fx)(std::forward(args)...); + template + static decltype(auto) invoke(object_type& mem) { + return mem.*fx; + } + + template + static decltype(auto) invoke(object_type& mem, Arg&& arg, Args&&...) { + return mem.*fx = std::forward(arg); } template @@ -7495,9 +8029,9 @@ namespace sol { namespace sol { namespace function_detail { - template + template inline int call(lua_State* L) { - Fx& fx = stack::get>(L, upvalue_index(1)); + Fx& fx = stack::get>(L, upvalue_index(start)); return fx(L); } } // function_detail @@ -7592,11 +8126,29 @@ namespace sol { return property_detail::property(std::true_type(), std::forward(f)); } + template + inline decltype(auto) writeonly_property(F&& f) { + return property_detail::property(std::false_type(), std::forward(f)); + } + + template + struct readonly_wrapper { + T v; + + readonly_wrapper(T v) : v(std::move(v)) {} + + operator T& () { + return v; + } + operator const T& () const { + return v; + } + }; + // Allow someone to make a member variable readonly (const) template inline auto readonly(R T::* v) { - typedef const R C; - return static_cast(v); + return readonly_wrapper>(v); } template @@ -7616,11 +8168,25 @@ namespace sol { return var_wrapper(std::forward(v)); } + namespace meta { + template + struct is_member_object : std::is_member_object_pointer {}; + + template + struct is_member_object> : std::true_type {}; + } + } // sol // end of sol/property.hpp namespace sol { + namespace function_detail { + inline int no_construction_error(lua_State* L) { + return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + } + } + namespace call_detail { template @@ -7634,7 +8200,7 @@ namespace sol { } template - struct void_call; + struct void_call : void_call> {}; template struct void_call> { @@ -7662,7 +8228,7 @@ namespace sol { template inline int overload_match_arity(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; + typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity @@ -7686,7 +8252,7 @@ namespace sol { template inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; + typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity @@ -7701,7 +8267,7 @@ namespace sol { template inline int overload_match_arity_single(types, std::index_sequence, std::index_sequence, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - typedef lua_bind_traits> traits; + typedef lua_bind_traits> traits; typedef meta::tuple_types return_types; typedef typename traits::free_args_list args_list; // compile-time eliminate any functions that we know ahead of time are of improper arity @@ -7837,7 +8403,7 @@ namespace sol { template struct agnostic_lua_call_wrapper { static int call(lua_State* L, const no_construction&) { - return luaL_error(L, "sol: cannot call this constructor (tagged as non-constructible)"); + return function_detail::no_construction_error(L); } }; @@ -7849,6 +8415,13 @@ namespace sol { } }; + template + struct agnostic_lua_call_wrapper, is_index, is_variable, checked, boost, C> { + static int call(lua_State* L, std::reference_wrapper f) { + return agnostic_lua_call_wrapper{}.call(L, f.get()); + } + }; + template struct lua_call_wrapper : agnostic_lua_call_wrapper {}; @@ -7922,7 +8495,7 @@ namespace sol { template static int call_const(std::false_type, lua_State* L, Args&&... args) { typedef typename traits_type::return_type R; - return call_assign(std::is_assignable>, R>(), L, std::forward(args)...); + return call_assign(std::is_copy_assignable>(), L, std::forward(args)...); } template @@ -7932,12 +8505,12 @@ namespace sol { template static int call(lua_State* L, V&& f) { - return call_const(std::is_const(), L, f); + return call_const(std::is_const(), L, std::forward(f)); } template static int call(lua_State* L, V&& f, object_type& o) { - return call_const(std::is_const(), L, f, o); + return call_const(std::is_const(), L, std::forward(f), o); } }; @@ -7948,9 +8521,10 @@ namespace sol { typedef typename wrap::object_type object_type; template - static int call(lua_State* L, V&& f, object_type& o) { + static int call(lua_State* L, V&& v, object_type& o) { typedef typename wrap::returns_list returns_list; typedef typename wrap::caller caller; + F f(std::forward(v)); return stack::call_into_lua(returns_list(), types<>(), L, boost + ( is_variable ? 3 : 2 ), caller(), f, o); } @@ -7974,6 +8548,28 @@ namespace sol { } }; + template + struct lua_call_wrapper, false, is_variable, checked, boost, C> { + typedef lua_bind_traits traits_type; + typedef wrapper> wrap; + typedef typename wrap::object_type object_type; + + template + static int call(lua_State* L, V&&) { + return luaL_error(L, "sol: cannot write to a sol::readonly variable"); + } + + template + static int call(lua_State* L, V&&, object_type&) { + return luaL_error(L, "sol: cannot write to a sol::readonly variable"); + } + }; + + template + struct lua_call_wrapper, true, is_variable, checked, boost, C> : lua_call_wrapper { + + }; + template struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { typedef constructor_list F; @@ -8102,12 +8698,21 @@ namespace sol { struct lua_call_wrapper, is_index, is_variable, checked, boost, C> { typedef std::conditional_t P; typedef meta::unqualified_t

U; + typedef wrapper wrap; typedef lua_bind_traits traits_type; + typedef meta::unqualified_t> object_type; template - static int self_call(lua_State* L, F&& f) { - typedef wrapper wrap; - typedef meta::unqualified_t> object_type; + static int self_call(std::true_type, lua_State* L, F&& f) { + // The type being void means we don't have any arguments, so it might be a free functions? + typedef typename traits_type::free_args_list args_list; + typedef typename wrap::returns_list returns_list; + typedef typename wrap::caller caller; + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f); + } + + template + static int self_call(std::false_type, lua_State* L, F&& f) { typedef meta::pop_front_type_t args_list; typedef T Ta; #ifdef SOL_SAFE_USERTYPE @@ -8129,7 +8734,7 @@ namespace sol { template static int defer_call(std::false_type, lua_State* L, F&& f, Args&&... args) { - return self_call(L, pick(meta::boolean(), f), std::forward(args)...); + return self_call(meta::any, meta::boolean>::value != type::userdata>>(), L, pick(meta::boolean(), f), std::forward(args)...); } template @@ -8175,9 +8780,9 @@ namespace sol { return lua_call_wrapper, is_index, is_variable, stack::stack_detail::default_check_arguments, boost>{}.call(L, std::forward(fx), std::forward(args)...); } - template + template inline int call_user(lua_State* L) { - auto& fx = stack::get>(L, upvalue_index(1)); + auto& fx = stack::get>(L, upvalue_index(start)); return call_wrapped(L, fx); } @@ -8195,6 +8800,9 @@ namespace sol { template struct is_var_bind> : std::true_type {}; + + template + struct is_var_bind> : is_var_bind {}; } // call_detail template @@ -8349,7 +8957,7 @@ namespace sol { // idx n + 1: is the object's void pointer // We don't need to store the size, because the other side is templated // with the same member function pointer type - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); function_type& memfx = memberdata.first; auto& item = *objdata.first; @@ -8376,7 +8984,7 @@ namespace sol { // idx n + 1: is the object's void pointer // We don't need to store the size, because the other side is templated // with the same member function pointer type - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); auto& mem = *objdata.first; function_type& var = memberdata.first; @@ -8399,6 +9007,38 @@ namespace sol { } }; + template + struct upvalue_member_variable> { + typedef std::remove_pointer_t> function_type; + typedef lua_bind_traits traits_type; + + static int real_call(lua_State* L) { + // Layout: + // idx 1...n: verbatim data of member variable pointer + // idx n + 1: is the object's void pointer + // We don't need to store the size, because the other side is templated + // with the same member function pointer type + auto memberdata = stack::stack_detail::get_as_upvalues(L); + auto objdata = stack::stack_detail::get_as_upvalues(L, memberdata.second); + auto& mem = *objdata.first; + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 0: + return call_detail::call_wrapped(L, var, mem); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + static int call(lua_State* L) { + return detail::static_trampoline<(&real_call)>(L); + } + + int operator()(lua_State* L) { + return call(L); + } + }; + template struct upvalue_this_member_function { typedef std::remove_pointer_t> function_type; @@ -8407,7 +9047,7 @@ namespace sol { static int real_call(lua_State* L) { // Layout: // idx 1...n: verbatim data of member variable pointer - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); function_type& memfx = memberdata.first; return call_detail::call_wrapped(L, memfx); } @@ -8429,7 +9069,7 @@ namespace sol { static int real_call(lua_State* L) { // Layout: // idx 1...n: verbatim data of member variable pointer - auto memberdata = stack::stack_detail::get_as_upvalues(L, 1); + auto memberdata = stack::stack_detail::get_as_upvalues(L); function_type& var = memberdata.first; switch (lua_gettop(L)) { case 1: @@ -8449,6 +9089,33 @@ namespace sol { return call(L); } }; + + template + struct upvalue_this_member_variable> { + typedef std::remove_pointer_t> function_type; + typedef lua_bind_traits traits_type; + + static int real_call(lua_State* L) { + // Layout: + // idx 1...n: verbatim data of member variable pointer + auto memberdata = stack::stack_detail::get_as_upvalues(L); + function_type& var = memberdata.first; + switch (lua_gettop(L)) { + case 1: + return call_detail::call_wrapped(L, var); + default: + return luaL_error(L, "sol: incorrect number of arguments to member variable function"); + } + } + + static int call(lua_State* L) { + return detail::static_trampoline<(&real_call)>(L); + } + + int operator()(lua_State* L) { + return call(L); + } + }; } // function_detail } // sol @@ -8766,7 +9433,9 @@ namespace sol { auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t>::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8785,7 +9454,9 @@ namespace sol { template static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8793,7 +9464,9 @@ namespace sol { static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8811,14 +9484,16 @@ namespace sol { auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t>::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr); upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); stack::push(L, c_closure(freefunc, upvalues)); } template static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(std::is_member_object_pointer>(), L, std::forward(fx), std::forward(args)...); + select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); } template >> = meta::enabler> @@ -8830,7 +9505,9 @@ namespace sol { template static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8838,7 +9515,9 @@ namespace sol { static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { typedef typename meta::bind_traits>::object_type C; lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, fx); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, fx); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8852,7 +9531,9 @@ namespace sol { std::decay_t target(std::forward(fx), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_free_function::call; - int upvalues = stack::stack_detail::push_as_upvalues(L, target); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::stack_detail::push_as_upvalues(L, target); stack::push(L, c_closure(freefunc, upvalues)); } @@ -8860,17 +9541,24 @@ namespace sol { stack::push(L, f); } - template + template >, std::is_base_of>>> = meta::enabler> static void select(lua_State* L, Fx&& fx, Args&&... args) { select_function(std::is_function>(), L, std::forward(fx), std::forward(args)...); } + template >, std::is_base_of>>> = meta::enabler> + static void select(lua_State* L, Fx&& fx) { + stack::push(L, std::forward(fx)); + } + template static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = function_detail::call>; + lua_CFunction freefunc = function_detail::call, 2>; - stack::push>(L, std::forward(args)...); - stack::push(L, c_closure(freefunc, 1)); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::forward(args)...); + stack::push(L, c_closure(freefunc, upvalues)); } template @@ -8899,7 +9587,11 @@ namespace sol { template struct pusher> { - static int push(lua_State* L, std::function fx) { + static int push(lua_State* L, const std::function& fx) { + return pusher>{}.push(L, fx); + } + + static int push(lua_State* L, std::function&& fx) { return pusher>{}.push(L, std::move(fx)); } }; @@ -8938,15 +9630,19 @@ namespace sol { template struct pusher> { static int push(lua_State* L, protect_t&& pw) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, std::move(pw.value)); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>>(L, std::move(pw.value)); + return stack::push(L, c_closure(cf, upvalues)); } static int push(lua_State* L, const protect_t& pw) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, pw.value); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>>(L, pw.value); + return stack::push(L, c_closure(cf, upvalues)); } }; @@ -9017,6 +9713,18 @@ namespace sol { } }; + template <> + struct pusher { + static int push(lua_State* L, no_construction) { + lua_CFunction cf = &function_detail::no_construction_error; + return stack::push(L, cf); + } + + static int push(lua_State* L, no_construction c, function_detail::call_indicator) { + return push(L, c); + } + }; + template struct pusher>> { static int push(lua_State* L, detail::tagged>) { @@ -9029,9 +9737,11 @@ namespace sol { struct pusher>> { template static int push(lua_State* L, C&& c) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>>(L, std::forward(c)); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>>(L, std::forward(c)); + return stack::push(L, c_closure(cf, upvalues)); } }; @@ -9046,9 +9756,11 @@ namespace sol { template struct pusher>> { static int push(lua_State* L, destructor_wrapper c) { - lua_CFunction cf = call_detail::call_user>; - int closures = stack::push>(L, std::move(c)); - return stack::push(L, c_closure(cf, closures)); + lua_CFunction cf = call_detail::call_user, 2>; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::move(c)); + return stack::push(L, c_closure(cf, upvalues)); } }; @@ -9199,11 +9911,11 @@ namespace sol { call_status err; template - decltype(auto) tagged_get(types>) const { + decltype(auto) tagged_get(types>) const { if (!valid()) { - return sol::optional(nullopt); + return optional(nullopt); } - return stack::get>(L, index); + return stack::get>(L, index); } template @@ -9424,7 +10136,7 @@ namespace sol { template basic_protected_function(proxy_base&& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function(), std::move(eh)) {} template - basic_protected_function(const proxy_base& p, reference eh = get_default_handler()) : basic_protected_function(static_cast>(p), std::move(eh)) {} + basic_protected_function(const proxy_base& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function(), std::move(eh)) {} template >>, meta::neg>> = meta::enabler> basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} basic_protected_function(lua_State* L, int index = -1, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) { @@ -9562,7 +10274,6 @@ namespace sol { // end of sol/stack_proxy.hpp #include -#include namespace sol { template @@ -9801,30 +10512,10 @@ namespace sol { return r; } - template - class basic_object : public base_t { + template + class basic_object : public basic_object_base { private: - template - decltype(auto) as_stack(std::true_type) const { - return stack::get(base_t::lua_state(), base_t::stack_index()); - } - - template - decltype(auto) as_stack(std::false_type) const { - base_t::push(); - return stack::pop(base_t::lua_state()); - } - - template - bool is_stack(std::true_type) const { - return stack::check(base_t::lua_state(), base_t::stack_index(), no_panic); - } - - template - bool is_stack(std::false_type) const { - auto pp = stack::push_pop(*this); - return stack::check(base_t::lua_state(), -1, no_panic); - } + typedef basic_object_base base_t; template basic_object(std::integral_constant, lua_State* L, int index = -1) noexcept : base_t(L, index) { @@ -9835,7 +10526,7 @@ namespace sol { public: basic_object() noexcept = default; - template , basic_object>>, meta::neg>, std::is_base_of>> = meta::enabler> + template , basic_object>>, meta::neg>, std::is_base_of>> = meta::enabler> basic_object(T&& r) : base_t(std::forward(r)) {} basic_object(lua_nil_t r) : base_t(r) {} basic_object(const basic_object&) = default; @@ -9854,24 +10545,12 @@ namespace sol { basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place, std::forward(arg), std::forward(args)...) {} basic_object& operator=(const basic_object&) = default; basic_object& operator=(basic_object&&) = default; - basic_object& operator=(const base_t& b) { base_t::operator=(b); return *this; } - basic_object& operator=(base_t&& b) { base_t::operator=(std::move(b)); return *this; } + basic_object& operator=(const base_type& b) { base_t::operator=(b); return *this; } + basic_object& operator=(base_type&& b) { base_t::operator=(std::move(b)); return *this; } template basic_object& operator=(const proxy_base& r) { this->operator=(r.operator basic_object()); return *this; } template basic_object& operator=(proxy_base&& r) { this->operator=(r.operator basic_object()); return *this; } - - template - decltype(auto) as() const { - return as_stack(std::is_same()); - } - - template - bool is() const { - if (!base_t::valid()) - return false; - return is_stack(std::is_same()); - } }; template @@ -9883,22 +10562,6 @@ namespace sol { object make_object(lua_State* L, Args&&... args) { return make_reference(L, std::forward(args)...); } - - inline bool operator==(const object& lhs, const lua_nil_t&) { - return !lhs.valid(); - } - - inline bool operator==(const lua_nil_t&, const object& rhs) { - return !rhs.valid(); - } - - inline bool operator!=(const object& lhs, const lua_nil_t&) { - return lhs.valid(); - } - - inline bool operator!=(const lua_nil_t&, const object& rhs) { - return rhs.valid(); - } } // sol // end of sol/object.hpp @@ -9956,7 +10619,7 @@ namespace sol { template decltype(auto) get_or(T&& otherwise) const { typedef decltype(get()) U; - sol::optional option = get>(); + optional option = get>(); if (option) { return static_cast(option.value()); } @@ -9965,7 +10628,7 @@ namespace sol { template decltype(auto) get_or(D&& otherwise) const { - sol::optional option = get>(); + optional option = get>(); if (option) { return static_cast(option.value()); } @@ -10085,6 +10748,128 @@ namespace sol { namespace sol { namespace usertype_detail { + const int metatable_index = 2; + const int metatable_core_index = 3; + const int filler_index = 4; + const int magic_index = 5; + + const int simple_metatable_index = 2; + const int index_function_index = 3; + const int newindex_function_index = 4; + + typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&); + typedef int(*member_search)(lua_State*, void*, int); + + struct call_information { + member_search index; + member_search new_index; + int runtime_target; + + call_information(member_search index, member_search newindex) : call_information(index, newindex, -1) {} + call_information(member_search index, member_search newindex, int runtimetarget) : index(index), new_index(newindex), runtime_target(runtimetarget) {} + }; + + typedef std::unordered_map mapping_t; + + struct variable_wrapper { + virtual int index(lua_State* L) = 0; + virtual int new_index(lua_State* L) = 0; + virtual ~variable_wrapper() {}; + }; + + template + struct callable_binding : variable_wrapper { + F fx; + + template + callable_binding(Arg&& arg) : fx(std::forward(arg)) {} + + virtual int index(lua_State* L) override { + return call_detail::call_wrapped(L, fx); + } + + virtual int new_index(lua_State* L) override { + return call_detail::call_wrapped(L, fx); + } + }; + + typedef std::unordered_map> variable_map; + typedef std::unordered_map function_map; + + struct simple_map { + const char* metakey; + variable_map variables; + function_map functions; + object index; + object newindex; + base_walk indexbaseclasspropogation; + base_walk newindexbaseclasspropogation; + + simple_map(const char* mkey, base_walk index, base_walk newindex, object i, object ni, variable_map&& vars, function_map&& funcs) + : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), + index(std::move(i)), newindex(std::move(ni)), + indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} + }; + } + + struct usertype_metatable_core { + usertype_detail::mapping_t mapping; + lua_CFunction indexfunc; + lua_CFunction newindexfunc; + std::vector runtime; + bool mustindex; + + usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) : + mapping(), indexfunc(ifx), + newindexfunc(nifx), runtime(), mustindex(false) + { + + } + + usertype_metatable_core(const usertype_metatable_core&) = default; + usertype_metatable_core(usertype_metatable_core&&) = default; + usertype_metatable_core& operator=(const usertype_metatable_core&) = default; + usertype_metatable_core& operator=(usertype_metatable_core&&) = default; + + }; + + namespace usertype_detail { + const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); + + struct add_destructor_tag {}; + struct check_destructor_tag {}; + struct verified_tag {} const verified{}; + + template + struct is_non_factory_constructor : std::false_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template + struct is_non_factory_constructor> : std::true_type {}; + + template <> + struct is_non_factory_constructor : std::true_type {}; + + template + struct is_constructor : is_non_factory_constructor {}; + + template + struct is_constructor> : std::true_type {}; + + template + using has_constructor = meta::any>...>; + + template + struct is_destructor : std::false_type {}; + + template + struct is_destructor> : std::true_type {}; + + template + using has_destructor = meta::any>...>; + struct no_comp { template bool operator()(A&&, B&&) const { @@ -10092,30 +10877,32 @@ namespace sol { } }; - typedef void(*base_walk)(lua_State*, bool&, int&, string_detail::string_shim&); - typedef int(*member_search)(lua_State*, void*); - - struct find_call_pair { - member_search first; - member_search second; - - find_call_pair(member_search first, member_search second) : first(first), second(second) {} - }; - - inline bool is_indexer(string_detail::string_shim s) { - return s == name_of(meta_function::index) || s == name_of(meta_function::new_index); + inline int is_indexer(string_detail::string_shim s) { + if (s == to_string(meta_function::index)) { + return 1; + } + else if (s == to_string(meta_function::new_index)) { + return 2; + } + return 0; } - inline bool is_indexer(meta_function mf) { - return mf == meta_function::index || mf == meta_function::new_index; + inline int is_indexer(meta_function mf) { + if (mf == meta_function::index) { + return 1; + } + else if (mf == meta_function::new_index) { + return 2; + } + return 0; } - inline bool is_indexer(call_construction) { - return false; + inline int is_indexer(call_construction) { + return 0; } - inline bool is_indexer(base_classes_tag) { - return false; + inline int is_indexer(base_classes_tag) { + return 0; } inline auto make_shim(string_detail::string_shim s) { @@ -10123,11 +10910,11 @@ namespace sol { } inline auto make_shim(call_construction) { - return string_detail::string_shim(name_of(meta_function::call_function)); + return string_detail::string_shim(to_string(meta_function::call_function)); } inline auto make_shim(meta_function mf) { - return string_detail::string_shim(name_of(mf)); + return string_detail::string_shim(to_string(mf)); } inline auto make_shim(base_classes_tag) { @@ -10147,18 +10934,143 @@ namespace sol { } struct registrar { + registrar() = default; + registrar(const registrar&) = default; + registrar(registrar&&) = default; + registrar& operator=(const registrar&) = default; + registrar& operator=(registrar&&) = default; virtual int push_um(lua_State* L) = 0; virtual ~registrar() {} }; - template + inline bool is_toplevel(lua_State* L, int index = magic_index) { + int isnum = 0; + lua_Integer magic = lua_tointegerx(L, upvalue_index(index), &isnum); + return isnum != 0 && magic == toplevel_magic; + } + + inline int runtime_object_call(lua_State* L, void*, int runtimetarget) { + usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + std::vector& runtime = umc.runtime; + object& runtimeobj = runtime[runtimetarget]; + return stack::push(L, runtimeobj); + } + + template inline int indexing_fail(lua_State* L) { - auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); - string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); - if (is_index) + if (is_index) { +#if 0//def SOL_SAFE_USERTYPE + auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); + string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); - else +#else + if (is_toplevel(L)) { + if (lua_getmetatable(L, 1) == 1) { + int metatarget = lua_gettop(L); + stack::get_field(L, stack_reference(L, raw_index(2)), metatarget); + return 1; + } + } + // With runtime extensibility, we can't hard-error things. They have to return nil, like regular table types, unfortunately... + return stack::push(L, lua_nil); +#endif + } + else { + auto maybeaccessor = stack::get>(L, is_index ? -1 : -2); + string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)")); return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str()); + } + } + + int runtime_new_index(lua_State* L, void*, int runtimetarget); + + template + inline int metatable_newindex(lua_State* L) { + if (is_toplevel(L)) { + auto non_indexable = [&L]() { + if (is_simple) { + simple_map& sm = stack::get>(L, upvalue_index(simple_metatable_index)); + function_map& functions = sm.functions; + optional maybeaccessor = stack::get>(L, 2); + if (!maybeaccessor) { + return; + } + std::string& accessor = maybeaccessor.value(); + auto preexistingit = functions.find(accessor); + if (preexistingit == functions.cend()) { + functions.emplace_hint(preexistingit, std::move(accessor), sol::object(L, 3)); + } + else { + preexistingit->second = sol::object(L, 3); + } + return; + } + usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + bool mustindex = umc.mustindex; + if (!mustindex) + return; + optional maybeaccessor = stack::get>(L, 2); + if (!maybeaccessor) { + return; + } + std::string& accessor = maybeaccessor.value(); + mapping_t& mapping = umc.mapping; + std::vector& runtime = umc.runtime; + int target = static_cast(runtime.size()); + auto preexistingit = mapping.find(accessor); + if (preexistingit == mapping.cend()) { + runtime.emplace_back(L, 3); + mapping.emplace_hint(mapping.cend(), accessor, call_information(&runtime_object_call, &runtime_new_index, target)); + } + else { + target = preexistingit->second.runtime_target; + runtime[target] = sol::object(L, 3); + preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); + } + }; + non_indexable(); + for (std::size_t i = 0; i < 4; lua_settop(L, 3), ++i) { + const char* metakey = nullptr; + switch (i) { + case 0: + metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); + break; + case 1: + metakey = &usertype_traits>::metatable()[0]; + luaL_getmetatable(L, metakey); + break; + case 2: + metakey = &usertype_traits::metatable()[0]; + luaL_getmetatable(L, metakey); + break; + case 3: + default: + metakey = &usertype_traits::user_metatable()[0]; + { + luaL_getmetatable(L, metakey); + lua_getmetatable(L, -1); + } + break; + } + int tableindex = lua_gettop(L); + if (type_of(L, tableindex) == type::lua_nil) { + continue; + } + stack::set_field(L, stack_reference(L, raw_index(2)), stack_reference(L, raw_index(3)), tableindex); + } + lua_settop(L, 0); + return 0; + } + return indexing_fail(L); + } + + inline int runtime_new_index(lua_State* L, void*, int runtimetarget) { + usertype_metatable_core& umc = stack::get>(L, upvalue_index(metatable_core_index)); + std::vector& runtime = umc.runtime; + object& runtimeobj = runtime[runtimetarget]; + runtimeobj = object(L, 3); + return 0; } template @@ -10230,41 +11142,6 @@ namespace sol { inline void make_reg_op(Regs&, int&, const char*) { // Do nothing if there's no support } - - struct add_destructor_tag {}; - struct check_destructor_tag {}; - struct verified_tag {} const verified{}; - - template - struct is_non_factory_constructor : std::false_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template - struct is_non_factory_constructor> : std::true_type {}; - - template <> - struct is_non_factory_constructor : std::true_type {}; - - template - struct is_constructor : is_non_factory_constructor {}; - - template - struct is_constructor> : std::true_type {}; - - template - using has_constructor = meta::any>...>; - - template - struct is_destructor : std::false_type {}; - - template - struct is_destructor> : std::true_type {}; - - template - using has_destructor = meta::any>...>; - } // usertype_detail template @@ -10279,7 +11156,7 @@ namespace sol { struct usertype_metatable : usertype_detail::registrar {}; template - struct usertype_metatable, Tn...> : usertype_detail::registrar { + struct usertype_metatable, Tn...> : usertype_metatable_core, usertype_detail::registrar { typedef std::make_index_sequence indices; typedef std::index_sequence half_indices; typedef std::array regs_t; @@ -10287,11 +11164,7 @@ namespace sol { typedef std::tuple ...> Tuple; template struct check_binding : is_variable_binding> {}; - typedef std::unordered_map mapping_t; Tuple functions; - mapping_t mapping; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; lua_CFunction destructfunc; lua_CFunction callconstructfunc; lua_CFunction indexbase; @@ -10300,20 +11173,20 @@ namespace sol { usertype_detail::base_walk newindexbaseclasspropogation; void* baseclasscheck; void* baseclasscast; - bool mustindex; bool secondarymeta; bool hasequals; bool hasless; bool haslessequals; template >> = meta::enabler> - inline lua_CFunction make_func() { + lua_CFunction make_func() const { return std::get(functions); } template >> = meta::enabler> - inline lua_CFunction make_func() { - return call; + lua_CFunction make_func() const { + const auto& name = std::get(functions); + return (usertype_detail::make_shim(name) == "__newindex") ? &call : &call; } static bool contains_variable() { @@ -10323,25 +11196,25 @@ namespace sol { bool contains_index() const { bool idx = false; - (void)detail::swallow{ 0, ((idx |= usertype_detail::is_indexer(std::get(functions))), 0) ... }; + (void)detail::swallow{ 0, ((idx |= (usertype_detail::is_indexer(std::get(functions)) != 0)), 0) ... }; return idx; } int finish_regs(regs_t& l, int& index) { if (!hasless) { - const char* name = name_of(meta_function::less_than).c_str(); + const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::make_reg_op, meta::supports_op_less>(l, index, name); } if (!haslessequals) { - const char* name = name_of(meta_function::less_than_or_equal_to).c_str(); + const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); usertype_detail::make_reg_op, meta::supports_op_less_equal>(l, index, name); } if (!hasequals) { - const char* name = name_of(meta_function::equal_to).c_str(); + const char* name = to_string(meta_function::equal_to).c_str(); usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name); } if (destructfunc != nullptr) { - l[index] = { name_of(meta_function::garbage_collect).c_str(), destructfunc }; + l[index] = { to_string(meta_function::garbage_collect).c_str(), destructfunc }; ++index; } return index; @@ -10355,6 +11228,7 @@ namespace sol { template void make_regs(regs_t&, int&, base_classes_tag, bases) { + static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); if (sizeof...(Bases) < 1) { return; } @@ -10378,25 +11252,25 @@ namespace sol { // Returnable scope // That would be a neat keyword for C++ // returnable { ... }; - if (reg.name == name_of(meta_function::equal_to)) { + if (reg.name == to_string(meta_function::equal_to)) { hasequals = true; } - if (reg.name == name_of(meta_function::less_than)) { + if (reg.name == to_string(meta_function::less_than)) { hasless = true; } - if (reg.name == name_of(meta_function::less_than_or_equal_to)) { + if (reg.name == to_string(meta_function::less_than_or_equal_to)) { haslessequals = true; } - if (reg.name == name_of(meta_function::garbage_collect)) { + if (reg.name == to_string(meta_function::garbage_collect)) { destructfunc = reg.func; return; } - else if (reg.name == name_of(meta_function::index)) { + else if (reg.name == to_string(meta_function::index)) { indexfunc = reg.func; mustindex = true; return; } - else if (reg.name == name_of(meta_function::new_index)) { + else if (reg.name == to_string(meta_function::new_index)) { newindexfunc = reg.func; mustindex = true; return; @@ -10406,37 +11280,58 @@ namespace sol { } template > - usertype_metatable(Args&&... args) : functions(std::forward(args)...), - mapping(), - indexfunc(usertype_detail::indexing_fail), newindexfunc(usertype_detail::indexing_fail), + usertype_metatable(Args&&... args) : usertype_metatable_core(&usertype_detail::indexing_fail, &usertype_detail::metatable_newindex), usertype_detail::registrar(), + functions(std::forward(args)...), destructfunc(nullptr), callconstructfunc(nullptr), indexbase(&core_indexing_call), newindexbase(&core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), - mustindex(contains_variable() || contains_index()), secondarymeta(contains_variable()), + secondarymeta(contains_variable()), hasequals(false), hasless(false), haslessequals(false) { - std::initializer_list ilist{ { - std::pair( - usertype_detail::make_string(std::get(functions)), - usertype_detail::find_call_pair(&usertype_metatable::real_find_call, - &usertype_metatable::real_find_call) + std::initializer_list ilist{ { + std::pair( usertype_detail::make_string(std::get(functions)), + usertype_detail::call_information(&usertype_metatable::real_find_call, + &usertype_metatable::real_find_call) ) }... }; - mapping.insert(ilist); + this->mapping.insert(ilist); + for (const auto& n : meta_function_names()) { + this->mapping.erase(n); + } + this->mustindex = contains_variable() || contains_index(); } + usertype_metatable(const usertype_metatable&) = default; + usertype_metatable(usertype_metatable&&) = default; + usertype_metatable& operator=(const usertype_metatable&) = default; + usertype_metatable& operator=(usertype_metatable&&) = default; + template - static int real_find_call(lua_State* L, void* um) { + static int real_find_call(lua_State* L, void* um, int) { auto& f = *static_cast(um); if (is_variable_binding(f.functions))>::value) { return real_call_with(L, f); } - return stack::push(L, c_closure(call, stack::push(L, light(f)))); + // set up upvalues + // for a chained call + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, light(f)); + auto cfunc = &call; + return stack::push(L, c_closure(cfunc, upvalues)); + } + + template + static int real_meta_call(lua_State* L, void* um, int) { + auto& f = *static_cast(um); + return is_index ? f.indexfunc(L) : f.newindexfunc(L); } template static int core_indexing_call(lua_State* L) { - usertype_metatable& f = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); + usertype_metatable& f = toplevel + ? stack::get>(L, upvalue_index(usertype_detail::metatable_index)) + : stack::pop>(L); static const int keyidx = -2 + static_cast(is_index); if (toplevel && stack::get(L, keyidx) != type::string) { return is_index ? f.indexfunc(L) : f.newindexfunc(L); @@ -10444,8 +11339,9 @@ namespace sol { std::string name = stack::get(L, keyidx); auto memberit = f.mapping.find(name); if (memberit != f.mapping.cend()) { - auto& member = is_index ? memberit->second.second : memberit->second.first; - return (member)(L, static_cast(&f)); + const usertype_detail::call_information& ci = memberit->second; + const usertype_detail::member_search& member = is_index ? ci.index: ci.new_index; + return (member)(L, static_cast(&f), ci.runtime_target); } string_detail::string_shim accessor = name; int ret = 0; @@ -10471,7 +11367,7 @@ namespace sol { template static int real_call(lua_State* L) { - usertype_metatable& f = stack::get>(L, upvalue_index(1)); + usertype_metatable& f = stack::get>(L, upvalue_index(usertype_detail::metatable_index)); return real_call_with(L, f); } @@ -10551,6 +11447,7 @@ namespace sol { static int push(lua_State* L, umt_t&& umx) { umt_t& um = make_cleanup(L, std::move(umx)); + usertype_metatable_core& umc = um; regs_t value_table{ {} }; int lastreg = 0; (void)detail::swallow{ 0, (um.template make_regs<(I * 2)>(value_table, lastreg, std::get<(I * 2)>(um.functions), std::get<(I * 2 + 1)>(um.functions)), 0)... }; @@ -10558,14 +11455,14 @@ namespace sol { value_table[lastreg] = { nullptr, nullptr }; regs_t ref_table = value_table; regs_t unique_table = value_table; - bool hasdestructor = !value_table.empty() && name_of(meta_function::garbage_collect) == value_table[lastreg - 1].name; + bool hasdestructor = !value_table.empty() && to_string(meta_function::garbage_collect) == value_table[lastreg - 1].name; if (hasdestructor) { ref_table[lastreg - 1] = { nullptr, nullptr }; unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct }; } // Now use um - const bool& mustindex = um.mustindex; + const bool& mustindex = umc.mustindex; for (std::size_t i = 0; i < 3; ++i) { // Pointer types, AKA "references" from C++ const char* metakey = nullptr; @@ -10587,8 +11484,10 @@ namespace sol { } luaL_newmetatable(L, metakey); stack_reference t(L, -1); - stack::push(L, make_light(um)); - luaL_setfuncs(L, metaregs, 1); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, make_light(um)); + luaL_setfuncs(L, metaregs, upvalues); if (um.baseclasscheck != nullptr) { stack::set_field(L, detail::base_class_check_key(), um.baseclasscheck, t.stack_index()); @@ -10597,14 +11496,14 @@ namespace sol { stack::set_field(L, detail::base_class_cast_key(), um.baseclasscast, t.stack_index()); } - stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, make_light(um)), t.stack_index()); - stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, make_light(um)), t.stack_index()); + stack::set_field(L, detail::base_class_index_propogation_key(), make_closure(um.indexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); + stack::set_field(L, detail::base_class_new_index_propogation_key(), make_closure(um.newindexbase, nullptr, make_light(um), make_light(umc)), t.stack_index()); if (mustindex) { // Basic index pushing: specialize // index and newindex to give variables and stuff - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), t.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), t.stack_index()); + stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); + stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), t.stack_index()); } else { // If there's only functions, we can use the fast index version @@ -10615,11 +11514,11 @@ namespace sol { lua_createtable(L, 0, 3); stack_reference metabehind(L, -1); if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); } if (um.secondarymeta) { - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index()); + stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); + stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); } stack::set_field(L, metatable_key, metabehind, t.stack_index()); metabehind.pop(); @@ -10631,18 +11530,20 @@ namespace sol { // Now for the shim-table that actually gets assigned to the name luaL_newmetatable(L, &usertype_traits::user_metatable()[0]); stack_reference t(L, -1); - stack::push(L, make_light(um)); - luaL_setfuncs(L, value_table.data(), 1); + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, make_light(um)); + luaL_setfuncs(L, value_table.data(), upvalues); { lua_createtable(L, 0, 3); stack_reference metabehind(L, -1); if (um.callconstructfunc != nullptr) { - stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, make_light(um)), metabehind.stack_index()); - } - if (um.secondarymeta) { - stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, make_light(um)), metabehind.stack_index()); - stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, make_light(um)), metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, make_closure(um.callconstructfunc, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); } + + stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); + stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); + stack::set_field(L, metatable_key, metabehind, t.stack_index()); metabehind.pop(); } @@ -10662,90 +11563,38 @@ namespace sol { namespace sol { namespace usertype_detail { - const lua_Integer toplevel_magic = static_cast(0x00000001); - - struct variable_wrapper { - virtual int index(lua_State* L) = 0; - virtual int new_index(lua_State* L) = 0; - virtual ~variable_wrapper() {}; - }; - - template - struct callable_binding : variable_wrapper { - F fx; - - template - callable_binding(Arg&& arg) : fx(std::forward(arg)) {} - - virtual int index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); + inline int call_indexing_object(lua_State* L, object& f) { + int before = lua_gettop(L); + f.push(); + for (int i = 1; i <= before; ++i) { + lua_pushvalue(L, i); } - - virtual int new_index(lua_State* L) override { - return call_detail::call_wrapped(L, fx); - } - }; - - typedef std::unordered_map> variable_map; - typedef std::unordered_map function_map; - - struct simple_map { - const char* metakey; - variable_map variables; - function_map functions; - base_walk indexbaseclasspropogation; - base_walk newindexbaseclasspropogation; - - simple_map(const char* mkey, base_walk index, base_walk newindex, variable_map&& vars, function_map&& funcs) : metakey(mkey), variables(std::move(vars)), functions(std::move(funcs)), indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {} - }; - - template - inline int simple_metatable_newindex(lua_State* L) { - int isnum = 0; - lua_Integer magic = lua_tointegerx(L, lua_upvalueindex(4), &isnum); - if (isnum != 0 && magic == toplevel_magic) { - for (std::size_t i = 0; i < 3; lua_pop(L, 1), ++i) { - // Pointer types, AKA "references" from C++ - const char* metakey = nullptr; - switch (i) { - case 0: - metakey = &usertype_traits::metatable()[0]; - break; - case 1: - metakey = &usertype_traits>::metatable()[0]; - break; - case 2: - default: - metakey = &usertype_traits::metatable()[0]; - break; - } - luaL_getmetatable(L, metakey); - int tableindex = lua_gettop(L); - if (type_of(L, tableindex) == type::lua_nil) { - continue; - } - stack::set_field(L, stack_reference(L, 2), stack_reference(L, 3), tableindex); - } - lua_settop(L, 0); - return 0; - } - return indexing_fail(L); + lua_callk(L, before, LUA_MULTRET, 0, nullptr); + int after = lua_gettop(L); + return after - before; } - inline int simple_indexing_fail(lua_State* L) { - return stack::push(L, sol::lua_nil); - } - - template + template inline int simple_core_indexing_call(lua_State* L) { - simple_map& sm = toplevel ? stack::get>(L, upvalue_index(1)) : stack::pop>(L); + simple_map& sm = toplevel + ? stack::get>(L, upvalue_index(simple_metatable_index)) + : stack::pop>(L); variable_map& variables = sm.variables; function_map& functions = sm.functions; static const int keyidx = -2 + static_cast(is_index); if (toplevel) { if (stack::get(L, keyidx) != type::string) { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); + if (has_indexing) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } } } string_detail::string_shim accessor = stack::get(L, keyidx); @@ -10760,10 +11609,25 @@ namespace sol { } auto fit = functions.find(accessorkey); if (fit != functions.cend()) { - auto& func = (fit->second); - return stack::push(L, func); + sol::object& func = fit->second; + if (is_index) { + return stack::push(L, func); + } + else { + if (has_indexing && !is_toplevel(L)) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } + } } - // Check table storage first for a method that works + /* Check table storage first for a method that works luaL_getmetatable(L, sm.metakey); if (type_of(L, -1) != type::lua_nil) { stack::get_field(L, accessor.c_str(), lua_gettop(L)); @@ -10775,7 +11639,8 @@ namespace sol { lua_pop(L, 1); } lua_pop(L, 1); - + */ + int ret = 0; bool found = false; // Otherwise, we need to do propagating calls through the bases @@ -10789,26 +11654,47 @@ namespace sol { return ret; } if (toplevel) { - lua_CFunction indexingfunc = is_index ? stack::get(L, upvalue_index(2)) : stack::get(L, upvalue_index(3)); - return indexingfunc(L); + if (has_indexing && !is_toplevel(L)) { + object& indexingfunc = is_index + ? sm.index + : sm.newindex; + return call_indexing_object(L, indexingfunc); + } + else { + return is_index + ? indexing_fail(L) + : metatable_newindex(L); + } } return -1; } + template inline int simple_real_index_call(lua_State* L) { - return simple_core_indexing_call(L); + return simple_core_indexing_call(L); } + template inline int simple_real_new_index_call(lua_State* L) { - return simple_core_indexing_call(L); + return simple_core_indexing_call(L); } + template inline int simple_index_call(lua_State* L) { - return detail::static_trampoline<(&simple_real_index_call)>(L); +#if defined(__clang__) + return detail::trampoline(L, &simple_real_index_call); +#else + return detail::static_trampoline<(&simple_real_index_call)>(L); +#endif } + template inline int simple_new_index_call(lua_State* L) { - return detail::static_trampoline<(&simple_real_new_index_call)>(L); +#if defined(__clang__) + return detail::trampoline(L, &simple_real_new_index_call); +#else + return detail::static_trampoline<(&simple_real_new_index_call)>(L); +#endif } } @@ -10820,8 +11706,8 @@ namespace sol { usertype_detail::function_map registrations; usertype_detail::variable_map varmap; object callconstructfunc; - lua_CFunction indexfunc; - lua_CFunction newindexfunc; + object indexfunc; + object newindexfunc; lua_CFunction indexbase; lua_CFunction newindexbase; usertype_detail::base_walk indexbaseclasspropogation; @@ -10834,6 +11720,15 @@ namespace sol { template void insert(N&& n, object&& o) { std::string key = usertype_detail::make_string(std::forward(n)); + int is_indexer = static_cast(usertype_detail::is_indexer(n)); + if (is_indexer == 1) { + indexfunc = o; + mustindex = true; + } + else if (is_indexer == 2) { + newindexfunc = o; + mustindex = true; + } auto hint = registrations.find(key); if (hint == registrations.cend()) { registrations.emplace_hint(hint, std::move(key), std::move(o)); @@ -10941,6 +11836,7 @@ namespace sol { template void add(lua_State*, base_classes_tag, bases) { static_assert(sizeof(usertype_detail::base_walk) <= sizeof(void*), "size of function pointer is greater than sizeof(void*); cannot work on this platform. Please file a bug report."); + static_assert(!meta::any_same::value, "base classes cannot list the original class as part of the bases"); if (sizeof...(Bases) < 1) { return; } @@ -10959,8 +11855,8 @@ namespace sol { template simple_usertype_metatable(usertype_detail::verified_tag, std::index_sequence, lua_State* L, Tuple&& args) : callconstructfunc(lua_nil), - indexfunc(&usertype_detail::simple_indexing_fail), newindexfunc(&usertype_detail::simple_metatable_newindex), - indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), + indexfunc(lua_nil), newindexfunc(lua_nil), + indexbase(&usertype_detail::simple_core_indexing_call), newindexbase(&usertype_detail::simple_core_indexing_call), indexbaseclasspropogation(usertype_detail::walk_all_bases), newindexbaseclasspropogation(&usertype_detail::walk_all_bases), baseclasscheck(nullptr), baseclasscast(nullptr), mustindex(false), secondarymeta(false) { @@ -10998,6 +11894,11 @@ namespace sol { template simple_usertype_metatable(lua_State* L, constructor_wrapper constructorlist, Args&&... args) : simple_usertype_metatable(L, usertype_detail::check_destructor_tag(), std::forward(args)..., "new", constructorlist) {} + simple_usertype_metatable(const simple_usertype_metatable&) = default; + simple_usertype_metatable(simple_usertype_metatable&&) = default; + simple_usertype_metatable& operator=(const simple_usertype_metatable&) = default; + simple_usertype_metatable& operator=(simple_usertype_metatable&&) = default; + virtual int push_um(lua_State* L) override { return stack::push(L, std::move(*this)); } @@ -11024,6 +11925,7 @@ namespace sol { const char* gcmetakey = &usertype_traits::gc_table()[0]; stack::push>(L, metatable_key, uniquegcmetakey, &usertype_traits::metatable()[0], umx.indexbaseclasspropogation, umx.newindexbaseclasspropogation, + std::move(umx.indexfunc), std::move(umx.newindexfunc), std::move(umx.varmap), std::move(umx.registrations) ); stack_reference stackvarmap(L, -1); @@ -11036,34 +11938,38 @@ namespace sol { } static int push(lua_State* L, umt_t&& umx) { + bool hasindex = umx.indexfunc.valid(); + bool hasnewindex = umx.newindexfunc.valid(); auto& varmap = make_cleanup(L, umx); + auto sic = hasindex ? &usertype_detail::simple_index_call : &usertype_detail::simple_index_call; + auto snic = hasnewindex ? &usertype_detail::simple_new_index_call : &usertype_detail::simple_new_index_call; bool hasequals = false; bool hasless = false; bool haslessequals = false; auto register_kvp = [&](std::size_t i, stack_reference& t, const std::string& first, object& second) { - if (first == name_of(meta_function::equal_to)) { + if (first == to_string(meta_function::equal_to)) { hasequals = true; } - else if (first == name_of(meta_function::less_than)) { + else if (first == to_string(meta_function::less_than)) { hasless = true; } - else if (first == name_of(meta_function::less_than_or_equal_to)) { + else if (first == to_string(meta_function::less_than_or_equal_to)) { haslessequals = true; } - else if (first == name_of(meta_function::index)) { - umx.indexfunc = second.template as(); + else if (first == to_string(meta_function::index)) { + umx.indexfunc = second; } - else if (first == name_of(meta_function::new_index)) { - umx.newindexfunc = second.template as(); + else if (first == to_string(meta_function::new_index)) { + umx.newindexfunc = second; } switch (i) { case 0: - if (first == name_of(meta_function::garbage_collect)) { + if (first == to_string(meta_function::garbage_collect)) { return; } break; case 1: - if (first == name_of(meta_function::garbage_collect)) { + if (first == to_string(meta_function::garbage_collect)) { stack::set_field(L, first, detail::unique_destruct, t.stack_index()); return; } @@ -11075,7 +11981,6 @@ namespace sol { stack::set_field(L, first, second, t.stack_index()); }; for (std::size_t i = 0; i < 3; ++i) { - // Pointer types, AKA "references" from C++ const char* metakey = nullptr; switch (i) { case 0: @@ -11099,15 +12004,15 @@ namespace sol { luaL_Reg opregs[4]{}; int opregsindex = 0; if (!hasless) { - const char* name = name_of(meta_function::less_than).c_str(); + const char* name = to_string(meta_function::less_than).c_str(); usertype_detail::make_reg_op, meta::supports_op_less>(opregs, opregsindex, name); } if (!haslessequals) { - const char* name = name_of(meta_function::less_than_or_equal_to).c_str(); + const char* name = to_string(meta_function::less_than_or_equal_to).c_str(); usertype_detail::make_reg_op, meta::supports_op_less_equal>(opregs, opregsindex, name); } if (!hasequals) { - const char* name = name_of(meta_function::equal_to).c_str(); + const char* name = to_string(meta_function::equal_to).c_str(); usertype_detail::make_reg_op::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name); } t.push(); @@ -11128,16 +12033,14 @@ namespace sol { if (umx.mustindex) { // use indexing function stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(sic, + nullptr, + make_light(varmap) ), t.stack_index()); stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(snic, + nullptr, + make_light(varmap) ), t.stack_index()); } else { @@ -11153,16 +12056,14 @@ namespace sol { } if (umx.secondarymeta) { stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(sic, + nullptr, + make_light(varmap) ), metabehind.stack_index()); stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, - make_light(varmap), - umx.indexfunc, - umx.newindexfunc + make_closure(snic, + nullptr, + make_light(varmap) ), metabehind.stack_index()); } stack::set_field(L, metatable_key, metabehind, t.stack_index()); @@ -11187,17 +12088,19 @@ namespace sol { } // use indexing function stack::set_field(L, meta_function::index, - make_closure(&usertype_detail::simple_index_call, + make_closure(sic, + nullptr, make_light(varmap), - umx.indexfunc, - umx.newindexfunc, + nullptr, + nullptr, usertype_detail::toplevel_magic ), metabehind.stack_index()); stack::set_field(L, meta_function::new_index, - make_closure(&usertype_detail::simple_new_index_call, + make_closure(snic, + nullptr, make_light(varmap), - umx.indexfunc, - umx.newindexfunc, + nullptr, + nullptr, usertype_detail::toplevel_magic ), metabehind.stack_index()); stack::set_field(L, metatable_key, metabehind, t.stack_index()); @@ -11226,7 +12129,7 @@ namespace sol { typedef std::array one; typedef std::array two; - template static one test(decltype(&C::find)); + template static one test(decltype(std::declval().find(std::declval>()))*); template static two test(...); public: @@ -11307,6 +12210,14 @@ namespace sol { typedef typename KV::first_type K; typedef typename KV::second_type V; typedef std::remove_reference_t())> IR; + typedef typename meta::iterator_tag::type tag_t; + typedef std::conditional_t::value, + V, + std::conditional_t()) + > + > push_type; struct iter { T& source; @@ -11324,7 +12235,7 @@ namespace sol { return *p.value(); #else return stack::get(L, 1); -#endif +#endif // Safe getting with error } static int real_index_call_associative(std::true_type, lua_State* L) { @@ -11335,7 +12246,7 @@ namespace sol { auto it = detail::find(src, *k); if (it != end(src)) { auto& v = *it; - return stack::push_reference(L, v.second); + return stack::stack_detail::push_reference(L, v.second); } } else { @@ -11351,6 +12262,9 @@ namespace sol { else if (name == "clear") { return stack::push(L, &clear_call); } + else if (name == "find") { + return stack::push(L, &find_call); + } } } return stack::push(L, lua_nil); @@ -11363,15 +12277,12 @@ namespace sol { using std::begin; auto it = begin(src); K k = *maybek; -#ifdef SOL_SAFE_USERTYPE if (k > src.size() || k < 1) { return stack::push(L, lua_nil); } -#else -#endif // Safety --k; std::advance(it, k); - return stack::push_reference(L, *it); + return stack::stack_detail::push_reference(L, *it); } else { auto maybename = stack::check_get(L, 2); @@ -11386,6 +12297,9 @@ namespace sol { else if (name == "clear") { return stack::push(L, &clear_call); } + else if (name == "find") { + return stack::push(L, &find_call); + } } } @@ -11406,46 +12320,62 @@ namespace sol { static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) { auto& src = get_src(L); - auto k = stack::check_get(L, 2); - if (k) { - using std::end; - auto it = detail::find(src, *k); - if (it != end(src)) { - auto& v = *it; - v.second = stack::get(L, 3); - } - else { - src.insert(it, { std::move(*k), stack::get(L, 3) }); - } +#ifdef SOL_CHECK_ARGUMENTS + auto maybek = stack::check_get(L, 2); + if (!maybek) { + return luaL_error(L, "sol: improper key of type %s to a %s", lua_typename(L, static_cast(type_of(L, 2))), detail::demangle().c_str()); + } + K& k = *maybek; +#else + K k = stack::get(L, 2); +#endif + using std::end; + auto it = detail::find(src, k); + if (it != end(src)) { + auto& v = *it; + v.second = stack::get(L, 3); + } + else { + src.insert(it, { std::move(k), stack::get(L, 3) }); } return 0; } static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) { auto& src = get_src(L); -#ifdef SOL_SAFE_USERTYPE +#ifdef SOL_CHECK_ARGUMENTS auto maybek = stack::check_get(L, 2); if (!maybek) { - return stack::push(L, lua_nil); + return luaL_error(L, "sol: improper index of type %s to a %s", lua_typename(L, static_cast(type_of(L, 2))), detail::demangle().c_str()); } - K k = *maybek; + K& k = *maybek; #else K k = stack::get(L, 2); #endif using std::begin; auto it = begin(src); +#ifdef SOL_CHECK_ARGUMENTS + if (k < 1) { + return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle().c_str()); + } +#endif + --k; if (k == src.size()) { - real_add_call_push(std::integral_constant::value>(), L, src, 1); + real_add_call_push(std::integral_constant::value && std::is_copy_constructible::value>(), L, src, 1); return 0; } - --k; +#ifdef SOL_CHECK_ARGUMENTS + if (k > src.size()) { + return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle().c_str()); + } +#endif std::advance(it, k); *it = stack::get(L, 3); return 0; } static int real_new_index_call(lua_State* L) { - return real_new_index_call_const(meta::neg, std::is_const>>(), is_associative(), L); + return real_new_index_call_const(meta::neg, std::is_const, meta::neg>>>(), is_associative(), L); } static int real_pairs_next_call_assoc(std::true_type, lua_State* L) { @@ -11456,7 +12386,9 @@ namespace sol { if (it == end(source)) { return 0; } - int p = stack::multi_push_reference(L, it->first, it->second); + int p; + p = stack::push_reference(L, it->first); + p += stack::stack_detail::push_reference(L, it->second); std::advance(it, 1); return p; } @@ -11479,7 +12411,9 @@ namespace sol { if (it == end(source)) { return 0; } - int p = stack::multi_push_reference(L, k + 1, *it); + int p; + p = stack::push_reference(L, k + 1); + p += stack::stack_detail::push_reference(L, *it); std::advance(it, 1); return p; } @@ -11523,7 +12457,7 @@ namespace sol { } static int real_add_call_push(std::false_type, lua_State*L, T& src, int boost = 0) { - return real_add_call_insert(std::integral_constant::value>(), L, src, boost); + return real_add_call_insert(std::integral_constant::value && std::is_copy_constructible::value>(), L, src, boost); } static int real_add_call_associative(std::true_type, lua_State* L) { @@ -11532,7 +12466,7 @@ namespace sol { static int real_add_call_associative(std::false_type, lua_State* L) { auto& src = get_src(L); - return real_add_call_push(std::integral_constant::value>(), L, src); + return real_add_call_push(std::integral_constant::value && std::is_copy_constructible::value>(), L, src); } static int real_add_call_capable(std::true_type, lua_State* L) { @@ -11545,7 +12479,7 @@ namespace sol { } static int real_add_call(lua_State* L) { - return real_add_call_capable(std::integral_constant::value || detail::has_insert::value>(), L); + return real_add_call_capable(std::integral_constant::value || detail::has_insert::value) && std::is_copy_constructible::value>(), L); } static int real_insert_call_capable(std::false_type, std::false_type, lua_State*L) { @@ -11569,7 +12503,7 @@ namespace sol { } static int real_insert_call(lua_State*L) { - return real_insert_call_capable(std::integral_constant::value>(), is_associative(), L); + return real_insert_call_capable(std::integral_constant::value && std::is_copy_assignable::value>(), is_associative(), L); } static int real_clear_call_capable(std::false_type, lua_State* L) { @@ -11587,6 +12521,36 @@ namespace sol { return real_clear_call_capable(std::integral_constant::value>(), L); } + static int real_find_call_capable(std::false_type, std::false_type, lua_State*L) { + static const std::string& s = detail::demangle(); + return luaL_error(L, "sol: cannot call find on type %s", s.c_str()); + } + + static int real_find_call_capable(std::false_type, std::true_type, lua_State*L) { + return real_index_call(L); + } + + static int real_find_call_capable(std::true_type, std::false_type, lua_State* L) { + auto k = stack::check_get(L, 2); + if (k) { + auto& src = get_src(L); + auto it = src.find(*k); + if (it != src.end()) { + auto& v = *it; + return stack::stack_detail::push_reference(L, v); + } + } + return stack::push(L, lua_nil); + } + + static int real_find_call_capable(std::true_type, std::true_type, lua_State* L) { + return real_index_call(L); + } + + static int real_find_call(lua_State*L) { + return real_find_call_capable(std::integral_constant::value>(), is_associative(), L); + } + static int add_call(lua_State*L) { return detail::static_trampoline<(&real_add_call)>(L); } @@ -11599,6 +12563,10 @@ namespace sol { return detail::static_trampoline<(&real_clear_call)>(L); } + static int find_call(lua_State*L) { + return detail::static_trampoline<(&real_find_call)>(L); + } + static int length_call(lua_State*L) { return detail::static_trampoline<(&real_length_call)>(L); } @@ -11625,7 +12593,7 @@ namespace sol { template inline auto container_metatable() { typedef container_usertype_metatable> meta_cumt; - std::array reg = { { + std::array reg = { { { "__index", &meta_cumt::index_call }, { "__newindex", &meta_cumt::new_index_call }, { "__pairs", &meta_cumt::pairs_call }, @@ -11634,6 +12602,7 @@ namespace sol { { "clear", &meta_cumt::clear_call }, { "insert", &meta_cumt::insert_call }, { "add", &meta_cumt::add_call }, + { "find", &meta_cumt::find_call }, std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy }, { nullptr, nullptr } } }; @@ -11739,7 +12708,9 @@ namespace sol { } int push(lua_State* L) { - return metatableregister->push_um(L); + int r = metatableregister->push_um(L); + metatableregister = nullptr; + return r; } }; @@ -11878,8 +12849,11 @@ namespace sol { } } - template - class basic_table_core : public base_t { + const new_table create = new_table{}; + + template + class basic_table_core : public basic_object_base { + typedef basic_object_base base_t; friend class state; friend class state_view; @@ -11916,15 +12890,15 @@ namespace sol { -> decltype(stack::pop>(nullptr)) { typedef decltype(stack::pop>(nullptr)) Tup; return Tup( - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<0>(keys)), - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get<1>(keys)), - traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys))... + traverse_get_optional(meta::is_optional>(), detail::forward_get<0>(keys)), + traverse_get_optional(meta::is_optional>(), detail::forward_get<1>(keys)), + traverse_get_optional(meta::is_optional>(), detail::forward_get(keys))... ); } template decltype(auto) tuple_get(types, std::index_sequence, Keys&& keys) const { - return traverse_get_optional(meta::is_specialization_of>(), detail::forward_get(keys)); + return traverse_get_optional(meta::is_optional>(), detail::forward_get(keys)); } template @@ -11992,41 +12966,52 @@ namespace sol { traverse_set_deep(std::forward(keys)...); } - basic_table_core(lua_State* L, detail::global_tag t) noexcept : reference(L, t) { } - + basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { } + + protected: + basic_table_core(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) {} + basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) {} + template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) {} + public: - typedef basic_table_iterator iterator; + typedef basic_table_iterator iterator; typedef iterator const_iterator; - basic_table_core() noexcept : base_t() { } - template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> - basic_table_core(T&& r) noexcept : base_t(std::forward(r)) { -#ifdef SOL_CHECK_ARGUMENTS - if (!is_table>::value) { - auto pp = stack::push_pop(*this); - stack::check(base_t::lua_state(), -1, type_panic); - } -#endif // Safety - } + basic_table_core() noexcept = default; basic_table_core(const basic_table_core&) = default; basic_table_core(basic_table_core&&) = default; basic_table_core& operator=(const basic_table_core&) = default; basic_table_core& operator=(basic_table_core&&) = default; basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {} basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {} - template >>, meta::neg>> = meta::enabler> + template >>, meta::neg, ref_index>>> = meta::enabler> basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {} - basic_table_core(lua_State* L, int index = -1) : base_t(L, index) { + basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { + if (!std::is_base_of::value) { + lua_pop(L, 1); + } + } + basic_table_core(lua_State* L, int index = -1) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } - basic_table_core(lua_State* L, ref_index index) : base_t(L, index) { + basic_table_core(lua_State* L, ref_index index) : basic_table_core(detail::no_safety, L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); stack::check(L, -1, type_panic); #endif // Safety } + template , basic_table_core>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_table>::value) { + auto pp = stack::push_pop(*this); + stack::check(base_t::lua_state(), -1, type_panic); + } +#endif // Safety + } iterator begin() const { return iterator(*this); @@ -12054,7 +13039,7 @@ namespace sol { template decltype(auto) get_or(Key&& key, T&& otherwise) const { typedef decltype(get("")) U; - sol::optional option = get>(std::forward(key)); + optional option = get>(std::forward(key)); if (option) { return static_cast(option.value()); } @@ -12063,7 +13048,7 @@ namespace sol { template decltype(auto) get_or(Key&& key, D&& otherwise) const { - sol::optional option = get>(std::forward(key)); + optional option = get>(std::forward(key)); if (option) { return static_cast(option.value()); } @@ -12073,7 +13058,7 @@ namespace sol { template decltype(auto) traverse_get(Keys&&... keys) const { auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_specialization_of>(), std::forward(keys)...); + return traverse_get_optional(meta::is_optional>(), std::forward(keys)...); } template @@ -12316,10 +13301,185 @@ namespace sol { namespace sol { typedef table_core table; + + namespace stack { + template <> + struct getter { + static table get(lua_State* L, int index = -1) { + if (lua_getmetatable(L, index) == 0) { + return table(L, ref_index(LUA_REFNIL)); + } + return table(L, -1); + } + }; + } // stack } // sol // end of sol/table.hpp +// beginning of sol/environment.hpp + +namespace sol { + + template + struct basic_environment : basic_table { + private: + typedef basic_table base_t; + + public: + basic_environment() noexcept = default; + basic_environment(const basic_environment&) = default; + basic_environment(basic_environment&&) = default; + basic_environment& operator=(const basic_environment&) = default; + basic_environment& operator=(basic_environment&&) = default; + basic_environment(const stack_reference& r) : basic_environment(r.lua_state(), r.stack_index()) {} + basic_environment(stack_reference&& r) : basic_environment(r.lua_state(), r.stack_index()) {} + + basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) {} + basic_environment(lua_State* L, new_table t, const reference& fallback) : basic_environment(L, std::move(t)) { + sol::stack_table mt(L, sol::new_table(0, 1)); + mt.set(sol::meta_function::index, fallback); + this->set(metatable_key, mt); + mt.pop(); + } + + basic_environment(env_t, const stack_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(env_t, const reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(this->lua_state(), -1, type_panic); +#endif // Safety + lua_pop(this->lua_state(), 2); + } + basic_environment(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + stack::check(L, index, type_panic); +#endif // Safety + } + basic_environment(lua_State* L, ref_index index) : base_t(detail::no_safety, L, index) { +#ifdef SOL_CHECK_ARGUMENTS + auto pp = stack::push_pop(*this); + stack::check(L, -1, type_panic); +#endif // Safety + } + template , basic_environment>>, meta::neg>, std::is_base_of>> = meta::enabler> + basic_environment(T&& r) noexcept : base_t(detail::no_safety, std::forward(r)) { +#ifdef SOL_CHECK_ARGUMENTS + if (!is_environment>::value) { + auto pp = stack::push_pop(*this); + stack::check(base_t::lua_state(), -1, type_panic); + } +#endif // Safety + } + + template + void set_on(const T& target) const { + lua_State* L = target.lua_state(); + auto pp = stack::push_pop(target); +#if SOL_LUA_VERSION < 502 + // Use lua_setfenv + this->push(); + lua_setfenv(L, -2); +#else + // Use upvalues as explained in Lua 5.2 and beyond's manual + this->push(); + const char* name = lua_setupvalue(L, -2, 1); + if (name == nullptr) { + this->pop(); + } +#endif + } + }; + + template + void set_environment(const basic_environment& env, const T& target) { + env.set_on(target); + } + + template + basic_environment get_environment(const T& target) { + lua_State* L = target.lua_state(); + auto pp = stack::pop_n(L, stack::push_environment_of(target)); + return basic_environment(L, -1); + } + + struct this_environment { + optional env; + + this_environment() : env(nullopt) {} + this_environment(sol::environment e) : env(std::move(e)) {} + this_environment(const this_environment&) = default; + this_environment(this_environment&&) = default; + this_environment& operator=(const this_environment&) = default; + this_environment& operator=(this_environment&&) = default; + + explicit operator bool() const { + return static_cast(env); + } + + operator optional& () { + return env; + } + + operator const optional& () const { + return env; + } + + operator environment& () { + return env.value(); + } + + operator const environment& () const { + return env.value(); + } + }; + + namespace stack { + template <> + struct getter { + static environment get(lua_State* L, int index, record& tracking) { + tracking.use(1); + return get_environment(stack_reference(L, raw_index(index))); + } + }; + + template <> + struct getter { + static this_environment get(lua_State* L, int, record& tracking) { + tracking.use(0); + lua_Debug info; + // Level 0 means current function (this C function, which may or may not be useful for us?) + // Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call) + int pre_stack_size = lua_gettop(L); + if (lua_getstack(L, 1, &info) != 1) { + if (lua_getstack(L, 0, &info) != 1) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + } + if (lua_getinfo(L, "f", &info) == 0) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + + sol::stack_reference f(L, -1); + sol::environment env(sol::env_key, f); + if (!env.valid()) { + lua_settop(L, pre_stack_size); + return this_environment(); + } + return this_environment(std::move(env)); + } + }; + } // stack +} // sol + +// end of sol/environment.hpp + // beginning of sol/load_result.hpp namespace sol { @@ -12332,11 +13492,11 @@ namespace sol { load_status err; template - decltype(auto) tagged_get(types>) const { + decltype(auto) tagged_get(types>) const { if (!valid()) { - return sol::optional(nullopt); + return optional(nullopt); } - return stack::get>(L, index); + return stack::get>(L, index); } template @@ -12349,20 +13509,20 @@ namespace sol { return stack::get(L, index); } - sol::optional tagged_get(types>) const { + optional tagged_get(types>) const { if (valid()) { return nullopt; } - return sol::error(detail::direct_error, stack::get(L, index)); + return error(detail::direct_error, stack::get(L, index)); } - sol::error tagged_get(types) const { + error tagged_get(types) const { #ifdef SOL_CHECK_ARGUMENTS if (valid()) { type_panic(L, index, type_of(L, index), type::none); } #endif // Check Argument Safety - return sol::error(detail::direct_error, stack::get(L, index)); + return error(detail::direct_error, stack::get(L, index)); } public: @@ -12458,6 +13618,29 @@ namespace sol { return kb; } + inline protected_function_result simple_on_error(lua_State*, sol::protected_function_result result) { + return result; + } + + inline protected_function_result default_on_error( lua_State* L, protected_function_result pfr ) { + type t = type_of(L, pfr.stack_index()); + std::string err = to_string(pfr.status()) + " error"; + if (t == type::string) { + err += " "; + err += stack::get(L, pfr.stack_index()); + } +#ifdef SOL_NO_EXCEPTIONS + if (t != type::nil) { + lua_pop(L, 1); + } + stack::push(L, err); + lua_error(L); +#else + throw error(detail::direct_error, err); +#endif + return pfr; + } + class state_view { private: lua_State* L; @@ -12639,16 +13822,94 @@ namespace sol { return require_core(key, [this, &filename]() {stack::script_file(L, filename); }, create_global); } + template + protected_function_result do_string(const std::string& code, const basic_environment& env) { + load_status x = static_cast(luaL_loadstring(L, code.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); + set_environment(env, pf); + return pf(); + } + + template + protected_function_result do_file(const std::string& filename, const basic_environment& env) { + load_status x = static_cast(luaL_loadfile(L, filename.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); + set_environment(env, pf); + return pf(); + } + protected_function_result do_string(const std::string& code) { - sol::protected_function pf = load(code); + load_status x = static_cast(luaL_loadstring(L, code.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); return pf(); } protected_function_result do_file(const std::string& filename) { - sol::protected_function pf = load_file(filename); + load_status x = static_cast(luaL_loadfile(L, filename.c_str())); + if (x != load_status::ok) { + return protected_function_result(L, -1, 0, 1, static_cast(x)); + } + protected_function pf(L, -1); + pf.pop(); return pf(); } + protected_function_result script(const std::string& code, const environment& env) { + return script(code, env, sol::default_on_error); + } + + protected_function_result script_file(const std::string& filename, const environment& env) { + return script_file(filename, env, sol::default_on_error); + } + + template >> = meta::enabler> + protected_function_result script(const std::string& code, Fx&& on_error) { + protected_function_result pfr = do_string(code); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template >> = meta::enabler> + protected_function_result script_file(const std::string& filename, Fx&& on_error) { + protected_function_result pfr = do_file(filename); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template + protected_function_result script(const std::string& code, const basic_environment& env, Fx&& on_error) { + protected_function_result pfr = do_string(code, env); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + + template + protected_function_result script_file(const std::string& filename, const basic_environment& env, Fx&& on_error) { + protected_function_result pfr = do_file(filename, env); + if (!pfr.valid()) { + return on_error(L, std::move(pfr)); + } + return pfr; + } + function_result script(const std::string& code) { int index = lua_gettop(L); stack::script(L, code); @@ -12905,9 +14166,10 @@ namespace sol { const char* message = lua_tostring(L, -1); if (message) { std::string err = message; - lua_pop(L, 1); + lua_settop(L, 0); throw error(err); } + lua_settop(L, 0); throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic")); #endif } @@ -13218,7 +14480,11 @@ namespace sol { #ifdef SOL_INSIDE_UNREAL #ifdef SOL_INSIDE_UNREAL_REMOVED_CHECK -#define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } }} +#if DO_CHECK +#define check(expr) { if(UNLIKELY(!(expr))) { FDebug::LogAssertFailedMessage( #expr, __FILE__, __LINE__ ); _DebugBreakAndPromptForRemote(); FDebug::AssertFailed( #expr, __FILE__, __LINE__ ); CA_ASSUME(false); } } +#else +#define check(expr) { CA_ASSUME(expr); } +#endif #endif #endif // Unreal Engine 4 Bullshit