memory tracker and separate-definition ADL customization points, inspired by Olek and Aurailus

This commit is contained in:
ThePhD 2019-09-01 02:27:58 -04:00
parent e8649d276b
commit 9294afc082
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
13 changed files with 427 additions and 9 deletions

View File

@ -36,6 +36,9 @@ if (SOL2_INTEROP_EXAMPLES OR SOL2_INTEROP_EXAMPLES_SINGLE OR SOL2_INTEROP_EXAMPL
add_subdirectory(interop/luwra)
endif()
# # In-depth customization example
add_subdirectory(customization)
# # Utility assert.hpp "library"
add_library(sol2_assert INTERFACE)
add_library(sol2::assert ALIAS sol2_assert)
@ -95,7 +98,7 @@ function (MAKE_EXAMPLE example_source_file example_suffix target_sol)
# and we have time to audit the entire lib
# for all uses of `detail::swallow`...
#target_compile_options(${example_name}
# PRIVATE -Wcomma)
# PRIVATE -Wcomma)
endif()
endif()

View File

@ -0,0 +1,68 @@
# # # # sol3
# The MIT License (MIT)
#
# Copyright (c) 2013-2019 Rapptz, ThePhD, and contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# # # sol3 Customization Examples
function (MAKE_CUSTOMIZATION_EXAMPLE example_suffix target_sol)
set(customization_example_name customization_to_table${example_suffix})
add_executable(${customization_example_name} source/main.cpp source/lua_interop.cpp source/lua_zm_interop.cpp)
set_target_properties(${customization_example_name}
PROPERTIES
OUTPUT_NAME "${customization_example_name}"
EXPORT_NAME sol2::${customization_example_name})
if (MSVC)
target_compile_options(${customization_example_name}
PRIVATE /std:c++latest /EHsc "$<$<CONFIG:Debug>:/MDd>"
"$<$<CONFIG:Release>:/MD>"
"$<$<CONFIG:RelWithDebInfo>:/MD>"
"$<$<CONFIG:MinSizeRel>:/MD>")
target_compile_definitions(${customization_example_name}
PRIVATE UNICODE _UNICODE
_CRT_SECURE_NO_WARNINGS _CRT_SECURE_NO_DEPRECATE)
else()
target_compile_options(${customization_example_name}
PRIVATE -std=c++1z
-ftemplate-backtrace-limit=0
-Wno-unknown-warning -Wno-unknown-warning-option
-Wall -Wpedantic -Werror -pedantic -pedantic-errors
-Wno-noexcept-type)
endif()
target_link_libraries(${customization_example_name}
PRIVATE Threads::Threads ${target_sol} ${LUA_LIBRARIES})
target_include_directories(${customization_example_name}
PRIVATE include)
endfunction()
if (SOL2_EXAMPLES)
MAKE_CUSTOMIZATION_EXAMPLE("" sol2::sol2)
endif()
if (SOL2_EXAMPLES_SINGLE)
MAKE_CUSTOMIZATION_EXAMPLE(".single" sol2::sol2_single)
endif()
if (SOL2_EXAMPLES_SINGLE_GENERATED)
MAKE_CUSTOMIZATION_EXAMPLE(".single.generated" sol2::sol2_single_generated)
endif()

View File

@ -0,0 +1,25 @@
#pragma once
#ifndef PROGRAM_ENTITY_HPP
#define PROGRAM_ENTITY_HPP
#include <zm/vec3.hpp>
class entity {
private:
zm::vec3 position_;
public:
entity() {
this->position_ = { 1, 1, 1 };
}
zm::vec3 get_position() const {
return this->position_;
}
void set_position(zm::vec3 v) {
this->position_ = v;
}
};
#endif // PROGRAM_ENTITY_HPP

View File

@ -0,0 +1,13 @@
#pragma once
#ifndef PROGRAM_LUA_INTEROP_HPP
#define PROGRAM_LUA_INTEROP_HPP
#include <lua_zm_interop.hpp>
#define SOL_ALL_SAFETIES_ON 1
#include <sol/forward.hpp>
void register_lua(sol::state& lua);
#endif // PROGRAM_LUA_INTEROP_HPP

View File

@ -0,0 +1,19 @@
#pragma once
#ifndef PROGRAM_LUA_ZM_INTEROP_HPP
#define PROGRAM_LUA_ZM_INTEROP_HPP
#define SOL_ALL_SAFETIES_ON 1
#include <sol/forward.hpp>
#include <zm/vec3.hpp>
#include <functional>
bool sol_lua_check(sol::types<zm::vec3>, lua_State* L, int index, std::function<sol::check_handler_type> handler, sol::stack::record& tracking);
zm::vec3 sol_lua_get(sol::types<zm::vec3>, lua_State* L, int index, sol::stack::record& tracking);
int sol_lua_push(sol::types<zm::vec3>, lua_State* L, const zm::vec3& v);
#endif // PROGRAM_LUA_ZM_INTEROP_HPP

View File

@ -0,0 +1,64 @@
#pragma once
#ifndef ZM_VEC3_HPP
#define ZM_VEC3_HPP
#include <cstddef>
namespace zm {
struct vec3 {
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
#pragma clang diagnostic ignored "-Wnested-anon-types"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
#pragma warning(disable : 4324) // structure was padded due to alignment specifier
#endif
union {
float elements[3];
struct {
union {
float x, r, s;
};
union {
float y, g, t;
};
union {
float z, b, p;
};
};
};
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif
constexpr float* data() {
return elements;
}
constexpr const float* data() const {
return this->elements;
}
constexpr float& operator[](std::size_t i) {
return this->elements[i];
}
constexpr const float& operator[](std::size_t i) const {
return this->elements[i];
}
};
} // namespace zm
#endif // ZM_VEC3_HPP

View File

@ -0,0 +1,10 @@
#include <lua_interop.hpp>
#include <entity.hpp>
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
void register_lua(sol::state& lua) {
lua.new_usertype<entity>("entity", "position", sol::property(&entity::get_position, &entity::set_position));
}

View File

@ -0,0 +1,31 @@
#include <lua_zm_interop.hpp>
#include <zm/vec3.hpp>
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
bool sol_lua_check(sol::types<zm::vec3>, lua_State* L, int index, std::function<sol::check_handler_type> handler, sol::stack::record& tracking) {
// use sol's method for checking
// specifically for a table
return sol::stack::check<sol::lua_table>(L, index, handler, tracking);
}
zm::vec3 sol_lua_get(sol::types<zm::vec3>, lua_State* L, int index, sol::stack::record& tracking) {
sol::lua_table vec3table = sol::stack::get<sol::lua_table>(L, index, tracking);
float x = vec3table["x"];
float y = vec3table["y"];
float z = vec3table["z"];
return zm::vec3{ x, y, z };
}
int sol_lua_push(sol::types<zm::vec3>, lua_State* L, const zm::vec3& v) {
// create table
sol::state_view lua(L);
sol::table vec3table = sol::table::create_with(L, "x", v.x, "y", v.y, "z", v.z);
// use base sol method to
// push the table
int amount = sol::stack::push(L, vec3table);
// return # of things pushed onto stack
return amount;
}

View File

@ -0,0 +1,39 @@
#include <lua_interop.hpp>
#include <entity.hpp>
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include <iostream>
int main(int, char* []) {
std::cout << "=== customization: vec3 as table ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
std::cout << "registering entities into Lua ..." << std::endl;
register_lua(lua);
std::cout << "running script ..." << std::endl;
const auto& script = R"lua(
local e = entity.new()
local pos = e.position
print("pos type", type(pos))
print("pos", pos.x, pos.y, pos.z)
e.position = { x = 52, y = 5.5, z = 47.5 }
local new_pos = e.position
print("pos", pos.x, pos.y, pos.z)
print("new_pos", new_pos.x, new_pos.y, new_pos.z)
)lua";
sol::optional<sol::error> result = lua.safe_script(script);
if (result.has_value()) {
std::cerr << "Something went horribly wrong: " << result.value().what() << std::endl;
}
std::cout << "finishing ..." << std::endl;
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,132 @@
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include <cstddef>
#include <cstdlib>
class memory_tracker {
public:
// 10 MB or something?
// idk whatever
inline static constexpr std::size_t arbitrary_default_limit = 1024 * 1024 * 10;
memory_tracker() : memory_tracker(arbitrary_default_limit) {
}
memory_tracker(std::size_t maximum_memory) : used(0), limit(maximum_memory), n_threads(0), n_tables(0), n_functions(0), n_userdata(0), n_strings(0) {
}
std::size_t currently_used() const {
return used;
}
std::size_t memory_limit() const {
return limit;
}
static void* allocate(void* memory_tracker_ud, void* ptr, size_t object_code, size_t nsize) {
memory_tracker& self = (*static_cast<memory_tracker*>(memory_tracker_ud));
return self.alloc(ptr, object_code, nsize);
}
private:
void* alloc(void* ptr, size_t original_block_size_or_code, size_t new_block_size) {
std::size_t original_block_size = original_block_size_or_code;
if (ptr == nullptr) {
// object code!
sol::type object_type = static_cast<sol::type>(original_block_size_or_code);
switch (object_type) {
case sol::type::function:
++n_functions;
break;
case sol::type::string:
++n_strings;
break;
case sol::type::userdata:
++n_userdata;
break;
case sol::type::table:
++n_tables;
break;
case sol::type::thread:
++n_threads;
break;
default:
// not a clue, fam
break;
}
// because it is an object code,
// it tells us literally nothing about
// the old block size,
// so set that to 0
original_block_size = 0;
}
if (new_block_size == 0) {
// Lua expects us to act like a "free"
// when the new block size is 0
std::free(ptr);
used -= original_block_size;
return nullptr;
}
// did we hit the limit?
std::size_t memory_differntial = new_block_size - original_block_size;
std::size_t desired_use = used + memory_differntial;
if (desired_use > limit) {
// tell the Lua Virtual Machine
// to toss off (by returning nullptr)
return nullptr;
}
// alright now we have to expand this shit
// guess we use C's realloc
ptr = std::realloc(ptr, new_block_size);
if (ptr != nullptr) {
// alright, we successfully allocated some space
// track it
used = desired_use;
}
// even if we're null, let Lua crash and burn for us
return ptr;
}
std::size_t used;
std::size_t limit;
std::size_t n_threads;
std::size_t n_tables;
std::size_t n_functions;
std::size_t n_userdata;
std::size_t n_strings;
};
struct my_type {
int a = 24;
bool b = false;
double d = 3.5;
};
#include <iostream>
int main() {
std::cout << "=== memory tracker ===" << std::endl;
memory_tracker box;
std::cout << "memory at start: " << box.currently_used() << " bytes / " << box.memory_limit() << " bytes" << std::endl;
sol::state lua(&sol::default_at_panic, &memory_tracker::allocate, &box);
lua.open_libraries(sol::lib::base);
std::cout << "memory after state creation: " << box.currently_used() << " bytes / " << box.memory_limit() << " bytes" << std::endl;
// trigger some allocations
lua.new_usertype<my_type>("my_type", "a", &my_type::a, "b", &my_type::b, "d", &my_type::d);
lua["f"] = [](std::string s) { return s + " woof!"; };
std::cout << "memory after function and usertype setup: " << box.currently_used() << " bytes / " << box.memory_limit() << " bytes" << std::endl;
lua.safe_script("print(f('bark'))");
lua.safe_script("local obj = my_type.new() print(obj.a, obj.b, obj.c) obj.b = true print(obj.a, obj.b, obj.c)");
std::cout << "memory at end: " << box.currently_used() << " bytes / " << box.memory_limit() << " bytes" << std::endl;
return 0;
}

View File

@ -28,17 +28,20 @@
#include <utility>
#include <type_traits>
#include <string_view>
#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA
struct lua_State;
#else
extern "C" {
struct lua_State;
struct lua_State;
}
#endif // C++ Mangling for Lua vs. Not
namespace sol {
enum class type;
class stateless_reference;
template <bool b>
class basic_reference;
@ -235,6 +238,8 @@ namespace sol {
class optional<T&>;
#endif
using check_handler_type = int(lua_State*, int, type, type, const char*);
} // namespace sol
#define SOL_BASE_CLASSES(T, ...) \

View File

@ -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 2019-08-28 04:16:59.509251 UTC
// This header was generated with sol (revision )
// Generated 2019-09-01 06:26:40.948435 UTC
// This header was generated with sol v3.0.3 (revision e8649d2)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -250,17 +250,20 @@
#include <utility>
#include <type_traits>
#include <string_view>
#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA
struct lua_State;
#else
extern "C" {
struct lua_State;
struct lua_State;
}
#endif // C++ Mangling for Lua vs. Not
namespace sol {
enum class type;
class stateless_reference;
template <bool b>
class basic_reference;
@ -457,6 +460,8 @@ namespace sol {
class optional<T&>;
#endif
using check_handler_type = int(lua_State*, int, type, type, const char*);
} // namespace sol
#define SOL_BASE_CLASSES(T, ...) \

View File

@ -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 2019-08-28 04:16:58.879902 UTC
// This header was generated with sol (revision )
// Generated 2019-09-01 06:26:40.339961 UTC
// This header was generated with sol v3.0.3 (revision e8649d2)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -276,17 +276,20 @@
#include <utility>
#include <type_traits>
#include <string_view>
#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA
struct lua_State;
#else
extern "C" {
struct lua_State;
struct lua_State;
}
#endif // C++ Mangling for Lua vs. Not
namespace sol {
enum class type;
class stateless_reference;
template <bool b>
class basic_reference;
@ -483,6 +486,8 @@ namespace sol {
class optional<T&>;
#endif
using check_handler_type = int(lua_State*, int, type, type, const char*);
} // namespace sol
#define SOL_BASE_CLASSES(T, ...) \
@ -1256,7 +1261,6 @@ namespace sol {
#include <string>
#if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES
#include <string_view>
#endif // C++17 features
#include <functional>
#if defined(SOL_USE_BOOST) && SOL_USE_BOOST