diff --git a/CMakeLists.txt b/CMakeLists.txt index 854a3d5b5..e1eacd05d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,6 @@ if(ENABLE_MASON) set(MASON_STXXL_VERSION "1.4.1") set(MASON_EXPAT_VERSION "2.2.0") set(MASON_LUA_VERSION "5.2.4") - set(MASON_LUABIND_VERSION "e414c57bcb687bb3091b7c55bbff6947f052e46b") set(MASON_BZIP2_VERSION "1.0.6") set(MASON_TBB_VERSION "43_20150316") @@ -94,6 +93,7 @@ endif() include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include/) include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/) +include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/sol2/) include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/third_party/variant/include) add_custom_target(FingerPrintConfigure ALL ${CMAKE_COMMAND} @@ -403,10 +403,6 @@ if(ENABLE_MASON) add_dependency_includes(${MASON_PACKAGE_lua_INCLUDE_DIRS}) set(USED_LUA_LIBRARIES ${MASON_PACKAGE_lua_STATIC_LIBS}) - mason_use(luabind_lua524 VERSION ${MASON_LUABIND_VERSION}) - add_dependency_includes(${MASON_PACKAGE_luabind_lua524_INCLUDE_DIRS}) - set(LUABIND_LIBRARY ${MASON_PACKAGE_luabind_lua524_STATIC_LIBS}) - mason_use(bzip2 VERSION ${MASON_BZIP2_VERSION}) add_dependency_includes(${MASON_PACKAGE_bzip2_INCLUDE_DIRS}) set(BZIP2_LIBRARIES ${MASON_PACKAGE_bzip2_STATIC_LIBS}) @@ -455,10 +451,6 @@ else() if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug) set(TBB_LIBRARIES ${TBB_DEBUG_LIBRARIES}) endif() - find_package(Luabind REQUIRED) - add_dependency_includes(${LUABIND_INCLUDE_DIR}) - set(USED_LUA_LIBRARIES ${LUA_LIBRARY}) - add_dependency_includes(${LUA_INCLUDE_DIR}) find_package(EXPAT REQUIRED) add_dependency_includes(${EXPAT_INCLUDE_DIRS}) @@ -537,6 +529,7 @@ ELSE() ENDIF() set(USED_LUA_LIBRARIES ${LUA_LIBRARY}) +add_dependency_includes(${LUA_INCLUDE_DIR}) if(NOT WIN32 AND NOT Boost_USE_STATIC_LIBS) add_dependency_defines(-DBOOST_TEST_DYN_LINK) diff --git a/include/extractor/extraction_way.hpp b/include/extractor/extraction_way.hpp index 67a982146..c172dc33f 100644 --- a/include/extractor/extraction_way.hpp +++ b/include/extractor/extraction_way.hpp @@ -96,6 +96,7 @@ struct ExtractionWay bool roundabout; bool circular; bool is_startpoint; + bool ignore_in_grid; TravelMode forward_travel_mode : 4; TravelMode backward_travel_mode : 4; guidance::RoadClassification road_classification; diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index c55a2601f..7495867e6 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -239,7 +239,6 @@ function way_function (way, result) -- ferries (doesn't cover routes tagged using relations) result.forward_mode = mode.ferry result.backward_mode = mode.ferry - result.ignore_in_grid = true if duration and durationIsValid(duration) then result.duration = math.max( 1, parseDuration(duration) ) else diff --git a/profiles/foot.lua b/profiles/foot.lua index 0c348a312..91c2cab42 100644 --- a/profiles/foot.lua +++ b/profiles/foot.lua @@ -7,7 +7,6 @@ barrier_whitelist = { [""] = true, ["cycle_barrier"] = true, ["bollard"] = true, access_tag_whitelist = { ["yes"] = true, ["foot"] = true, ["permissive"] = true, ["designated"] = true } access_tag_blacklist = { ["no"] = true, ["private"] = true, ["agricultural"] = true, ["forestry"] = true, ["delivery"] = true } access_tags_hierarchy = { "foot", "access" } -ignore_in_grid = { ["ferry"] = true } restrictions = { "foot" } walking_speed = 5 diff --git a/src/extractor/scripting_environment_sol2.cpp b/src/extractor/scripting_environment_sol2.cpp index 3ed18224d..399ac7780 100644 --- a/src/extractor/scripting_environment_sol2.cpp +++ b/src/extractor/scripting_environment_sol2.cpp @@ -8,6 +8,7 @@ #include "extractor/profile_properties.hpp" #include "extractor/raster_source.hpp" #include "extractor/restriction_parser.hpp" +#include "util/coordinate.hpp" #include "util/exception.hpp" #include "util/lua_util.hpp" #include "util/simple_logger.hpp" @@ -20,11 +21,61 @@ #include #include +namespace sol +{ +template <> struct is_container : std::false_type +{ +}; +template <> struct is_container : std::false_type +{ +}; +} + namespace osrm { namespace extractor { +template +auto get_value_by_key(T const &object, const char *key) -> decltype(object.get_value_by_key(key)) +{ + auto v = object.get_value_by_key(key); + if (v && *v) + { // non-empty string? + return v; + } + else + { + return nullptr; + } +} + +template +const char* get_value_by_key(T const &object, const char *key, D const default_value) +{ + auto v = get_value_by_key(object, key); + if (v && *v) + { + return v; + } + else + { + return default_value; + } +} + +template double latToDouble(T const &object) +{ + return static_cast(util::toFloating(object.lat)); +} + +template double lonToDouble(T const &object) +{ + return static_cast(util::toFloating(object.lon)); +} + +auto get_nodes_for_way(const osmium::Way &way) -> decltype(way.nodes()) { return way.nodes(); } + Sol2ScriptingEnvironment::Sol2ScriptingEnvironment(const std::string &file_name) : file_name(file_name) { @@ -35,14 +86,222 @@ void Sol2ScriptingEnvironment::InitContext(Sol2ScriptingContext &context) { context.state.open_libraries(); - // TODO: register things here + context.state["durationIsValid"] = durationIsValid; + context.state["parseDuration"] = parseDuration; + context.state["trimLaneString"] = trimLaneString; + context.state["applyAccessTokens"] = applyAccessTokens; + context.state["canonicalizeStringList"] = canonicalizeStringList; + + context.state.new_enum("mode", + "inaccessible", + TRAVEL_MODE_INACCESSIBLE, + "driving", + TRAVEL_MODE_DRIVING, + "cycling", + TRAVEL_MODE_CYCLING, + "walking", + TRAVEL_MODE_WALKING, + "ferry", + TRAVEL_MODE_FERRY, + "train", + TRAVEL_MODE_TRAIN, + "pushing_bike", + TRAVEL_MODE_PUSHING_BIKE, + "steps_up", + TRAVEL_MODE_STEPS_UP, + "steps_down", + TRAVEL_MODE_STEPS_DOWN, + "river_up", + TRAVEL_MODE_RIVER_UP, + "river_down", + TRAVEL_MODE_RIVER_DOWN, + "route", + TRAVEL_MODE_ROUTE); + + context.state.new_enum("road_priority_class", + "motorway", + extractor::guidance::RoadPriorityClass::MOTORWAY, + "trunk", + extractor::guidance::RoadPriorityClass::TRUNK, + "primary", + extractor::guidance::RoadPriorityClass::PRIMARY, + "secondary", + extractor::guidance::RoadPriorityClass::SECONDARY, + "tertiary", + extractor::guidance::RoadPriorityClass::TERTIARY, + "main_residential", + extractor::guidance::RoadPriorityClass::MAIN_RESIDENTIAL, + "side_residential", + extractor::guidance::RoadPriorityClass::SIDE_RESIDENTIAL, + "link_road", + extractor::guidance::RoadPriorityClass::LINK_ROAD, + "bike_path", + extractor::guidance::RoadPriorityClass::BIKE_PATH, + "foot_path", + extractor::guidance::RoadPriorityClass::FOOT_PATH, + "connectivity", + extractor::guidance::RoadPriorityClass::CONNECTIVITY); + + context.state.new_usertype("sources", + "load", + &SourceContainer::LoadRasterSource, + "query", + &SourceContainer::GetRasterDataFromSource, + "interpolate", + &SourceContainer::GetRasterInterpolateFromSource); + + context.state.new_enum("constants", "precision", COORDINATE_PRECISION); + + context.state.new_usertype( + "ProfileProperties", + "traffic_signal_penalty", + sol::property(&ProfileProperties::GetTrafficSignalPenalty, + &ProfileProperties::SetTrafficSignalPenalty), + "u_turn_penalty", + sol::property(&ProfileProperties::GetUturnPenalty, // + &ProfileProperties::SetUturnPenalty), + "max_speed_for_map_matching", + sol::property(&ProfileProperties::GetMaxSpeedForMapMatching, + &ProfileProperties::SetMaxSpeedForMapMatching), + "continue_straight_at_waypoint", + &ProfileProperties::continue_straight_at_waypoint, + "use_turn_restrictions", + &ProfileProperties::use_turn_restrictions, + "left_hand_driving", + &ProfileProperties::left_hand_driving); + + context.state.new_usertype>( + "vector", + "Add", + static_cast::*)(const std::string &)>( + &std::vector::push_back)); + + context.state.new_usertype( + "Location", "lat", &osmium::Location::lat, "lon", &osmium::Location::lon); + + context.state.new_usertype("Way", + "get_value_by_key", + &get_value_by_key, + "id", + &osmium::Way::id, + "get_nodes", + &get_nodes_for_way); + + context.state.new_usertype("Node", + "location", + &osmium::Node::location, + "get_value_by_key", + &get_value_by_key, + "id", + &osmium::Node::id); + + context.state.new_usertype("ResultNode", + "traffic_lights", + &ExtractionNode::traffic_lights, + "barrier", + &ExtractionNode::barrier); + + context.state.new_usertype( + "RoadClassification", + "motorway_class", + sol::property(&guidance::RoadClassification::IsMotorwayClass, + &guidance::RoadClassification::SetMotorwayFlag), + "link_class", + sol::property(&guidance::RoadClassification::IsLinkClass, + &guidance::RoadClassification::SetLinkClass), + "may_be_ignored", + sol::property(&guidance::RoadClassification::IsLowPriorityRoadClass, + &guidance::RoadClassification::SetLowPriorityFlag), + "road_priority_class", + sol::property(&guidance::RoadClassification::GetClass, + &guidance::RoadClassification::SetClass), + "num_lanes", + sol::property(&guidance::RoadClassification::GetNumberOfLanes, + &guidance::RoadClassification::SetNumberOfLanes)); + + context.state.new_usertype( + "ResultWay", + "forward_speed", + &ExtractionWay::forward_speed, + "backward_speed", + &ExtractionWay::backward_speed, + "name", + sol::property(&ExtractionWay::GetName, &ExtractionWay::SetName), + "ref", + sol::property(&ExtractionWay::GetRef, &ExtractionWay::SetRef), + "pronunciation", + sol::property(&ExtractionWay::GetPronunciation, &ExtractionWay::SetPronunciation), + "destinations", + sol::property(&ExtractionWay::GetDestinations, &ExtractionWay::SetDestinations), + "turn_lanes_forward", + sol::property(&ExtractionWay::GetTurnLanesForward, &ExtractionWay::SetTurnLanesForward), + "turn_lanes_backward", + sol::property(&ExtractionWay::GetTurnLanesBackward, &ExtractionWay::SetTurnLanesBackward), + "roundabout", + &ExtractionWay::roundabout, + "circular", + &ExtractionWay::circular, + "is_startpoint", + &ExtractionWay::is_startpoint, + "duration", + &ExtractionWay::duration, + "road_classification", + &ExtractionWay::road_classification, + "forward_mode", + sol::property(&ExtractionWay::get_forward_mode, &ExtractionWay::set_forward_mode), + "backward_mode", + sol::property(&ExtractionWay::get_backward_mode, &ExtractionWay::set_backward_mode)); + + context.state.new_usertype("WayNodeList"); + + // Keep in mind .location is undefined since we're not using libosmium's location cache + context.state.new_usertype("NodeRef", "id", &osmium::NodeRef::ref); + + context.state.new_usertype("EdgeSource", + "source_coordinate", + &InternalExtractorEdge::source_coordinate, + "weight_data", + &InternalExtractorEdge::weight_data); + + context.state.new_usertype( + "WeightData", "speed", &InternalExtractorEdge::WeightData::speed); + + context.state.new_usertype("EdgeTarget", + "lon", + &lonToDouble, + "lat", + &latToDouble); + + context.state.new_usertype( + "Coordinate", + "lon", + sol::property(&lonToDouble), + "lat", + sol::property(&latToDouble)); + + context.state.new_usertype( + "RasterDatum", "datum", &RasterDatum::datum, "invalid_data", &RasterDatum::get_invalid); + + context.state["properties"] = &context.properties; + context.state["sources"] = &context.sources; + + // + // end of register block + // util::luaAddScriptFolderToLoadPath(context.state.lua_state(), file_name.c_str()); - context.has_turn_penalty_function = true; - context.has_node_function = true; - context.has_way_function = true; - context.has_segment_function = true; + context.state.script_file(file_name); + + sol::function turn_function = context.state["turn_function"]; + sol::function node_function = context.state["node_function"]; + sol::function way_function = context.state["way_function"]; + sol::function segment_function = context.state["segment_function"]; + + context.has_turn_penalty_function = turn_function.valid(); + context.has_node_function = node_function.valid(); + context.has_way_function = way_function.valid(); + context.has_segment_function = segment_function.valid(); } const ProfileProperties &Sol2ScriptingEnvironment::GetProfileProperties() @@ -117,33 +376,64 @@ void Sol2ScriptingEnvironment::ProcessElements( std::vector Sol2ScriptingEnvironment::GetNameSuffixList() { auto &context = GetSol2Context(); - BOOST_ASSERT(context.state != nullptr); + BOOST_ASSERT(context.state.lua_state() != nullptr); std::vector suffixes_vector; - // TODO: fill if get_suff. function exists + + sol::function get_name_suffix_list = context.state["get_name_suffix_list"]; + + if (get_name_suffix_list.valid()) + { + get_name_suffix_list(suffixes_vector); + } + return suffixes_vector; } std::vector Sol2ScriptingEnvironment::GetRestrictions() { auto &context = GetSol2Context(); - BOOST_ASSERT(context.state != nullptr); + BOOST_ASSERT(context.state.lua_state() != nullptr); std::vector restrictions; - // TODO: fill if get_restrictoins is available + + sol::function get_restrictions = context.state["get_restrictions"]; + + if (get_restrictions.valid()) + { + get_restrictions(restrictions); + } + return restrictions; } void Sol2ScriptingEnvironment::SetupSources() { auto &context = GetSol2Context(); - BOOST_ASSERT(context.state != nullptr); + BOOST_ASSERT(context.state.lua_state() != nullptr); - // TODO: call source_function if exists + sol::function source_function = context.state["source_function"]; + + if (source_function.valid()) + { + source_function(); + } } int32_t Sol2ScriptingEnvironment::GetTurnPenalty(const double angle) { auto &context = GetSol2Context(); - // turn_function(angle) if function exists + + sol::function turn_function = context.state["turn_function"]; + + if (turn_function.valid()) + { + const double penalty = turn_function(angle); + + BOOST_ASSERT(penalty < std::numeric_limits::max()); + BOOST_ASSERT(penalty > std::numeric_limits::min()); + + return penalty; + } + return 0; } @@ -153,19 +443,31 @@ void Sol2ScriptingEnvironment::ProcessSegment(const osrm::util::Coordinate &sour InternalExtractorEdge::WeightData &weight) { auto &context = GetSol2Context(); - // TODO: call segment_function if exists + + sol::function segment_function = context.state["segment_function"]; + + if (segment_function.valid()) + { + segment_function(source, target, distance, weight); + } } void Sol2ScriptingContext::processNode(const osmium::Node &node, ExtractionNode &result) { - BOOST_ASSERT(state != nullptr); - // TODO: node_function + BOOST_ASSERT(state.lua_state() != nullptr); + + sol::function node_function = state["node_function"]; + + node_function(node, result); } void Sol2ScriptingContext::processWay(const osmium::Way &way, ExtractionWay &result) { - BOOST_ASSERT(state != nullptr); - // TODO: way_function + BOOST_ASSERT(state.lua_state() != nullptr); + + sol::function way_function = state["way_function"]; + + way_function(way, result); } } } diff --git a/third_party/sol2/sol.hpp b/third_party/sol2/sol2/sol.hpp similarity index 87% rename from third_party/sol2/sol.hpp rename to third_party/sol2/sol2/sol.hpp index 7643601f8..10b56452a 100644 --- a/third_party/sol2/sol.hpp +++ b/third_party/sol2/sol2/sol.hpp @@ -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 2016-10-15 22:53:00.289259 UTC -// This header was generated with sol v2.14.10 (revision 8f7433f) +// Generated 2016-12-02 10:47:03.358052 UTC +// This header was generated with sol v2.15.3 (revision 7bef50d) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -48,6 +48,7 @@ namespace sol { std::string w; public: error(const std::string& str) : error(detail::direct_error, "lua: error: " + str) {} + error(std::string&& str) : error(detail::direct_error, "lua: error: " + std::move(str)) {} error(detail::direct_error_tag, const std::string& str) : std::runtime_error(""), w(str) {} error(detail::direct_error_tag, std::string&& str) : std::runtime_error(""), w(std::move(str)) {} @@ -373,6 +374,9 @@ namespace sol { template struct is_tuple> : std::true_type { }; + template + struct is_builtin_type : std::integral_constant::value || std::is_pointer::value || std::is_array::value> {}; + template struct unwrapped { typedef T type; @@ -754,1078 +758,19 @@ namespace sol { // beginning of sol/object.hpp -// beginning of sol/optional.hpp - -// beginning of sol/in_place.hpp - -namespace sol { - - namespace detail { - struct in_place_of {}; - template - struct in_place_of_i {}; - template - struct in_place_of_t {}; - } // detail - - struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; }; - constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); } - template - constexpr inline in_place_tag in_place(detail::in_place_of_t) { return in_place_tag(in_place_tag::init()); } - template - constexpr inline in_place_tag in_place(detail::in_place_of_i) { return in_place_tag(in_place_tag::init()); } - - using in_place_t = in_place_tag(&)(detail::in_place_of); - template - using in_place_type_t = in_place_tag(&)(detail::in_place_of_t); - template - using in_place_index_t = in_place_tag(&)(detail::in_place_of_i); - -} // sol - -// end of sol/in_place.hpp - -#if defined(SOL_USE_BOOST) -#include -#else -// beginning of Optional/optional.hpp - -# ifndef ___SOL_OPTIONAL_HPP___ -# define ___SOL_OPTIONAL_HPP___ - -# include -# include -# include -# include -# include -# include -# include - -# define TR2_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false - -# if defined __GNUC__ // NOTE: GNUC is also defined for Clang -# if (__GNUC__ >= 5) -# define TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# endif -# -# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# endif -# -# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# endif -# endif -# -# if defined __clang_major__ -# if (__clang_major__ == 3 && __clang_minor__ >= 5) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# elif (__clang_major__ > 3) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# endif -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# endif -# endif -# -# if defined _MSC_VER -# if (_MSC_VER >= 1900) -# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# endif -# endif - -# if defined __clang__ -# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif -# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif - -# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 -# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr -# else -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 -# define OPTIONAL_CONSTEXPR_INIT_LIST -# endif - -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) -# define OPTIONAL_HAS_MOVE_ACCESSORS 1 -# else -# define OPTIONAL_HAS_MOVE_ACCESSORS 0 -# endif - -# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr -# if (defined __cplusplus) && (__cplusplus == 201103L) -# define OPTIONAL_MUTABLE_CONSTEXPR -# else -# define OPTIONAL_MUTABLE_CONSTEXPR constexpr -# endif - -namespace sol{ - -# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it: it is already there -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - template - using is_trivially_destructible = ::std::has_trivial_destructor; -# endif - -# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - -template -struct is_nothrow_move_constructible -{ - constexpr static bool value = ::std::is_nothrow_constructible::value; -}; - -template -struct is_assignable -{ - template - constexpr static bool has_assign(...) { return false; } - - template () = ::std::declval(), true)) > - // the comma operator is necessary for the cases where operator= returns void - constexpr static bool has_assign(bool) { return true; } - - constexpr static bool value = has_assign(true); -}; - -template -struct is_nothrow_move_assignable -{ - template - struct has_nothrow_move_assign { - constexpr static bool value = false; - }; - - template - struct has_nothrow_move_assign { - constexpr static bool value = noexcept( ::std::declval() = ::std::declval() ); - }; - - constexpr static bool value = has_nothrow_move_assign::value>::value; -}; - -# endif - -template class optional; - -template class optional; - -template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type& t) noexcept -{ - return static_cast(t); -} - -template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type&& t) noexcept -{ - static_assert(!::std::is_lvalue_reference::value, "!!"); - return static_cast(t); -} - -template inline constexpr typename ::std::remove_reference::type&& constexpr_move(T&& t) noexcept -{ - return static_cast::type&&>(t); -} - -#if defined NDEBUG -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) -#else -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) -#endif - -namespace detail_ -{ - -template -struct has_overloaded_addressof -{ - template - constexpr static bool has_overload(...) { return false; } - - template ().operator&()) > - constexpr static bool has_overload(bool) { return true; } - - constexpr static bool value = has_overload(true); -}; - -template )> -constexpr T* static_addressof(T& ref) -{ - return &ref; -} - -template )> -T* static_addressof(T& ref) -{ - return ::std::addressof(ref); -} - -template -constexpr U convert(U v) { return v; } - -} // namespace detail_ - -constexpr struct trivial_init_t {} trivial_init{}; - -struct nullopt_t -{ - struct init{}; - constexpr explicit nullopt_t(init){} -}; -constexpr nullopt_t nullopt{nullopt_t::init()}; - -class bad_optional_access : public ::std::logic_error { -public: - explicit bad_optional_access(const ::std::string& what_arg) : ::std::logic_error{what_arg} {} - explicit bad_optional_access(const char* what_arg) : ::std::logic_error{what_arg} {} -}; - -template -struct optional_base -{ - bool init_; - char storage_[sizeof(T)]; - - constexpr optional_base() noexcept : init_(false), storage_() {}; - - explicit optional_base(const T& v) : init_(true), storage_() { - new (&storage())T(v); - } - - explicit optional_base(T&& v) : init_(true), storage_() { - new (&storage())T(constexpr_move(v)); - } - - template explicit optional_base(in_place_t, Args&&... args) - : init_(true), storage_() { - new (&storage())T(constexpr_forward(args)...); - } - - template >)> - explicit optional_base(in_place_t, ::std::initializer_list il, Args&&... args) - : init_(true), storage_() { - new (&storage())T(il, constexpr_forward(args)...); - } -#if defined __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - T& storage() { - return *reinterpret_cast(&storage_[0]); - } - - constexpr const T& storage() const { - return *reinterpret_cast(&storage_[0]); - } -#if defined __GNUC__ -#pragma GCC diagnostic pop -#endif - - ~optional_base() { if (init_) { storage().T::~T(); } } -}; - -#if defined __GNUC__ && !defined TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ -template -using constexpr_optional_base = optional_base; -#else -template -struct constexpr_optional_base -{ - bool init_; - char storage_[sizeof(T)]; - constexpr constexpr_optional_base() noexcept : init_(false), storage_() {} - - explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_() { - new (&storage())T(v); - } - - explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_() { - new (&storage())T(constexpr_move(v)); - } - - template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) - : init_(true), storage_() { - new (&storage())T(constexpr_forward(args)...); - } - - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, ::std::initializer_list il, Args&&... args) - : init_(true), storage_() { - new (&storage())T(il, constexpr_forward(args)...); - } - -#if defined __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - T& storage() { - return (*reinterpret_cast(&storage_[0])); - } - - constexpr const T& storage() const { - return (*reinterpret_cast(&storage_[0])); - } -#if defined __GNUC__ -#pragma GCC diagnostic pop -#endif - - ~constexpr_optional_base() = default; -}; -#endif - -template -using OptionalBase = typename ::std::conditional< - ::std::is_trivially_destructible::value, - constexpr_optional_base::type>, - optional_base::type> ->::type; - -template -class optional : private OptionalBase -{ - static_assert( !::std::is_same::type, nullopt_t>::value, "bad T" ); - static_assert( !::std::is_same::type, in_place_t>::value, "bad T" ); - - constexpr bool initialized() const noexcept { return OptionalBase::init_; } - typename ::std::remove_const::type* dataptr() { return ::std::addressof(OptionalBase::storage()); } - constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage()); } - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - constexpr const T& contained_val() const& { return OptionalBase::storage(); } -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return ::std::move(OptionalBase::storage()); } - OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage(); } -# else - T& contained_val() & { return OptionalBase::storage(); } - T&& contained_val() && { return ::std::move(OptionalBase::storage()); } -# endif -# else - constexpr const T& contained_val() const { return OptionalBase::storage(); } - T& contained_val() { return OptionalBase::storage(); } -# endif - - void clear() noexcept { - if (initialized()) dataptr()->T::~T(); - OptionalBase::init_ = false; - } - - template - void initialize(Args&&... args) noexcept(noexcept(T(::std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(::std::forward(args)...); - OptionalBase::init_ = true; - } - - template - void initialize(::std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, ::std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(il, ::std::forward(args)...); - OptionalBase::init_ = true; - } - -public: - typedef T value_type; - - // 20.5.5.1, constructors - constexpr optional() noexcept : OptionalBase() {}; - constexpr optional(nullopt_t) noexcept : OptionalBase() {}; - - optional(const optional& rhs) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(*rhs); - OptionalBase::init_ = true; - } - } - - optional(const optional& rhs) : optional() - { - if (rhs) { - ::new (static_cast(dataptr())) T(*rhs); - OptionalBase::init_ = true; - } - } - - optional(optional&& rhs) noexcept(::std::is_nothrow_move_constructible::value) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(::std::move(*rhs)); - OptionalBase::init_ = true; - } - } - - constexpr optional(const T& v) : OptionalBase(v) {} - - constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} - - template - explicit constexpr optional(in_place_t, Args&&... args) - : OptionalBase(in_place, constexpr_forward(args)...) {} - - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, ::std::initializer_list il, Args&&... args) - : OptionalBase(in_place, il, constexpr_forward(args)...) {} - - // 20.5.4.2, Destructor - ~optional() = default; - - // 20.5.4.3, assignment - optional& operator=(nullopt_t) noexcept - { - clear(); - return *this; - } - - optional& operator=(const optional& rhs) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); - else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; - return *this; - } - - optional& operator=(optional&& rhs) - noexcept(::std::is_nothrow_move_assignable::value && ::std::is_nothrow_move_constructible::value) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(::std::move(*rhs)); - else if (initialized() == true && rhs.initialized() == true) contained_val() = ::std::move(*rhs); - return *this; - } - - template - auto operator=(U&& v) - -> typename ::std::enable_if - < - ::std::is_same::type, T>::value, - optional& - >::type - { - if (initialized()) { contained_val() = ::std::forward(v); } - else { initialize(::std::forward(v)); } - return *this; - } - - template - void emplace(Args&&... args) - { - clear(); - initialize(::std::forward(args)...); - } - - template - void emplace(::std::initializer_list il, Args&&... args) - { - clear(); - initialize(il, ::std::forward(args)...); - } - - // 20.5.4.4, Swap - void swap(optional& rhs) noexcept(::std::is_nothrow_move_constructible::value && noexcept(swap(::std::declval(), ::std::declval()))) - { - if (initialized() == true && rhs.initialized() == false) { rhs.initialize(::std::move(**this)); clear(); } - else if (initialized() == false && rhs.initialized() == true) { initialize(::std::move(*rhs)); rhs.clear(); } - else if (initialized() == true && rhs.initialized() == true) { using ::std::swap; swap(**this, *rhs); } - } - - // 20.5.4.5, Observers - - explicit constexpr operator bool() const noexcept { return initialized(); } - - constexpr T const* operator ->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - - OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { - assert (initialized()); - return dataptr(); - } - - constexpr T const& operator *() const& { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { - assert (initialized()); - return contained_val(); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { - assert (initialized()); - return constexpr_move(contained_val()); - } - - constexpr T const& value() const& { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& value() & { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { - if (!initialized()) throw bad_optional_access("bad optional access"); - return ::std::move(contained_val()); - } - -# else - - T* operator ->() { - assert (initialized()); - return dataptr(); - } - - constexpr T const& operator *() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - T& operator *() { - assert (initialized()); - return contained_val(); - } - - constexpr T const& value() const { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - - T& value() { - return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); - } - -# endif - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - - template - constexpr T value_or(V&& v) const& - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - - template - OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# else - - template - T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# endif - -# else - - template - constexpr T value_or(V&& v) const - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# endif - -}; - -template -class optional -{ - static_assert( !::std::is_same::value, "bad T" ); - static_assert( !::std::is_same::value, "bad T" ); - T* ref; - -public: - - // 20.5.5.1, construction/destruction - constexpr optional() noexcept : ref(nullptr) {} - - constexpr optional(nullopt_t) noexcept : ref(nullptr) {} - - constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} - - optional(T&&) = delete; - - constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} - - explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} - - explicit optional(in_place_t, T&&) = delete; - - ~optional() = default; - - // 20.5.5.2, mutation - optional& operator=(nullopt_t) noexcept { - ref = nullptr; - return *this; - } - - // optional& operator=(const optional& rhs) noexcept { - // ref = rhs.ref; - // return *this; - // } - - // optional& operator=(optional&& rhs) noexcept { - // ref = rhs.ref; - // return *this; - // } - - template - auto operator=(U&& rhs) noexcept - -> typename ::std::enable_if - < - ::std::is_same::type, optional>::value, - optional& - >::type - { - ref = rhs.ref; - return *this; - } - - template - auto operator=(U&& rhs) noexcept - -> typename ::std::enable_if - < - !::std::is_same::type, optional>::value, - optional& - >::type - = delete; - - void emplace(T& v) noexcept { - ref = detail_::static_addressof(v); - } - - void emplace(T&&) = delete; - - void swap(optional& rhs) noexcept - { - ::std::swap(ref, rhs.ref); - } - - // 20.5.5.3, observers - constexpr T* operator->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); - } - - constexpr T& operator*() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); - } - - constexpr T& value() const { - return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); - } - - explicit constexpr operator bool() const noexcept { - return ref != nullptr; - } - - template - constexpr T& value_or(V&& v) const - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } -}; - -template -class optional -{ - static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); -}; - -template constexpr bool operator==(const optional& x, const optional& y) -{ - return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; -} - -template constexpr bool operator!=(const optional& x, const optional& y) -{ - return !(x == y); -} - -template constexpr bool operator<(const optional& x, const optional& y) -{ - return (!y) ? false : (!x) ? true : *x < *y; -} - -template constexpr bool operator>(const optional& x, const optional& y) -{ - return (y < x); -} - -template constexpr bool operator<=(const optional& x, const optional& y) -{ - return !(y < x); -} - -template constexpr bool operator>=(const optional& x, const optional& y) -{ - return !(x < y); -} - -template constexpr bool operator==(const optional& x, nullopt_t) noexcept -{ - return (!x); -} - -template constexpr bool operator==(nullopt_t, const optional& x) noexcept -{ - return (!x); -} - -template constexpr bool operator!=(const optional& x, nullopt_t) noexcept -{ - return bool(x); -} - -template constexpr bool operator!=(nullopt_t, const optional& x) noexcept -{ - return bool(x); -} - -template constexpr bool operator<(const optional&, nullopt_t) noexcept -{ - return false; -} - -template constexpr bool operator<(nullopt_t, const optional& x) noexcept -{ - return bool(x); -} - -template constexpr bool operator<=(const optional& x, nullopt_t) noexcept -{ - return (!x); -} - -template constexpr bool operator<=(nullopt_t, const optional&) noexcept -{ - return true; -} - -template constexpr bool operator>(const optional& x, nullopt_t) noexcept -{ - return bool(x); -} - -template constexpr bool operator>(nullopt_t, const optional&) noexcept -{ - return false; -} - -template constexpr bool operator>=(const optional&, nullopt_t) noexcept -{ - return true; -} - -template constexpr bool operator>=(nullopt_t, const optional& x) noexcept -{ - return (!x); -} - -template constexpr bool operator==(const optional& x, const T& v) -{ - return bool(x) ? *x == v : false; -} - -template constexpr bool operator==(const T& v, const optional& x) -{ - return bool(x) ? v == *x : false; -} - -template constexpr bool operator!=(const optional& x, const T& v) -{ - return bool(x) ? *x != v : true; -} - -template constexpr bool operator!=(const T& v, const optional& x) -{ - return bool(x) ? v != *x : true; -} - -template constexpr bool operator<(const optional& x, const T& v) -{ - return bool(x) ? *x < v : true; -} - -template constexpr bool operator>(const T& v, const optional& x) -{ - return bool(x) ? v > *x : true; -} - -template constexpr bool operator>(const optional& x, const T& v) -{ - return bool(x) ? *x > v : false; -} - -template constexpr bool operator<(const T& v, const optional& x) -{ - return bool(x) ? v < *x : false; -} - -template constexpr bool operator>=(const optional& x, const T& v) -{ - return bool(x) ? *x >= v : false; -} - -template constexpr bool operator<=(const T& v, const optional& x) -{ - return bool(x) ? v <= *x : false; -} - -template constexpr bool operator<=(const optional& x, const T& v) -{ - return bool(x) ? *x <= v : true; -} - -template constexpr bool operator>=(const T& v, const optional& x) -{ - return bool(x) ? v >= *x : true; -} - -template constexpr bool operator==(const optional& x, const T& v) -{ - return bool(x) ? *x == v : false; -} - -template constexpr bool operator==(const T& v, const optional& x) -{ - return bool(x) ? v == *x : false; -} - -template constexpr bool operator!=(const optional& x, const T& v) -{ - return bool(x) ? *x != v : true; -} - -template constexpr bool operator!=(const T& v, const optional& x) -{ - return bool(x) ? v != *x : true; -} - -template constexpr bool operator<(const optional& x, const T& v) -{ - return bool(x) ? *x < v : true; -} - -template constexpr bool operator>(const T& v, const optional& x) -{ - return bool(x) ? v > *x : true; -} - -template constexpr bool operator>(const optional& x, const T& v) -{ - return bool(x) ? *x > v : false; -} - -template constexpr bool operator<(const T& v, const optional& x) -{ - return bool(x) ? v < *x : false; -} - -template constexpr bool operator>=(const optional& x, const T& v) -{ - return bool(x) ? *x >= v : false; -} - -template constexpr bool operator<=(const T& v, const optional& x) -{ - return bool(x) ? v <= *x : false; -} - -template constexpr bool operator<=(const optional& x, const T& v) -{ - return bool(x) ? *x <= v : true; -} - -template constexpr bool operator>=(const T& v, const optional& x) -{ - return bool(x) ? v >= *x : true; -} - -template constexpr bool operator==(const optional& x, const T& v) -{ - return bool(x) ? *x == v : false; -} - -template constexpr bool operator==(const T& v, const optional& x) -{ - return bool(x) ? v == *x : false; -} - -template constexpr bool operator!=(const optional& x, const T& v) -{ - return bool(x) ? *x != v : true; -} - -template constexpr bool operator!=(const T& v, const optional& x) -{ - return bool(x) ? v != *x : true; -} - -template constexpr bool operator<(const optional& x, const T& v) -{ - return bool(x) ? *x < v : true; -} - -template constexpr bool operator>(const T& v, const optional& x) -{ - return bool(x) ? v > *x : true; -} - -template constexpr bool operator>(const optional& x, const T& v) -{ - return bool(x) ? *x > v : false; -} - -template constexpr bool operator<(const T& v, const optional& x) -{ - return bool(x) ? v < *x : false; -} - -template constexpr bool operator>=(const optional& x, const T& v) -{ - return bool(x) ? *x >= v : false; -} - -template constexpr bool operator<=(const T& v, const optional& x) -{ - return bool(x) ? v <= *x : false; -} - -template constexpr bool operator<=(const optional& x, const T& v) -{ - return bool(x) ? *x <= v : true; -} - -template constexpr bool operator>=(const T& v, const optional& x) -{ - return bool(x) ? v >= *x : true; -} - -template -void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) -{ - x.swap(y); -} - -template -constexpr optional::type> make_optional(T&& v) -{ - return optional::type>(constexpr_forward(v)); -} - -template -constexpr optional make_optional(::std::reference_wrapper v) -{ - return optional(v.get()); -} - -} // namespace - -namespace std -{ - template - struct hash> - { - typedef typename hash::result_type result_type; - typedef sol::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? ::std::hash{}(*arg) : result_type{}; - } - }; - - template - struct hash> - { - typedef typename hash::result_type result_type; - typedef sol::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? ::std::hash{}(*arg) : result_type{}; - } - }; -} - -# undef TR2_OPTIONAL_REQUIRES -# undef TR2_OPTIONAL_ASSERTED_EXPRESSION - -# endif //___SOL_OPTIONAL_HPP___ -// end of Optional/optional.hpp - -#endif // Boost vs. Better optional - -namespace sol { - -#if defined(SOL_USE_BOOST) - template - using optional = boost::optional; - using nullopt_t = boost::none_t; - const nullopt_t nullopt = boost::none; -#endif // Boost vs. Better optional - -} // sol - -// end of sol/optional.hpp - // beginning of sol/reference.hpp // beginning of sol/types.hpp +// beginning of sol/optional.hpp + // beginning of sol/compatibility.hpp // beginning of sol/compatibility/version.hpp #include -#if defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +#if defined(_WIN32) || defined(_MSC_VER) #ifndef SOL_CODECVT_SUPPORT #define SOL_CODECVT_SUPPORT 1 #endif // sol codecvt support @@ -1834,7 +779,7 @@ namespace sol { #ifndef SOL_CODECVT_SUPPORT #define SOL_CODECVT_SUPPORT 1 #endif // codecvt support -#endif // g++ 5.x.x +#endif // g++ 5.x.x (MinGW too) #else #endif // Windows/VC++ vs. g++ vs Others @@ -2055,7 +1000,7 @@ inline const char* kepler_lua_compat_get_string(lua_State* L, void* ud, size_t* return ls->s; } -#if !defined(SOL_LUAJIT) || ((SOL_LUAJIT_VERSION - 020100) <= 0) +#if !defined(SOL_LUAJIT) || ((SOL_LUAJIT_VERSION - 20100) <= 0) inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const char* name, const char*) { kepler_lua_compat_get_string_view ls; @@ -2843,6 +1788,1133 @@ inline void luaL_pushresult(luaL_Buffer_52 *B) { // end of sol/compatibility.hpp +// beginning of sol/in_place.hpp + +namespace sol { + + namespace detail { + struct in_place_of {}; + template + struct in_place_of_i {}; + template + struct in_place_of_t {}; + } // detail + + struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; }; + constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); } + template + constexpr inline in_place_tag in_place(detail::in_place_of_t) { return in_place_tag(in_place_tag::init()); } + template + constexpr inline in_place_tag in_place(detail::in_place_of_i) { return in_place_tag(in_place_tag::init()); } + + using in_place_t = in_place_tag(&)(detail::in_place_of); + template + using in_place_type_t = in_place_tag(&)(detail::in_place_of_t); + template + using in_place_index_t = in_place_tag(&)(detail::in_place_of_i); + +} // sol + +// end of sol/in_place.hpp + +#if defined(SOL_USE_BOOST) +#include +#else +// beginning of sol/optional_implementation.hpp + +# ifndef SOL_OPTIONAL_IMPLEMENTATION_HPP +# define SOL_OPTIONAL_IMPLEMENTATION_HPP + +# include +# include +# include +# include +# include +# include +# include +#ifdef SOL_NO_EXCEPTIONS +#include +#endif // Exceptions + +# define TR2_OPTIONAL_REQUIRES(...) typename ::std::enable_if<__VA_ARGS__::value, bool>::type = false + +# if defined __GNUC__ // NOTE: GNUC is also defined for Clang +# if (__GNUC__ >= 5) +# define TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ +# endif +# +# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# elif (__GNUC__ > 4) +# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# endif +# endif +# +# if defined __clang_major__ +# if (__clang_major__ == 3 && __clang_minor__ >= 5) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# elif (__clang_major__ > 3) +# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# endif +# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) +# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ +# endif +# endif +# +# if defined _MSC_VER +# if (_MSC_VER >= 1900) +# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# endif +# endif + +# if defined __clang__ +# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif +# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 +# else +# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 +# endif + +# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 +# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr +# else +# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 +# define OPTIONAL_CONSTEXPR_INIT_LIST +# endif + +# if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || (defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L)) +# define OPTIONAL_HAS_MOVE_ACCESSORS 1 +# else +# define OPTIONAL_HAS_MOVE_ACCESSORS 0 +# endif + +# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr +# if defined(TR2_OPTIONAL_MSVC_2015_AND_HIGHER___) || ((defined __cplusplus) && (__cplusplus == 201103L)) +# define OPTIONAL_MUTABLE_CONSTEXPR +# else +# define OPTIONAL_MUTABLE_CONSTEXPR constexpr +# endif + +# if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +#pragma warning( push ) +#pragma warning( disable : 4814 ) +#endif + +namespace sol { + + // BEGIN workaround for missing is_trivially_destructible +# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it: it is already there +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + template + using is_trivially_destructible = ::std::has_trivial_destructor; +# endif + // END workaround for missing is_trivially_destructible + +# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ + // leave it; our metafunctions are already defined. +# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ + // leave it: it is already there +# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS + // leave it: the user doesn't want it +# else + + template + struct is_nothrow_move_constructible + { + constexpr static bool value = ::std::is_nothrow_constructible::value; + }; + + template + struct is_assignable + { + template + constexpr static bool has_assign(...) { return false; } + + template () = ::std::declval(), true)) > + // the comma operator is necessary for the cases where operator= returns void + constexpr static bool has_assign(bool) { return true; } + + constexpr static bool value = has_assign(true); + }; + + template + struct is_nothrow_move_assignable + { + template + struct has_nothrow_move_assign { + constexpr static bool value = false; + }; + + template + struct has_nothrow_move_assign { + constexpr static bool value = noexcept(::std::declval() = ::std::declval()); + }; + + constexpr static bool value = has_nothrow_move_assign::value>::value; + }; + // end workaround + +# endif + + template class optional; + + // 20.5.5, optional for lvalue reference types + template class optional; + + // workaround: std utility functions aren't constexpr yet + template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type& t) noexcept + { + return static_cast(t); + } + + template inline constexpr T&& constexpr_forward(typename ::std::remove_reference::type&& t) noexcept + { + static_assert(!::std::is_lvalue_reference::value, "!!"); + return static_cast(t); + } + + template inline constexpr typename ::std::remove_reference::type&& constexpr_move(T&& t) noexcept + { + return static_cast::type&&>(t); + } + +#if defined NDEBUG +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) +#else +# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) +#endif + + namespace detail_ + { + + // static_addressof: a constexpr version of addressof + template + struct has_overloaded_addressof + { + template + constexpr static bool has_overload(...) { return false; } + + template ().operator&()) > + constexpr static bool has_overload(bool) { return true; } + + constexpr static bool value = has_overload(true); + }; + + template )> + constexpr T* static_addressof(T& ref) + { + return &ref; + } + + template )> + T* static_addressof(T& ref) + { + return ::std::addressof(ref); + } + + // the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A + template + constexpr U convert(U v) { return v; } + + } // namespace detail_ + + constexpr struct trivial_init_t {} trivial_init{}; + + // 20.5.7, Disengaged state indicator + struct nullopt_t + { + struct init {}; + constexpr explicit nullopt_t(init) {} + }; + constexpr nullopt_t nullopt{ nullopt_t::init() }; + + // 20.5.8, class bad_optional_access + class bad_optional_access : public ::std::logic_error { + public: + explicit bad_optional_access(const ::std::string& what_arg) : ::std::logic_error{ what_arg } {} + explicit bad_optional_access(const char* what_arg) : ::std::logic_error{ what_arg } {} + }; + + template + struct optional_base + { + bool init_; + char storage_[sizeof(T)]; + + constexpr optional_base() noexcept : init_(false), storage_() {}; + + explicit optional_base(const T& v) : init_(true), storage_() { + new (&storage())T(v); + } + + explicit optional_base(T&& v) : init_(true), storage_() { + new (&storage())T(constexpr_move(v)); + } + + template explicit optional_base(in_place_t, Args&&... args) + : init_(true), storage_() { + new (&storage())T(constexpr_forward(args)...); + } + + template >)> + explicit optional_base(in_place_t, ::std::initializer_list il, Args&&... args) + : init_(true), storage_() { + new (&storage())T(il, constexpr_forward(args)...); + } +#if defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + T& storage() { + return *reinterpret_cast(&storage_[0]); + } + + constexpr const T& storage() const { + return *reinterpret_cast(&storage_[0]); + } +#if defined __GNUC__ +#pragma GCC diagnostic pop +#endif + + ~optional_base() { if (init_) { storage().T::~T(); } } + }; + +#if defined __GNUC__ && !defined TR2_OPTIONAL_GCC_5_0_AND_HIGHER___ + // Sorry, GCC 4.x; you're just a piece of shit + template + using constexpr_optional_base = optional_base; +#else + template + struct constexpr_optional_base + { + bool init_; + char storage_[sizeof(T)]; + constexpr constexpr_optional_base() noexcept : init_(false), storage_() {} + + explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_() { + new (&storage())T(v); + } + + explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_() { + new (&storage())T(constexpr_move(v)); + } + + template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) + : init_(true), storage_() { + new (&storage())T(constexpr_forward(args)...); + } + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, ::std::initializer_list il, Args&&... args) + : init_(true), storage_() { + new (&storage())T(il, constexpr_forward(args)...); + } + +#if defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + T& storage() { + return (*reinterpret_cast(&storage_[0])); + } + + constexpr const T& storage() const { + return (*reinterpret_cast(&storage_[0])); + } +#if defined __GNUC__ +#pragma GCC diagnostic pop +#endif + + ~constexpr_optional_base() = default; + }; +#endif + + template + using OptionalBase = typename ::std::conditional< + ::std::is_trivially_destructible::value, + constexpr_optional_base::type>, + optional_base::type> + >::type; + + template + class optional : private OptionalBase + { + static_assert(!::std::is_same::type, nullopt_t>::value, "bad T"); + static_assert(!::std::is_same::type, in_place_t>::value, "bad T"); + + constexpr bool initialized() const noexcept { return OptionalBase::init_; } + typename ::std::remove_const::type* dataptr() { return ::std::addressof(OptionalBase::storage()); } + constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage()); } + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + constexpr const T& contained_val() const& { return OptionalBase::storage(); } +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return ::std::move(OptionalBase::storage()); } + OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage(); } +# else + T& contained_val() & { return OptionalBase::storage(); } + T&& contained_val() && { return ::std::move(OptionalBase::storage()); } +# endif +# else + constexpr const T& contained_val() const { return OptionalBase::storage(); } + T& contained_val() { return OptionalBase::storage(); } +# endif + + void clear() noexcept { + if (initialized()) dataptr()->T::~T(); + OptionalBase::init_ = false; + } + + template + void initialize(Args&&... args) noexcept(noexcept(T(::std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(::std::forward(args)...); + OptionalBase::init_ = true; + } + + template + void initialize(::std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, ::std::forward(args)...))) + { + assert(!OptionalBase::init_); + ::new (static_cast(dataptr())) T(il, ::std::forward(args)...); + OptionalBase::init_ = true; + } + + public: + typedef T value_type; + + // 20.5.5.1, constructors + constexpr optional() noexcept : OptionalBase() {}; + constexpr optional(nullopt_t) noexcept : OptionalBase() {}; + + optional(const optional& rhs) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + optional(const optional& rhs) : optional() + { + if (rhs) { + ::new (static_cast(dataptr())) T(*rhs); + OptionalBase::init_ = true; + } + } + + optional(optional&& rhs) noexcept(::std::is_nothrow_move_constructible::value) + : OptionalBase() + { + if (rhs.initialized()) { + ::new (static_cast(dataptr())) T(::std::move(*rhs)); + OptionalBase::init_ = true; + } + } + + constexpr optional(const T& v) : OptionalBase(v) {} + + constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} + + template + explicit constexpr optional(in_place_t, Args&&... args) + : OptionalBase(in_place, constexpr_forward(args)...) {} + + template >)> + OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, ::std::initializer_list il, Args&&... args) + : OptionalBase(in_place, il, constexpr_forward(args)...) {} + + // 20.5.4.2, Destructor + ~optional() = default; + + // 20.5.4.3, assignment + optional& operator=(nullopt_t) noexcept + { + clear(); + return *this; + } + + optional& operator=(const optional& rhs) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); + else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; + return *this; + } + + optional& operator=(optional&& rhs) + noexcept(::std::is_nothrow_move_assignable::value && ::std::is_nothrow_move_constructible::value) + { + if (initialized() == true && rhs.initialized() == false) clear(); + else if (initialized() == false && rhs.initialized() == true) initialize(::std::move(*rhs)); + else if (initialized() == true && rhs.initialized() == true) contained_val() = ::std::move(*rhs); + return *this; + } + + template + auto operator=(U&& v) + -> typename ::std::enable_if + < + ::std::is_same::type, T>::value, + optional& + >::type + { + if (initialized()) { contained_val() = ::std::forward(v); } + else { initialize(::std::forward(v)); } + return *this; + } + + template + void emplace(Args&&... args) + { + clear(); + initialize(::std::forward(args)...); + } + + template + void emplace(::std::initializer_list il, Args&&... args) + { + clear(); + initialize(il, ::std::forward(args)...); + } + + // 20.5.4.4, Swap + void swap(optional& rhs) noexcept(::std::is_nothrow_move_constructible::value && noexcept(swap(::std::declval(), ::std::declval()))) + { + if (initialized() == true && rhs.initialized() == false) { rhs.initialize(::std::move(**this)); clear(); } + else if (initialized() == false && rhs.initialized() == true) { initialize(::std::move(*rhs)); rhs.clear(); } + else if (initialized() == true && rhs.initialized() == true) { using ::std::swap; swap(**this, *rhs); } + } + + // 20.5.4.5, Observers + + explicit constexpr operator bool() const noexcept { return initialized(); } + + constexpr T const* operator ->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { + assert(initialized()); + return dataptr(); + } + + constexpr T const& operator *() const& { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { + assert(initialized()); + return contained_val(); + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { + assert(initialized()); + return constexpr_move(contained_val()); + } + + constexpr T const& value() const& { + return initialized() ? + contained_val() +#ifdef SOL_NO_EXCEPTIONS + // we can't abort here + // because there's no constexpr abort + : *(T*)nullptr; +#else + : (throw bad_optional_access("bad optional access"), contained_val()); +#endif + } + + OPTIONAL_MUTABLE_CONSTEXPR T& value() & { + return initialized() ? + contained_val() +#ifdef SOL_NO_EXCEPTIONS + : *(T*)nullptr; +#else + : (throw bad_optional_access("bad optional access"), contained_val()); +#endif + } + + OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { + return initialized() ? + contained_val() +#ifdef SOL_NO_EXCEPTIONS + // we can't abort here + // because there's no constexpr abort + : std::move(*(T*)nullptr); +#else + : (throw bad_optional_access("bad optional access"), contained_val()); +#endif + } + +# else + + T* operator ->() { + assert(initialized()); + return dataptr(); + } + + constexpr T const& operator *() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); + } + + T& operator *() { + assert(initialized()); + return contained_val(); + } + + constexpr T const& value() const { + return initialized() ? + contained_val() +#ifdef SOL_NO_EXCEPTIONS + // we can't abort here + // because there's no constexpr abort + : *(T*)nullptr; +#else + : (throw bad_optional_access("bad optional access"), contained_val()); +#endif + } + + T& value() { + return initialized() ? + contained_val() +#ifdef SOL_NO_EXCEPTIONS + // we can abort here + // but the others are constexpr, so we can't... + : (std::abort(), *(T*)nullptr); +#else + : (throw bad_optional_access("bad optional access"), contained_val()); +#endif + } + +# endif + +# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 + + template + constexpr T value_or(V&& v) const& + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 + + template + OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# else + + template + T value_or(V&& v) && + { + return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); + } + +# endif + +# else + + template + constexpr T value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + +# endif + + }; + + template + class optional + { + static_assert(!::std::is_same::value, "bad T"); + static_assert(!::std::is_same::value, "bad T"); + T* ref; + + public: + + // 20.5.5.1, construction/destruction + constexpr optional() noexcept : ref(nullptr) {} + + constexpr optional(nullopt_t) noexcept : ref(nullptr) {} + + constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} + + optional(T&&) = delete; + + constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} + + explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} + + explicit optional(in_place_t, T&&) = delete; + + ~optional() = default; + + // 20.5.5.2, mutation + optional& operator=(nullopt_t) noexcept { + ref = nullptr; + return *this; + } + + // optional& operator=(const optional& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + // optional& operator=(optional&& rhs) noexcept { + // ref = rhs.ref; + // return *this; + // } + + template + auto operator=(U&& rhs) noexcept + -> typename ::std::enable_if + < + ::std::is_same::type, optional>::value, + optional& + >::type + { + ref = rhs.ref; + return *this; + } + + template + auto operator=(U&& rhs) noexcept + -> typename ::std::enable_if + < + !::std::is_same::type, optional>::value, + optional& + >::type + = delete; + + void emplace(T& v) noexcept { + ref = detail_::static_addressof(v); + } + + void emplace(T&&) = delete; + + void swap(optional& rhs) noexcept + { + ::std::swap(ref, rhs.ref); + } + + // 20.5.5.3, observers + constexpr T* operator->() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); + } + + constexpr T& operator*() const { + return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); + } + + constexpr T& value() const { + return ref ? + *ref +#ifdef SOL_NO_EXCEPTIONS + // we can't abort here + // because there's no constexpr abort + : *(T*)nullptr; +#else + : throw bad_optional_access("bad optional access"); +#endif + } + + explicit constexpr operator bool() const noexcept { + return ref != nullptr; + } + + template + constexpr T& value_or(V&& v) const + { + return *this ? **this : detail_::convert(constexpr_forward(v)); + } + }; + + template + class optional + { + static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); + }; + + // 20.5.8, Relational operators + template constexpr bool operator==(const optional& x, const optional& y) + { + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; + } + + template constexpr bool operator!=(const optional& x, const optional& y) + { + return !(x == y); + } + + template constexpr bool operator<(const optional& x, const optional& y) + { + return (!y) ? false : (!x) ? true : *x < *y; + } + + template constexpr bool operator>(const optional& x, const optional& y) + { + return (y < x); + } + + template constexpr bool operator<=(const optional& x, const optional& y) + { + return !(y < x); + } + + template constexpr bool operator>=(const optional& x, const optional& y) + { + return !(x < y); + } + + // 20.5.9, Comparison with nullopt + template constexpr bool operator==(const optional& x, nullopt_t) noexcept + { + return (!x); + } + + template constexpr bool operator==(nullopt_t, const optional& x) noexcept + { + return (!x); + } + + template constexpr bool operator!=(const optional& x, nullopt_t) noexcept + { + return bool(x); + } + + template constexpr bool operator!=(nullopt_t, const optional& x) noexcept + { + return bool(x); + } + + template constexpr bool operator<(const optional&, nullopt_t) noexcept + { + return false; + } + + template constexpr bool operator<(nullopt_t, const optional& x) noexcept + { + return bool(x); + } + + template constexpr bool operator<=(const optional& x, nullopt_t) noexcept + { + return (!x); + } + + template constexpr bool operator<=(nullopt_t, const optional&) noexcept + { + return true; + } + + template constexpr bool operator>(const optional& x, nullopt_t) noexcept + { + return bool(x); + } + + template constexpr bool operator>(nullopt_t, const optional&) noexcept + { + return false; + } + + template constexpr bool operator>=(const optional&, nullopt_t) noexcept + { + return true; + } + + template constexpr bool operator>=(nullopt_t, const optional& x) noexcept + { + return (!x); + } + + // 20.5.10, Comparison with T + template constexpr bool operator==(const optional& x, const T& v) + { + return bool(x) ? *x == v : false; + } + + template constexpr bool operator==(const T& v, const optional& x) + { + return bool(x) ? v == *x : false; + } + + template constexpr bool operator!=(const optional& x, const T& v) + { + return bool(x) ? *x != v : true; + } + + template constexpr bool operator!=(const T& v, const optional& x) + { + return bool(x) ? v != *x : true; + } + + template constexpr bool operator<(const optional& x, const T& v) + { + return bool(x) ? *x < v : true; + } + + template constexpr bool operator>(const T& v, const optional& x) + { + return bool(x) ? v > *x : true; + } + + template constexpr bool operator>(const optional& x, const T& v) + { + return bool(x) ? *x > v : false; + } + + template constexpr bool operator<(const T& v, const optional& x) + { + return bool(x) ? v < *x : false; + } + + template constexpr bool operator>=(const optional& x, const T& v) + { + return bool(x) ? *x >= v : false; + } + + template constexpr bool operator<=(const T& v, const optional& x) + { + return bool(x) ? v <= *x : false; + } + + template constexpr bool operator<=(const optional& x, const T& v) + { + return bool(x) ? *x <= v : true; + } + + template constexpr bool operator>=(const T& v, const optional& x) + { + return bool(x) ? v >= *x : true; + } + + // Comparison of optional with T + template constexpr bool operator==(const optional& x, const T& v) + { + return bool(x) ? *x == v : false; + } + + template constexpr bool operator==(const T& v, const optional& x) + { + return bool(x) ? v == *x : false; + } + + template constexpr bool operator!=(const optional& x, const T& v) + { + return bool(x) ? *x != v : true; + } + + template constexpr bool operator!=(const T& v, const optional& x) + { + return bool(x) ? v != *x : true; + } + + template constexpr bool operator<(const optional& x, const T& v) + { + return bool(x) ? *x < v : true; + } + + template constexpr bool operator>(const T& v, const optional& x) + { + return bool(x) ? v > *x : true; + } + + template constexpr bool operator>(const optional& x, const T& v) + { + return bool(x) ? *x > v : false; + } + + template constexpr bool operator<(const T& v, const optional& x) + { + return bool(x) ? v < *x : false; + } + + template constexpr bool operator>=(const optional& x, const T& v) + { + return bool(x) ? *x >= v : false; + } + + template constexpr bool operator<=(const T& v, const optional& x) + { + return bool(x) ? v <= *x : false; + } + + template constexpr bool operator<=(const optional& x, const T& v) + { + return bool(x) ? *x <= v : true; + } + + template constexpr bool operator>=(const T& v, const optional& x) + { + return bool(x) ? v >= *x : true; + } + + // Comparison of optional with T + template constexpr bool operator==(const optional& x, const T& v) + { + return bool(x) ? *x == v : false; + } + + template constexpr bool operator==(const T& v, const optional& x) + { + return bool(x) ? v == *x : false; + } + + template constexpr bool operator!=(const optional& x, const T& v) + { + return bool(x) ? *x != v : true; + } + + template constexpr bool operator!=(const T& v, const optional& x) + { + return bool(x) ? v != *x : true; + } + + template constexpr bool operator<(const optional& x, const T& v) + { + return bool(x) ? *x < v : true; + } + + template constexpr bool operator>(const T& v, const optional& x) + { + return bool(x) ? v > *x : true; + } + + template constexpr bool operator>(const optional& x, const T& v) + { + return bool(x) ? *x > v : false; + } + + template constexpr bool operator<(const T& v, const optional& x) + { + return bool(x) ? v < *x : false; + } + + template constexpr bool operator>=(const optional& x, const T& v) + { + return bool(x) ? *x >= v : false; + } + + template constexpr bool operator<=(const T& v, const optional& x) + { + return bool(x) ? v <= *x : false; + } + + template constexpr bool operator<=(const optional& x, const T& v) + { + return bool(x) ? *x <= v : true; + } + + template constexpr bool operator>=(const T& v, const optional& x) + { + return bool(x) ? v >= *x : true; + } + + // 20.5.12, Specialized algorithms + template + void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) { + x.swap(y); + } + + template + constexpr optional::type> make_optional(T&& v) { + return optional::type>(constexpr_forward(v)); + } + + template + constexpr optional make_optional(::std::reference_wrapper v) { + return optional(v.get()); + } + +} // namespace + +namespace std +{ + template + struct hash> { + typedef typename hash::result_type result_type; + typedef sol::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? ::std::hash{}(*arg) : result_type{}; + } + }; + + template + struct hash> { + typedef typename hash::result_type result_type; + typedef sol::optional argument_type; + + constexpr result_type operator()(argument_type const& arg) const { + return arg ? ::std::hash{}(*arg) : result_type{}; + } + }; +} + +# if defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ +#pragma warning( pop ) +#endif + +# undef TR2_OPTIONAL_REQUIRES +# undef TR2_OPTIONAL_ASSERTED_EXPRESSION + +# endif // SOL_OPTIONAL_IMPLEMENTATION_HPP +// end of sol/optional_implementation.hpp + +#endif // Boost vs. Better optional + +namespace sol { + +#if defined(SOL_USE_BOOST) + template + using optional = boost::optional; + using nullopt_t = boost::none_t; + const nullopt_t nullopt = boost::none; +#endif // Boost vs. Better optional + +} // sol + +// end of sol/optional.hpp + // beginning of sol/string_shim.hpp #pragma once @@ -2854,8 +2926,8 @@ namespace sol { const char* p; string_shim(const std::string& r) : string_shim(r.data(), r.size()) {} - string_shim(const char* p) : string_shim(p, std::char_traits::length(p)) {} - string_shim(const char* p, std::size_t s) : s(s), p(p) {} + string_shim(const char* ptr) : string_shim(ptr, std::char_traits::length(ptr)) {} + string_shim(const char* ptr, std::size_t sz) : s(sz), p(ptr) {} static int compare(const char* lhs_p, std::size_t lhs_sz, const char* rhs_p, std::size_t rhs_sz) { int result = std::char_traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); @@ -2937,9 +3009,11 @@ namespace sol { catch (const std::exception& e) { lua_pushstring(L, e.what()); } +#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) catch (...) { lua_pushstring(L, "caught (...) exception"); } +#endif return lua_error(L); } @@ -2954,9 +3028,11 @@ namespace sol { catch (const std::exception& e) { lua_pushstring(L, e.what()); } +#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) catch (...) { lua_pushstring(L, "caught (...) exception"); } +#endif return lua_error(L); } @@ -3128,14 +3204,14 @@ namespace sol { struct closure { lua_CFunction c_function; std::tuple upvalues; - closure(lua_CFunction f, Upvalues... upvalues) : c_function(f), upvalues(std::forward(upvalues)...) {} + closure(lua_CFunction f, Upvalues... targetupvalues) : c_function(f), upvalues(std::forward(targetupvalues)...) {} }; template <> struct closure<> { lua_CFunction c_function; int upvalues; - closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {} + closure(lua_CFunction f, int upvalue_count = 0) : c_function(f), upvalues(upvalue_count) {} }; typedef closure<> c_closure; @@ -3241,6 +3317,7 @@ namespace sol { new_index, mode, call, + call_function = call, metatable, to_string, length, @@ -3257,7 +3334,13 @@ namespace sol { less_than, less_than_or_equal_to, garbage_collect, - call_function = call, + floor_division, + bitwise_left_shift, + bitwise_right_shift, + bitwise_not, + bitwise_and, + bitwise_or, + bitwise_xor, }; typedef meta_function meta_method; @@ -3273,7 +3356,7 @@ namespace sol { "__newindex", "__mode", "__call", - "__metatable", + "__mt", "__tostring", "__len", "__unm", @@ -3523,6 +3606,12 @@ namespace sol { template struct lua_type_of::value>> : std::integral_constant {}; + template + struct is_container : std::false_type {}; + + template + struct is_container>::value>> : std::true_type {}; + template <> struct lua_type_of : std::integral_constant {}; @@ -3627,6 +3716,9 @@ namespace sol { template struct is_userdata> : std::true_type {}; + template + struct is_container : detail::is_container{}; + template inline type type_of() { return lua_type_of>::value; @@ -3704,7 +3796,7 @@ namespace sol { struct push_popper_n { lua_State* L; int t; - push_popper_n(lua_State* L, int x) : L(L), t(x) { } + push_popper_n(lua_State* luastate, int x) : L(luastate), t(x) { } ~push_popper_n() { lua_pop(L, t); } }; template <> @@ -3738,20 +3830,20 @@ namespace sol { class reference { private: - lua_State* L = nullptr; // non-owning + lua_State* luastate = nullptr; // non-owning int ref = LUA_NOREF; int copy() const noexcept { if (ref == LUA_NOREF) return LUA_NOREF; push(); - return luaL_ref(L, LUA_REGISTRYINDEX); + return luaL_ref(lua_state(), LUA_REGISTRYINDEX); } protected: - reference(lua_State* L, detail::global_tag) noexcept : L(L) { - lua_pushglobaltable(L); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + reference(lua_State* L, detail::global_tag) noexcept : luastate(L) { + lua_pushglobaltable(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } int stack_index() const noexcept { @@ -3763,46 +3855,46 @@ namespace sol { reference(nil_t) noexcept : reference() {} reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {} reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {} - reference(lua_State* L, int index = -1) noexcept : L(L) { - lua_pushvalue(L, index); - ref = luaL_ref(L, LUA_REGISTRYINDEX); + reference(lua_State* L, int index = -1) noexcept : luastate(L) { + lua_pushvalue(lua_state(), index); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } virtual ~reference() noexcept { - luaL_unref(L, LUA_REGISTRYINDEX, ref); + luaL_unref(lua_state(), LUA_REGISTRYINDEX, ref); } reference(reference&& o) noexcept { - L = o.L; + luastate = o.luastate; ref = o.ref; - o.L = nullptr; + o.luastate = nullptr; o.ref = LUA_NOREF; } reference& operator=(reference&& o) noexcept { - L = o.L; + luastate = o.luastate; ref = o.ref; - o.L = nullptr; + o.luastate = nullptr; o.ref = LUA_NOREF; return *this; } reference(const reference& o) noexcept { - L = o.L; + luastate = o.luastate; ref = o.copy(); } reference& operator=(const reference& o) noexcept { - L = o.L; + luastate = o.luastate; ref = o.copy(); return *this; } int push() const noexcept { - lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); return 1; } @@ -3824,12 +3916,12 @@ namespace sol { type get_type() const noexcept { auto pp = stack::push_pop(*this); - int result = lua_type(L, -1); + int result = lua_type(lua_state(), -1); return static_cast(result); } lua_State* lua_state() const noexcept { - return L; + return luastate; } }; @@ -4056,7 +4148,7 @@ namespace sol { template inline int user_alloc_destroy(lua_State* L) { - void* rawdata = lua_touserdata(L, upvalue_index(1)); + void* rawdata = lua_touserdata(L, 1); T* data = static_cast(rawdata); std::allocator alloc; alloc.destroy(data); @@ -4252,7 +4344,7 @@ namespace sol { template inline auto tagged_get(types, lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get(L, index, tracking)) { auto op = check_get(L, index, type_panic, tracking); - return *op; + return *std::move(op); } #else template @@ -4527,13 +4619,13 @@ namespace sol { } template - inline std::string demangle() { + inline const std::string& demangle() { static const std::string d = demangle_once(); return d; } template - inline std::string short_demangle() { + inline const std::string& short_demangle() { static const std::string d = short_demangle_once(); return d; } @@ -4546,32 +4638,32 @@ namespace sol { template struct usertype_traits { - static const std::string name; - static const std::string qualified_name; - static const std::string metatable; - static const std::string user_metatable; - static const std::string user_gc_metatable; - static const std::string gc_table; + static const std::string& name() { + static const std::string& n = detail::short_demangle(); + return n; + } + static const std::string& qualified_name() { + static const std::string& q_n = detail::demangle(); + return q_n; + } + static const std::string& metatable() { + static const std::string m = std::string("sol.").append(detail::demangle()); + return m; + } + static const std::string& user_metatable() { + static const std::string u_m = std::string("sol.").append(detail::demangle()).append(".user"); + return u_m; + } + static const std::string& user_gc_metatable() { + static const std::string u_g_m = std::string("sol.").append(detail::demangle()).append(".user\xE2\x99\xBB"); + return u_g_m; + } + static const std::string& gc_table() { + static const std::string g_t = std::string("sol.").append(detail::demangle()).append(".\xE2\x99\xBB"); + return g_t; + } }; - template - const std::string usertype_traits::name = detail::short_demangle(); - - template - const std::string usertype_traits::qualified_name = detail::demangle(); - - template - const std::string usertype_traits::metatable = std::string("sol.").append(detail::demangle()); - - template - const std::string usertype_traits::user_metatable = std::string("sol.").append(detail::demangle()).append(".user"); - - template - const std::string usertype_traits::user_gc_metatable = std::string("sol.").append(detail::demangle()).append(".user\xE2\x99\xBB"); - - template - const std::string usertype_traits::gc_table = std::string("sol.").append(detail::demangle().append(".\xE2\x99\xBB")); - } // end of sol/usertype_traits.hpp @@ -4678,7 +4770,7 @@ namespace sol { namespace stack_detail { template inline bool check_metatable(lua_State* L, int index = -2) { - const auto& metakey = usertype_traits::metatable; + const auto& metakey = usertype_traits::metatable(); luaL_getmetatable(L, &metakey[0]); const type expectedmetatabletype = static_cast(lua_type(L, -1)); if (expectedmetatabletype != type::nil) { @@ -4911,21 +5003,7 @@ namespace sol { }; template - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - // Allow nil to be transformed to nullptr - if (indextype == type::nil) { - tracking.use(1); - return true; - } - return checker, type::userdata, C>{}.check(types>(), L, indextype, index, std::forward(handler), tracking); - } - }; - - template - struct checker { + struct checker, type::userdata, C> { template static bool check(types, lua_State* L, type indextype, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -4964,11 +5042,28 @@ namespace sol { lua_pop(L, 1); return true; } + }; + template + struct checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); - return check(types(), L, indextype, index, std::forward(handler), tracking); + return checker, type::userdata, C>{}.check(types(), L, indextype, index, std::forward(handler), tracking); + } + }; + + template + struct checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + const type indextype = type_of(L, index); + // Allow nil to be transformed to nullptr + if (indextype == type::nil) { + tracking.use(1); + return true; + } + return checker, type::userdata, C>{}.check(L, index, std::forward(handler), tracking); } }; @@ -5007,13 +5102,17 @@ namespace sol { template struct checker, type::poly, C> { template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); if (t == type::none) { tracking.use(0); return true; } - return t == type::nil || stack::check(L, index, std::forward(handler), tracking); + if (t == type::nil) { + tracking.use(1); + return true; + } + return stack::check(L, index, no_panic, tracking); } }; } // stack @@ -5056,7 +5155,7 @@ namespace sol { template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); + return getter>{}.get(L, index, tracking); } }; @@ -5452,7 +5551,7 @@ namespace sol { }; template - struct getter { + struct getter> { static T* get_no_nil(lua_State* L, int index, record& tracking) { tracking.use(1); void** pudata = static_cast(lua_touserdata(L, index)); @@ -5471,28 +5570,49 @@ namespace sol { T* obj = static_cast(udata); return obj; } + + static T& get(lua_State* L, int index, record& tracking) { + return *get_no_nil(L, index, tracking); + } + }; + template + struct getter> { static T* get(lua_State* L, int index, record& tracking) { type t = type_of(L, index); if (t == type::nil) { tracking.use(1); return nullptr; } - return get_no_nil(L, index, tracking); + return getter>::get_no_nil(L, index, tracking); } }; template struct getter> { static T* get(lua_State* L, int index, record& tracking) { - return getter::get_no_nil(L, index, tracking); + return getter>::get_no_nil(L, index, tracking); } }; template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return *getter::get_no_nil(L, index, tracking); + return getter>::get(L, index, tracking); + } + }; + + template + struct getter> { + static T& get(lua_State* L, int index, record& tracking) { + return getter{}.get(L, index, tracking); + } + }; + + template + struct getter { + static T* get(lua_State* L, int index, record& tracking) { + return getter>::get(L, index, tracking); } }; @@ -5510,13 +5630,6 @@ namespace sol { } }; - template - struct getter> { - static T& get(lua_State* L, int index, record& tracking) { - return getter{}.get(L, index, tracking); - } - }; - template struct getter> { typedef std::tuple(nullptr, 0))...> R; @@ -5783,7 +5896,7 @@ namespace sol { template static int push(lua_State* L, Args&&... args) { - return push_keyed(L, usertype_traits::metatable, std::forward(args)...); + return push_keyed(L, usertype_traits::metatable(), std::forward(args)...); } }; @@ -5808,7 +5921,7 @@ namespace sol { } static int push(lua_State* L, T* obj) { - return push_keyed(L, usertype_traits*>::metatable, obj); + return push_keyed(L, usertype_traits*>::metatable(), obj); } }; @@ -5829,7 +5942,7 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { template static int push(lua_State* L, Args&&... args) { return pusher>{}.push(L, std::forward(args)...); @@ -5861,7 +5974,7 @@ namespace sol { *fx = detail::special_destruct; detail::default_construct::construct(mem, std::forward(args)...); *pref = unique_usertype_traits::get(*mem); - if (luaL_newmetatable(L, &usertype_traits>::metatable[0]) == 1) { + if (luaL_newmetatable(L, &usertype_traits>::metatable()[0]) == 1) { set_field(L, "__gc", detail::unique_destruct

); } lua_setmetatable(L, -2); @@ -6072,8 +6185,7 @@ namespace sol { lua_CFunction cdel = detail::user_alloc_destroy; // Make sure we have a plain GC set for this data if (luaL_newmetatable(L, name) != 0) { - lua_pushlightuserdata(L, rawdata); - lua_pushcclosure(L, cdel, 1); + lua_pushcclosure(L, cdel, 0); lua_setfield(L, -2, "__gc"); } lua_setmetatable(L, -2); @@ -6083,13 +6195,13 @@ namespace sol { template , no_metatable_t, metatable_key_t>> = meta::enabler> static int push(lua_State* L, Arg&& arg, Args&&... args) { - const auto name = &usertype_traits>::user_gc_metatable[0]; + const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, std::forward(arg), std::forward(args)...); } template static int push(lua_State* L, no_metatable_t, Args&&... args) { - const auto name = &usertype_traits>::user_gc_metatable[0]; + const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, std::forward(args)...); } @@ -6100,22 +6212,22 @@ namespace sol { } static int push(lua_State* L, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable[0]; + const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, u.value); } static int push(lua_State* L, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable[0]; + const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, std::move(u.value)); } static int push(lua_State* L, no_metatable_t, const user& u) { - const auto name = &usertype_traits>::user_gc_metatable[0]; + const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, u.value); } static int push(lua_State* L, no_metatable_t, user&& u) { - const auto name = &usertype_traits>::user_gc_metatable[0]; + const auto name = &usertype_traits>::user_gc_metatable()[0]; return push_with(L, name, std::move(u.value)); } }; @@ -6137,6 +6249,8 @@ namespace sol { } static int push(lua_State* L, const char* str) { + if (str == nullptr) + return stack::push(L, nil); return push_sized(L, str, std::char_traits::length(str)); } @@ -6824,7 +6938,7 @@ namespace sol { } int last = index + count; for (int i = index; i < last; ++i) { - lua_remove(L, i); + lua_remove(L, index); } } @@ -6882,13 +6996,16 @@ namespace sol { return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); } - inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) { + inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) { + if (lua_gettop(L) == 0) { + return call_syntax::dot; + } luaL_getmetatable(L, key.c_str()); auto pn = pop_n(L, 1); - if (lua_compare(L, -1, index, LUA_OPEQ) == 1) { - return call_syntax::colon; + if (lua_compare(L, -1, index, LUA_OPEQ) != 1) { + return call_syntax::dot; } - return call_syntax::dot; + return call_syntax::colon; } inline void script(lua_State* L, const std::string& code) { @@ -6926,6 +7043,35 @@ namespace sol { // end of sol/stack.hpp +// beginning of sol/as_args.hpp + +namespace sol { + template + struct to_args_t { + T src; + }; + + template + auto as_args(Source&& source) { + return to_args_t{ std::forward(source) }; + } + + namespace stack { + template + struct pusher> { + int push(lua_State* L, const to_args_t& e) { + int p = 0; + for (const auto& i : e.src) { + p += stack::push(L, i); + } + return p; + } + }; + } +} // sol + +// end of sol/as_args.hpp + // beginning of sol/variadic_args.hpp // beginning of sol/stack_proxy.hpp @@ -6971,7 +7117,7 @@ namespace sol { public: function_result() = default; - function_result(lua_State* L, int index = -1, int returncount = 0) : L(L), index(index), returncount(returncount) { + function_result(lua_State* Ls, int idx = -1, int retnum = 0) : L(Ls), index(idx), returncount(retnum) { } function_result(const function_result&) = default; @@ -7387,12 +7533,12 @@ namespace sol { struct constructor_match { T* obj; - constructor_match(T* obj) : obj(obj) {} + constructor_match(T* o) : obj(o) {} template int operator()(types, index_value, types r, types a, lua_State* L, int, int start) const { detail::default_construct func{}; - return stack::call_into_lua(r, a, L, start, func, obj); + return stack::call_into_lua(r, a, L, start, func, obj); } }; @@ -7420,11 +7566,50 @@ namespace sol { } return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); } + + 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) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + + 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 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 + if (meta::find_in_pack_v, index_value...>::value) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + if (traits::free_arity != fxarity) { + return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } + + 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 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 + if (meta::find_in_pack_v, index_value...>::value) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + if (traits::free_arity != fxarity) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + stack::record tracking{}; + if (!stack::stack_detail::check_types{}.check(args_list(), L, start, no_panic, tracking)) { + return overload_match_arity(types(), std::index_sequence(), std::index_sequence(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + } + return matchfx(types(), index_value(), return_types(), args_list(), L, fxarity, start, std::forward(args)...); + } } // overload_detail template inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) { - return overload_detail::overload_match_arity(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); + return overload_detail::overload_match_arity_single(types(), std::make_index_sequence(), std::index_sequence<>(), std::forward(matchfx), L, fxarity, start, std::forward(args)...); } template @@ -7441,9 +7626,9 @@ namespace sol { template inline int construct(lua_State* L) { - static const auto& meta = usertype_traits::metatable; + static const auto& meta = usertype_traits::metatable(); int argcount = lua_gettop(L); - call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable[0], 1) : call_syntax::dot; + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1) : call_syntax::dot; argcount -= static_cast(syntax); T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); @@ -7572,10 +7757,11 @@ namespace sol { static int call(lua_State* L, Fx&& f) { typedef std::conditional_t::value, object_type, T> Ta; #ifdef SOL_SAFE_USERTYPE - object_type* o = static_cast(stack::get(L, 1)); - if (o == nullptr) { + auto maybeo = stack::check_get(L, 1); + if (!maybeo || maybeo.value() == nullptr) { return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)"); } + object_type* o = static_cast(maybeo.value()); return call(L, std::forward(f), *o); #else object_type& o = static_cast(*stack::get>(L, 1)); @@ -7601,13 +7787,14 @@ namespace sol { static int call_assign(std::true_type, lua_State* L, V&& f) { typedef std::conditional_t::value, object_type, T> Ta; #ifdef SOL_SAFE_USERTYPE - object_type* o = static_cast(stack::get(L, 1)); - if (o == nullptr) { + auto maybeo = stack::check_get(L, 1); + if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { return luaL_error(L, "sol: received nil for 'self' argument (bad '.' access?)"); } return luaL_error(L, "sol: received nil for 'self' argument (pass 'self' as first argument)"); } + object_type* o = static_cast(maybeo.value()); return call_assign(std::true_type(), L, f, *o); #else object_type& o = static_cast(*stack::get>(L, 1)); @@ -7659,13 +7846,14 @@ namespace sol { static int call(lua_State* L, V&& f) { typedef std::conditional_t::value, object_type, T> Ta; #ifdef SOL_SAFE_USERTYPE - object_type* o = static_cast(stack::get(L, 1)); - if (o == nullptr) { + auto maybeo = stack::check_get(L, 1); + if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { return luaL_error(L, "sol: 'self' argument is nil (bad '.' access?)"); } return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)"); } + object_type* o = static_cast(maybeo.value()); return call(L, f, *o); #else object_type& o = static_cast(*stack::get>(L, 1)); @@ -7679,9 +7867,9 @@ namespace sol { typedef constructor_list F; static int call(lua_State* L, F&) { - const auto& metakey = usertype_traits::metatable; + const auto& metakey = usertype_traits::metatable(); int argcount = lua_gettop(L); - call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable[0], 1) : call_syntax::dot; + call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1) : call_syntax::dot; argcount -= static_cast(syntax); T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); @@ -7711,7 +7899,7 @@ namespace sol { struct onmatch { template int operator()(types, index_value, types r, types a, lua_State* L, int, int start, F& f) { - const auto& metakey = usertype_traits::metatable; + const auto& metakey = usertype_traits::metatable(); T** pointerpointer = reinterpret_cast(lua_newuserdata(L, sizeof(T*) + sizeof(T))); reference userdataref(L, -1); T*& referencepointer = *pointerpointer; @@ -7726,7 +7914,7 @@ namespace sol { if (type_of(L, -1) == type::nil) { lua_pop(L, 1); std::string err = "sol: unable to get usertype metatable for "; - err += usertype_traits::name; + err += usertype_traits::name(); return luaL_error(L, err.c_str()); } lua_setmetatable(L, -2); @@ -7736,7 +7924,7 @@ namespace sol { }; static int call(lua_State* L, F& f) { - call_syntax syntax = stack::get_call_syntax(L, &usertype_traits::user_metatable[0]); + call_syntax syntax = stack::get_call_syntax(L, &usertype_traits::user_metatable()[0], 1); int syntaxval = static_cast(syntax); int argcount = lua_gettop(L) - syntaxval; return construct_match>...>(onmatch(), L, argcount, 1 + syntaxval, f); @@ -7811,20 +7999,20 @@ namespace sol { typedef meta::pop_front_type_t args_list; typedef T Ta; #ifdef SOL_SAFE_USERTYPE - object_type* po = static_cast(stack::get(L, 1)); - if (po == nullptr) { + auto maybeo = stack::check_get(L, 1); + if (!maybeo || maybeo.value() == nullptr) { if (is_variable) { return luaL_error(L, "sol: 'self' argument is nil (bad '.' access?)"); } return luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument)"); } - object_type& o = *po; + object_type* o = static_cast(maybeo.value()); #else - object_type& o = static_cast(*stack::get>(L, 1)); + object_type* o = static_cast(stack::get>(L, 1)); #endif // Safety 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, o); + return stack::call_into_lua(returns_list(), args_list(), L, boost + (is_variable ? 3 : 2), caller(), f, *o); } template @@ -8161,9 +8349,6 @@ namespace sol { template struct functor_function { typedef meta::unwrapped_t> Function; - typedef decltype(&Function::operator()) function_type; - typedef meta::function_return_t return_type; - typedef meta::function_args_t args_lists; Function fx; template @@ -8174,7 +8359,7 @@ namespace sol { } int operator()(lua_State* L) { - auto f = [&](lua_State* L) -> int { return this->call(L); }; + auto f = [&](lua_State*) -> int { return this->call(L); }; return detail::trampoline(L, f); } }; @@ -8195,7 +8380,7 @@ namespace sol { } int operator()(lua_State* L) { - auto f = [&](lua_State* L) -> int { return this->call(L); }; + auto f = [&](lua_State*) -> int { return this->call(L); }; return detail::trampoline(L, f); } }; @@ -8225,7 +8410,7 @@ namespace sol { } int operator()(lua_State* L) { - auto f = [&](lua_State* L) -> int { return this->call(L); }; + auto f = [&](lua_State*) -> int { return this->call(L); }; return detail::trampoline(L, f); } }; @@ -8271,6 +8456,75 @@ namespace sol { // beginning of sol/resolve.hpp namespace sol { + // Clang has distinct problems with constexpr arguments, + // so don't use the constexpr versions inside of clang. +#ifndef __clang__ + namespace detail { + template(Args...)>> + inline constexpr auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { + using Sig = R(Args...); + typedef meta::unqualified_t Fu; + return static_cast(&Fu::operator()); + } + + template> + inline constexpr auto resolve_f(std::true_type, F&& f) + -> decltype(resolve_i(types>(), std::forward(f))) { + return resolve_i(types>(), std::forward(f)); + } + + template + inline constexpr void resolve_f(std::false_type, F&&) { + static_assert(meta::has_deducible_signature::value, + "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + } + + template> + inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { + return resolve_f(meta::has_deducible_signature {}, std::forward(f)); + } + + template> + inline constexpr auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { + return resolve_i(types(), std::forward(f)); + } + + template + inline constexpr Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { + return mem_func_ptr; + } + + template + inline constexpr Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { + return mem_variable_ptr; + } + } // detail + + template + inline constexpr auto resolve(R fun_ptr(Args...))->R(*)(Args...) { + return fun_ptr; + } + + template + inline constexpr Sig* resolve(Sig* fun_ptr) { + return fun_ptr; + } + + template + inline constexpr auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { + return mem_ptr; + } + + template + inline constexpr Sig C::* resolve(Sig C::* mem_ptr) { + return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); + } + + template>> = meta::enabler> + inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { + return detail::resolve_i(types(), std::forward(f)); + } +#else namespace detail { template(Args...)>> inline auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { @@ -8336,6 +8590,7 @@ namespace sol { inline auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { return detail::resolve_i(types(), std::forward(f)); } +#endif } // sol // end of sol/resolve.hpp @@ -8820,7 +9075,7 @@ namespace sol { public: protected_function_result() = default; - protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status err = call_status::ok) noexcept : L(L), index(index), returncount(returncount), popcount(popcount), err(err) { + protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept : L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) { } protected_function_result(const protected_function_result&) = default; @@ -9153,7 +9408,7 @@ namespace sol { stack_proxy sp; va_iterator() : L(nullptr), index((std::numeric_limits::max)()), stacktop((std::numeric_limits::max)()) {} - va_iterator(lua_State* L, int index, int stacktop) : L(L), index(index), stacktop(stacktop), sp(L, index) {} + va_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {} reference operator*() { return stack_proxy(L, index); @@ -9264,7 +9519,7 @@ namespace sol { typedef std::reverse_iterator const_reverse_iterator; variadic_args() = default; - variadic_args(lua_State* L, int index = -1) : L(L), index(lua_absindex(L, index)), stacktop(lua_gettop(L)) {} + variadic_args(lua_State* luastate, int stackindex = -1) : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {} variadic_args(const variadic_args&) = default; variadic_args& operator=(const variadic_args&) = default; variadic_args(variadic_args&& o) : L(o.L), index(o.index), stacktop(o.stacktop) { @@ -9490,7 +9745,7 @@ namespace sol { key_type key; template - proxy(Table table, T&& key) : tbl(table), key(std::forward(key)) {} + proxy(Table table, T&& k) : tbl(table), key(std::forward(k)) {} template proxy& set(T&& item) { @@ -9564,22 +9819,26 @@ namespace sol { template inline bool operator==(T&& left, const proxy& right) { - return left == right.template get>(); + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; } template inline bool operator==(const proxy& right, T&& left) { - return right.template get>() == left; + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; } template inline bool operator!=(T&& left, const proxy& right) { - return right.template get>() != left; + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; } template inline bool operator!=(const proxy& right, T&& left) { - return right.template get>() != left; + typedef decltype(stack::get(nullptr, 0)) U; + return right.template get>() == left; } template @@ -9727,8 +9986,8 @@ namespace sol { static void walk_single_base(lua_State* L, bool& found, int& ret, string_detail::string_shim&) { if (found) return; - const char* metakey = &usertype_traits::metatable[0]; - const char* gcmetakey = &usertype_traits::gc_table[0]; + const char* metakey = &usertype_traits::metatable()[0]; + const char* gcmetakey = &usertype_traits::gc_table()[0]; const char* basewalkkey = is_index ? detail::base_class_index_propogation_key() : detail::base_class_new_index_propogation_key(); luaL_getmetatable(L, metakey); @@ -10077,7 +10336,7 @@ namespace sol { static umt_t& make_cleanup(lua_State* L, umt_t&& umx) { // ensure some sort of uniqueness static int uniqueness = 0; - std::string uniquegcmetakey = usertype_traits::user_gc_metatable; + std::string uniquegcmetakey = usertype_traits::user_gc_metatable(); // std::to_string doesn't exist in android still, with NDK, so this bullshit // is necessary // thanks, Android :v @@ -10088,7 +10347,7 @@ namespace sol { snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); ++uniqueness; - const char* gcmetakey = &usertype_traits::gc_table[0]; + const char* gcmetakey = &usertype_traits::gc_table()[0]; // Make sure userdata's memory is properly in lua first, // otherwise all the light userdata we make later will become invalid stack::push>(L, metatable_key, uniquegcmetakey, std::move(umx)); @@ -10125,16 +10384,16 @@ namespace sol { luaL_Reg* metaregs = nullptr; switch (i) { case 0: - metakey = &usertype_traits::metatable[0]; + metakey = &usertype_traits::metatable()[0]; metaregs = ref_table.data(); break; case 1: - metakey = &usertype_traits>::metatable[0]; + metakey = &usertype_traits>::metatable()[0]; metaregs = unique_table.data(); break; case 2: default: - metakey = &usertype_traits::metatable[0]; + metakey = &usertype_traits::metatable()[0]; metaregs = value_table.data(); break; } @@ -10182,7 +10441,7 @@ namespace sol { } // Now for the shim-table that actually gets assigned to the name - luaL_newmetatable(L, &usertype_traits::user_metatable[0]); + 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); @@ -10262,14 +10521,14 @@ namespace sol { const char* metakey = nullptr; switch (i) { case 0: - metakey = &usertype_traits::metatable[0]; + metakey = &usertype_traits::metatable()[0]; break; case 1: - metakey = &usertype_traits>::metatable[0]; + metakey = &usertype_traits>::metatable()[0]; break; case 2: default: - metakey = &usertype_traits::metatable[0]; + metakey = &usertype_traits::metatable()[0]; break; } luaL_getmetatable(L, metakey); @@ -10538,7 +10797,7 @@ namespace sol { static usertype_detail::simple_map& make_cleanup(lua_State* L, umt_t& umx) { static int uniqueness = 0; - std::string uniquegcmetakey = usertype_traits::user_gc_metatable; + std::string uniquegcmetakey = usertype_traits::user_gc_metatable(); // std::to_string doesn't exist in android still, with NDK, so this bullshit // is necessary // thanks, Android :v @@ -10549,8 +10808,11 @@ namespace sol { snprintf(uniquetarget, uniquegcmetakey.length(), "%d", uniqueness); ++uniqueness; - 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.varmap), std::move(umx.registrations)); + 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.varmap), std::move(umx.registrations) + ); stack_reference stackvarmap(L, -1); stack::set_field(L, gcmetakey, stackvarmap); stackvarmap.pop(); @@ -10604,14 +10866,14 @@ namespace sol { const char* metakey = nullptr; switch (i) { case 0: - metakey = &usertype_traits::metatable[0]; + metakey = &usertype_traits::metatable()[0]; break; case 1: - metakey = &usertype_traits>::metatable[0]; + metakey = &usertype_traits>::metatable()[0]; break; case 2: default: - metakey = &usertype_traits::metatable[0]; + metakey = &usertype_traits::metatable()[0]; break; } luaL_newmetatable(L, metakey); @@ -10697,7 +10959,7 @@ namespace sol { } // Now for the shim-table that actually gets pushed - luaL_newmetatable(L, &usertype_traits::user_metatable[0]); + luaL_newmetatable(L, &usertype_traits::user_metatable()[0]); stack_reference t(L, -1); for (auto& kvp : varmap.functions) { auto& first = std::get<0>(kvp); @@ -10758,6 +11020,45 @@ namespace sol { static const bool value = sizeof(test(0)) == sizeof(char); }; + template + struct has_push_back { + private: + typedef std::array one; + typedef std::array two; + + template static one test(decltype(std::declval().push_back(std::declval>()))*); + template static two test(...); + + public: + static const bool value = sizeof(test(0)) == sizeof(char); + }; + + template + struct has_clear { + private: + typedef std::array one; + typedef std::array two; + + template static one test(decltype(&C::clear)); + template static two test(...); + + public: + static const bool value = sizeof(test(0)) == sizeof(char); + }; + + template + struct has_insert { + private: + typedef std::array one; + typedef std::array two; + + template static one test(decltype(std::declval().insert(std::declval>(), std::declval>()))*); + template static two test(...); + + public: + static const bool value = sizeof(test(0)) == sizeof(char); + }; + template T& get_first(const T& t) { return std::forward(t); @@ -10786,10 +11087,12 @@ namespace sol { template struct container_usertype_metatable { + typedef meta::has_key_value_pair> is_associative; typedef meta::unqualified_t T; - typedef std::size_t K; - typedef typename T::value_type V; typedef typename T::iterator I; + typedef std::conditional_t> KV; + typedef typename KV::first_type K; + typedef typename KV::second_type V; typedef std::remove_reference_t())> IR; struct iter { @@ -10801,179 +11104,20 @@ namespace sol { static auto& get_src(lua_State* L) { #ifdef SOL_SAFE_USERTYPE - auto p = stack::get(L, 1); - if (p == nullptr) { - luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument or call on proper type)"); + auto p = stack::check_get(L, 1); + if (!p || p.value() == nullptr) { + luaL_error(L, "sol: 'self' argument is not the proper type (pass 'self' as first argument with ':' or call on proper type)"); } - return *p; + return *p.value(); #else return stack::get(L, 1); #endif } - static int real_index_call(lua_State* L) { - auto& src = get_src(L); -#ifdef SOL_SAFE_USERTYPE - auto maybek = stack::check_get(L, 2); - if (maybek) { - using std::begin; - auto it = begin(src); - K k = *maybek; - if (k <= src.size() && k > 0) { - --k; - std::advance(it, k); - return stack::push_reference(L, *it); - } - } - return stack::push(L, nil); -#else - using std::begin; - auto it = begin(src); - K k = stack::get(L, 2); - --k; - std::advance(it, k); - return stack::push_reference(L, *it); -#endif // Safety - } - - template > = meta::enabler> - static int real_new_index_call_const(std::integral_constant, lua_State* L) { - luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); - return 0; - } - - template > = meta::enabler> - static int real_new_index_call_const(std::integral_constant, lua_State* L) { - auto& src = get_src(L); -#ifdef SOL_SAFE_USERTYPE - auto maybek = stack::check_get(L, 2); - if (maybek) { - K k = *maybek; - if (k <= src.size() && k > 0) { - --k; - using std::begin; - auto it = begin(src); - std::advance(it, k); - *it = stack::get(L, 3); - } - } -#else - using std::begin; - auto it = begin(src); - K k = stack::get(L, 2); - --k; - std::advance(it, k); - *it = stack::get(L, 3); -#endif - return 0; - } - - static int real_new_index_call(lua_State* L) { - return real_new_index_call_const(meta::neg, std::is_const>>(), L); - } - - static int real_pairs_next_call(lua_State* L) { - using std::end; - iter& i = stack::get>(L, 1); - auto& source = i.source; - auto& it = i.it; - K k = stack::get(L, 2); - if (it == end(source)) { - return 0; - } - int p = stack::multi_push_reference(L, k + 1, *it); - std::advance(it, 1); - return p; - } - - static int real_pairs_call(lua_State* L) { - auto& src = get_src(L); - using std::begin; - stack::push(L, pairs_next_call); - stack::push>(L, src, begin(src)); - stack::push(L, 0); - return 3; - } - - static int real_length_call(lua_State*L) { - auto& src = get_src(L); - return stack::push(L, src.size()); - } - -#if 0 - static int real_push_back_call(lua_State*L) { - auto& src = get_src(L); - src.push_back(stack::get(L, 2)); - return 0; - } - - static int real_insert_call(lua_State*L) { - using std::begin; - auto& src = get_src(L); - src.insert(std::next(begin(src), stack::get(L, 2)), stack::get(L, 3)); - return 0; - } - - static int push_back_call(lua_State*L) { - return detail::static_trampoline<(&real_length_call)>(L); - } - - static int insert_call(lua_State*L) { - return detail::static_trampoline<(&real_insert_call)>(L); - } -#endif // Sometime later, in a distant universe... - - static int length_call(lua_State*L) { - return detail::static_trampoline<(&real_length_call)>(L); - } - - static int pairs_next_call(lua_State*L) { - return detail::static_trampoline<(&real_pairs_next_call)>(L); - } - - static int pairs_call(lua_State*L) { - return detail::static_trampoline<(&real_pairs_call)>(L); - } - - static int index_call(lua_State*L) { - return detail::static_trampoline<(&real_index_call)>(L); - } - - static int new_index_call(lua_State*L) { - return detail::static_trampoline<(&real_new_index_call)>(L); - } - }; - - template - struct container_usertype_metatable>::value>> { - typedef meta::unqualified_t T; - typedef typename T::value_type KV; - typedef typename KV::first_type K; - typedef typename KV::second_type V; - typedef typename T::iterator I; - struct iter { - T& source; - I it; - - iter(T& source, I it) : source(source), it(std::move(it)) {} - }; - - static auto& get_src(lua_State* L) { -#ifdef SOL_SAFE_USERTYPE - auto p = stack::get(L, 1); - if (p == nullptr) { - luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument or call on proper type)"); - } - return *p; -#else - return stack::get(L, 1); -#endif - } - - static int real_index_call(lua_State* L) { - auto& src = get_src(L); + static int real_index_call_associative(std::true_type, lua_State* L) { auto k = stack::check_get(L, 2); if (k) { + auto& src = get_src(L); using std::end; auto it = detail::find(src, *k); if (it != end(src)) { @@ -10981,15 +11125,73 @@ namespace sol { return stack::push_reference(L, v.second); } } + else { + auto maybename = stack::check_get(L, 2); + if (maybename) { + auto& name = *maybename; + if (name == "add") { + return stack::push(L, &add_call); + } + else if (name == "insert") { + return stack::push(L, &insert_call); + } + else if (name == "clear") { + return stack::push(L, &clear_call); + } + } + } return stack::push(L, nil); } - static int real_new_index_call_const(std::false_type, lua_State* L) { - luaL_error(L, "sol: cannot write to a const value type"); - return 0; + static int real_index_call_associative(std::false_type, lua_State* L) { + auto& src = get_src(L); + auto maybek = stack::check_get(L, 2); + if (maybek) { + using std::begin; + auto it = begin(src); + K k = *maybek; +#ifdef SOL_SAFE_USERTYPE + if (k > src.size() || k < 1) { + return stack::push(L, nil); + } +#else +#endif // Safety + --k; + std::advance(it, k); + return stack::push_reference(L, *it); + } + else { + auto maybename = stack::check_get(L, 2); + if (maybename) { + auto& name = *maybename; + if (name == "add") { + return stack::push(L, &add_call); + } + else if (name == "insert") { + return stack::push(L, &insert_call); + } + else if (name == "clear") { + return stack::push(L, &clear_call); + } + } + } + + return stack::push(L, nil); } - static int real_new_index_call_const(std::true_type, lua_State* L) { + static int real_index_call(lua_State* L) { + return real_index_call_associative(is_associative(), L); + } + + static int real_new_index_call_const(std::false_type, std::false_type, lua_State* L) { + return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); + } + + static int real_new_index_call_const(std::false_type, std::true_type, lua_State* L) { + return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)"); + } + + 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) { @@ -11006,23 +11208,47 @@ namespace sol { return 0; } - static int real_new_index_call(lua_State* L) { - return real_new_index_call_const(meta::neg>(), L); + 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 + auto maybek = stack::check_get(L, 2); + if (!maybek) { + return stack::push(L, nil); + } + K k = *maybek; +#else + K k = stack::get(L, 2); +#endif + using std::begin; + auto it = begin(src); + if (k == src.size()) { + real_add_call_push(std::integral_constant::value>(), L, src, 1); + return 0; + } + --k; + std::advance(it, k); + *it = stack::get(L, 3); + return 0; } - static int real_pairs_next_call(lua_State* L) { + static int real_new_index_call(lua_State* L) { + return real_new_index_call_const(meta::neg, std::is_const>>(), is_associative(), L); + } + + static int real_pairs_next_call_assoc(std::true_type, lua_State* L) { using std::end; iter& i = stack::get>(L, 1); auto& source = i.source; auto& it = i.it; - std::advance(it, 1); if (it == end(source)) { return 0; } - return stack::multi_push_reference(L, it->first, it->second); + int p = stack::multi_push_reference(L, it->first, it->second); + std::advance(it, 1); + return p; } - static int real_pairs_call(lua_State* L) { + static int real_pairs_call_assoc(std::true_type, lua_State* L) { auto& src = get_src(L); using std::begin; stack::push(L, pairs_next_call); @@ -11031,11 +11257,135 @@ namespace sol { return 3; } + static int real_pairs_next_call_assoc(std::false_type, lua_State* L) { + using std::end; + iter& i = stack::get>(L, 1); + auto& source = i.source; + auto& it = i.it; + K k = stack::get(L, 2); + if (it == end(source)) { + return 0; + } + int p = stack::multi_push_reference(L, k + 1, *it); + std::advance(it, 1); + return p; + } + + static int real_pairs_call_assoc(std::false_type, lua_State* L) { + auto& src = get_src(L); + using std::begin; + stack::push(L, pairs_next_call); + stack::push>(L, src, begin(src)); + stack::push(L, 0); + return 3; + } + + static int real_pairs_next_call(lua_State* L) { + return real_pairs_next_call_assoc(is_associative(), L); + } + + static int real_pairs_call(lua_State* L) { + return real_pairs_call_assoc(is_associative(), L); + } + static int real_length_call(lua_State*L) { auto& src = get_src(L); return stack::push(L, src.size()); } + static int real_add_call_insert(std::true_type, lua_State*L, T& src, int boost = 0) { + using std::end; + src.insert(end(src), stack::get(L, 2 + boost)); + return 0; + } + + static int real_add_call_insert(std::false_type, lua_State*L, T&, int = 0) { + static const std::string& s = detail::demangle(); + return luaL_error(L, "sol: cannot call insert on type %s", s.c_str()); + } + + static int real_add_call_push(std::true_type, lua_State*L, T& src, int boost = 0) { + src.push_back(stack::get(L, 2 + boost)); + return 0; + } + + 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); + } + + static int real_add_call_associative(std::true_type, lua_State* L) { + return real_insert_call(L); + } + + 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); + } + + static int real_add_call_capable(std::true_type, lua_State* L) { + return real_add_call_associative(is_associative(), L); + } + + static int real_add_call_capable(std::false_type, lua_State* L) { + static const std::string& s = detail::demangle(); + return luaL_error(L, "sol: cannot call add on type %s", s.c_str()); + } + + static int real_add_call(lua_State* L) { + return real_add_call_capable(std::integral_constant::value || detail::has_insert::value>(), L); + } + + static int real_insert_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 insert on type %s", s.c_str()); + } + + static int real_insert_call_capable(std::false_type, std::true_type, lua_State*L) { + return real_insert_call_capable(std::false_type(), std::false_type(), L); + } + + static int real_insert_call_capable(std::true_type, std::false_type, lua_State* L) { + using std::begin; + auto& src = get_src(L); + src.insert(std::next(begin(src), stack::get(L, 2)), stack::get(L, 3)); + return 0; + } + + static int real_insert_call_capable(std::true_type, std::true_type, lua_State* L) { + return real_new_index_call(L); + } + + static int real_insert_call(lua_State*L) { + return real_insert_call_capable(std::integral_constant::value>(), is_associative(), L); + } + + static int real_clear_call_capable(std::false_type, lua_State* L) { + static const std::string& s = detail::demangle(); + return luaL_error(L, "sol: cannot call clear on type %s", s.c_str()); + } + + static int real_clear_call_capable(std::true_type, lua_State* L) { + auto& src = get_src(L); + src.clear(); + return 0; + } + + static int real_clear_call(lua_State*L) { + return real_clear_call_capable(std::integral_constant::value>(), L); + } + + static int add_call(lua_State*L) { + return detail::static_trampoline<(&real_add_call)>(L); + } + + static int insert_call(lua_State*L) { + return detail::static_trampoline<(&real_insert_call)>(L); + } + + static int clear_call(lua_State*L) { + return detail::static_trampoline<(&real_clear_call)>(L); + } + static int length_call(lua_State*L) { return detail::static_trampoline<(&real_length_call)>(L); } @@ -11058,67 +11408,80 @@ namespace sol { }; namespace stack { + namespace stack_detail { + template + inline auto container_metatable() { + typedef container_usertype_metatable> meta_cumt; + std::array reg = { { + { "__index", &meta_cumt::index_call }, + { "__newindex", &meta_cumt::new_index_call }, + { "__pairs", &meta_cumt::pairs_call }, + { "__ipairs", &meta_cumt::pairs_call }, + { "__len", &meta_cumt::length_call }, + { "clear", &meta_cumt::clear_call }, + { "insert", &meta_cumt::insert_call }, + { "add", &meta_cumt::add_call }, + std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy }, + { nullptr, nullptr } + } }; + return reg; + } - template - struct pusher, meta::neg, std::is_base_of>>>::value>> { - typedef container_usertype_metatable cumt; - static int push(lua_State* L, const T& cont) { - auto fx = [&L]() { - const char* metakey = &usertype_traits::metatable[0]; + template + inline auto container_metatable_behind() { + typedef container_usertype_metatable> meta_cumt; + std::array reg = { { + { "__index", &meta_cumt::index_call }, + { "__newindex", &meta_cumt::new_index_call }, + { nullptr, nullptr } + } }; + return reg; + } + + template + struct metatable_setup { + lua_State* L; + + metatable_setup(lua_State* L) : L(L) {} + + void operator()() { + static const auto reg = container_metatable(); + static const auto containerreg = container_metatable_behind(); + static const char* metakey = &usertype_traits::metatable()[0]; + if (luaL_newmetatable(L, metakey) == 1) { - luaL_Reg reg[] = { - { "__index", &cumt::index_call }, - { "__newindex", &cumt::new_index_call }, - { "__pairs", &cumt::pairs_call }, - { "__len", &cumt::length_call }, - { "__gc", &detail::usertype_alloc_destroy }, - { nullptr, nullptr } - }; - luaL_setfuncs(L, reg, 0); + stack_reference metatable(L, -1); + luaL_setfuncs(L, reg.data(), 0); + + lua_createtable(L, 0, static_cast(containerreg.size())); + stack_reference metabehind(L, -1); + luaL_setfuncs(L, containerreg.data(), 0); + + stack::set_field(L, metatable_key, metabehind, metatable.stack_index()); + metabehind.pop(); } lua_setmetatable(L, -2); - }; + } + }; + } + + template + struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + static int push(lua_State* L, const T& cont) { + stack_detail::metatable_setup fx(L); return pusher>{}.push_fx(L, fx, cont); } static int push(lua_State* L, T&& cont) { - auto fx = [&L]() { - const char* metakey = &usertype_traits::metatable[0]; - if (luaL_newmetatable(L, metakey) == 1) { - luaL_Reg reg[] = { - { "__index", &cumt::index_call }, - { "__newindex", &cumt::new_index_call }, - { "__pairs", &cumt::pairs_call }, - { "__len", &cumt::length_call }, - { "__gc", &detail::usertype_alloc_destroy }, - { nullptr, nullptr } - }; - luaL_setfuncs(L, reg, 0); - } - lua_setmetatable(L, -2); - }; + stack_detail::metatable_setup fx(L); return pusher>{}.push_fx(L, fx, std::move(cont)); } }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { - typedef container_usertype_metatable cumt; + struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { static int push(lua_State* L, T* cont) { - auto fx = [&L]() { - const char* metakey = &usertype_traits*>::metatable[0]; - if (luaL_newmetatable(L, metakey) == 1) { - luaL_Reg reg[] = { - { "__index", &cumt::index_call }, - { "__newindex", &cumt::new_index_call }, - { "__pairs", &cumt::pairs_call }, - { "__len", &cumt::length_call }, - { nullptr, nullptr } - }; - luaL_setfuncs(L, reg, 0); - } - lua_setmetatable(L, -2); - }; + stack_detail::metatable_setup>*> fx(L); return pusher>{}.push_fx(L, fx, cont); } }; @@ -11295,8 +11658,8 @@ namespace sol { namespace sol { namespace detail { template - struct clean { lua_State* L; clean(lua_State* L) : L(L) {} ~clean() { lua_pop(L, static_cast(n)); } }; - struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* L, int& n) : L(L), n(n) {} ~ref_clean() { lua_pop(L, static_cast(n)); } }; + struct clean { lua_State* L; clean(lua_State* luastate) : L(luastate) {} ~clean() { lua_pop(L, static_cast(n)); } }; + struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* luastate, int& n) : L(luastate), n(n) {} ~ref_clean() { lua_pop(L, static_cast(n)); } }; inline int fail_on_newindex(lua_State* L) { return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); } @@ -11508,7 +11871,7 @@ namespace sol { template basic_table_core& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name, user); + return set_usertype(usertype_traits::name(), user); } template @@ -11683,6 +12046,7 @@ namespace sol { template static inline table create_with(lua_State* L, Args&&... args) { + static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list."); static const int narr = static_cast(meta::count_2_for_pack::value); return create(L, narr, static_cast((sizeof...(Args) / 2) - narr), std::forward(args)...); } @@ -11720,6 +12084,10 @@ namespace sol { static const int narr = static_cast(meta::count_2_for_pack::value); return create(std::forward(name), narr, sizeof...(Args) / 2 - narr, std::forward(args)...); } + + ~basic_table_core() { + + } }; } // sol @@ -11778,7 +12146,7 @@ namespace sol { public: load_result() = default; - load_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, load_status err = load_status::ok) noexcept : L(L), index(index), returncount(returncount), popcount(popcount), err(err) { + load_result(lua_State* Ls, int stackindex = -1, int retnum = 0, int popnum = 0, load_status lerr = load_status::ok) noexcept : L(Ls), index(stackindex), returncount(retnum), popcount(popnum), err(lerr) { } load_result(const load_result&) = default; @@ -11825,7 +12193,7 @@ namespace sol { template decltype(auto) call(Args&&... args) { - return get().template call(std::forward(args)...); + return get().template call(std::forward(args)...); } template @@ -11925,10 +12293,14 @@ namespace sol { typedef global_table::iterator iterator; typedef global_table::const_iterator const_iterator; - state_view(lua_State* L) : - L(L), - reg(L, LUA_REGISTRYINDEX), - global(L, detail::global_) { + state_view(lua_State* Ls) : + L(Ls), + reg(Ls, LUA_REGISTRYINDEX), + global(Ls, detail::global_) { + + } + + state_view(this_state Ls) : state_view(Ls.L){ } @@ -11966,7 +12338,7 @@ namespace sol { lua_pop(L, 1); #endif // Lua 5.2+ only break; -#endif // Not LuaJIT +#endif // Not LuaJIT - comes builtin case lib::string: luaL_requiref(L, "string", luaopen_string, 1); lua_pop(L, 1); @@ -11983,11 +12355,11 @@ namespace sol { #ifdef SOL_LUAJIT luaL_requiref(L, "bit32", luaopen_bit, 1); lua_pop(L, 1); -#elif SOL_LUA_VERSION == 502 +#elif (SOL_LUA_VERSION == 502) || defined(LUA_COMPAT_BITLIB) || defined(LUA_COMPAT_5_2) luaL_requiref(L, "bit32", luaopen_bit32, 1); lua_pop(L, 1); #else -#endif // Lua 5.2 only (deprecated in 5.3 (503)) +#endif // Lua 5.2 only (deprecated in 5.3 (503)) (Can be turned on with Compat flags) break; case lib::io: luaL_requiref(L, "io", luaopen_io, 1); @@ -12011,13 +12383,13 @@ namespace sol { #ifdef SOL_LUAJIT luaL_requiref(L, "ffi", luaopen_ffi, 1); lua_pop(L, 1); -#endif +#endif // LuaJIT only break; case lib::jit: #ifdef SOL_LUAJIT luaL_requiref(L, "jit", luaopen_jit, 1); lua_pop(L, 1); -#endif +#endif // LuaJIT Only break; case lib::count: default: @@ -12039,18 +12411,30 @@ namespace sol { return require_core(key, [this, &filename]() {stack::script_file(L, filename); }, create_global); } + protected_function_result do_string(const std::string& code) { + sol::protected_function pf = load(code); + return pf(); + } + + protected_function_result do_file(const std::string& filename) { + sol::protected_function pf = load_file(filename); + return pf(); + } + function_result script(const std::string& code) { - int index = (::std::max)(lua_gettop(L), 1); + int index = lua_gettop(L); stack::script(L, code); - int returns = lua_gettop(L) - (index - 1); - return function_result(L, index, returns); + int postindex = lua_gettop(L); + int returns = postindex - index; + return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); } function_result script_file(const std::string& filename) { - int index = (::std::max)(lua_gettop(L), 1); + int index = lua_gettop(L); stack::script_file(L, filename); - int returns = lua_gettop(L) - (index - 1); - return function_result(L, index, returns); + int postindex = lua_gettop(L); + int returns = postindex - index; + return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); } load_result load(const std::string& code) { @@ -12134,7 +12518,7 @@ namespace sol { template state_view& set_usertype(usertype& user) { - return set_usertype(usertype_traits::name, user); + return set_usertype(usertype_traits::name(), user); } template @@ -12283,11 +12667,32 @@ namespace sol { return -1; #else const char* message = lua_tostring(L, -1); - std::string err = message ? message : "An unexpected error occurred and forced the lua state to call atpanic"; - throw error(err); + if (message) { + std::string err = message; + lua_pop(L, 1); + throw error(err); + } + throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic")); #endif } + inline int default_error_handler(lua_State*L) { + using namespace sol; + std::string msg = "An unknown error has triggered the default error handler"; + optional maybetopmsg = stack::check_get(L, 1); + if (maybetopmsg) { + const string_detail::string_shim& topmsg = maybetopmsg.value(); + msg.assign(topmsg.c_str(), topmsg.size()); + } + luaL_traceback(L, L, msg.c_str(), 1); + optional maybetraceback = stack::check_get(L, -1); + if (maybetraceback) { + const string_detail::string_shim& traceback = maybetraceback.value(); + msg.assign(traceback.c_str(), traceback.size()); + } + return stack::push(L, msg); + } + class state : private std::unique_ptr, public state_view { private: typedef std::unique_ptr unique_base; @@ -12301,6 +12706,7 @@ namespace sol { state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close), state_view(unique_base::get()) { set_panic(panic); + sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler)); stack::luajit_exception_handler(unique_base::get()); } @@ -12315,6 +12721,49 @@ namespace sol { // beginning of sol/thread.hpp namespace sol { + struct lua_thread_state { + lua_State* L; + operator lua_State* () const { + return L; + } + lua_State* operator-> () const { + return L; + } + }; + + namespace stack { + + template <> + struct pusher { + int push(lua_State*, lua_thread_state lts) { + lua_pushthread(lts.L); + return 1; + } + }; + + template <> + struct getter { + lua_thread_state get(lua_State* L, int index = -1) { + lua_thread_state lts{ lua_tothread(L, index) }; + return lts; + } + }; + + template <> + struct check_getter { + template + optional get(lua_State* L, int index, Handler&& handler) { + lua_thread_state lts{ lua_tothread(L, index) }; + if (lts.L == nullptr) { + handler(L, index, type::thread, type_of(L, index)); + return nullopt; + } + return lts; + } + }; + + } + class thread : public reference { public: thread() noexcept = default; @@ -12329,11 +12778,25 @@ namespace sol { type_assert(L, index, type::thread); #endif // Safety } + thread(lua_State* L, lua_State* actualthread) : thread(L, lua_thread_state{ actualthread }) {} + thread(lua_State* L, sol::this_state actualthread) : thread(L, lua_thread_state{ actualthread.L }) {} + thread(lua_State* L, lua_thread_state actualthread) : reference(L, -stack::push(L, actualthread)) { +#ifdef SOL_CHECK_ARGUMENTS + type_assert(L, -1, type::thread); +#endif // Safety + lua_pop(L, 1); + } state_view state() const { return state_view(this->thread_state()); } + bool is_main_thread() const { + int ismainthread = lua_pushthread(this->thread_state()); + lua_pop(this->thread_state(), 1); + return ismainthread == 1; + } + lua_State* thread_state() const { auto pp = stack::push_pop(*this); lua_State* lthread = lua_tothread(lua_state(), -1);