langsmoke/ref_cpp

3827 lines
135 KiB
Plaintext

#ifndef SOL_STACK_CORE_HPP
#define SOL_STACK_CORE_HPP
#include <vector>
#include <bitset>
#include <forward_list>
#include <string>
#include <limits>
#include <algorithm>
#include <sstream>
#include <optional>
#include <type_traits>
namespace sol {
namespace detail {
struct with_function_tag { };
struct as_reference_tag { };
template <typename T>
struct as_pointer_tag { };
template <typename T>
struct as_value_tag { };
template <typename T>
struct as_unique_tag { };
template <typename T>
struct as_table_tag { };
template <typename Tag>
inline constexpr bool is_tagged_v
= meta::is_specialization_of_v<Tag,
detail::
as_pointer_tag> || meta::is_specialization_of_v<Tag, as_value_tag> || meta::is_specialization_of_v<Tag, as_unique_tag> || meta::is_specialization_of_v<Tag, as_table_tag> || std::is_same_v<Tag, as_reference_tag> || std::is_same_v<Tag, with_function_tag>;
using lua_reg_table = luaL_Reg[64];
using unique_destructor = void (*)(void*);
using unique_tag = detail::inheritance_unique_cast_function;
inline void* alloc_newuserdata(lua_State* L, std::size_t bytesize) {
#if SOL_LUA_VERSION_I_ >= 504
return lua_newuserdatauv(L, bytesize, 1);
#else
return lua_newuserdata(L, bytesize);
#endif
}
constexpr std::uintptr_t align(std::size_t alignment, std::uintptr_t ptr, std::size_t& space) {
std::uintptr_t offby = static_cast<std::uintptr_t>(ptr % alignment);
std::uintptr_t padding = (alignment - offby) % alignment;
ptr += padding;
space -= padding;
return ptr;
}
inline void* align(std::size_t alignment, void* ptr, std::size_t& space) {
return reinterpret_cast<void*>(align(alignment, reinterpret_cast<std::uintptr_t>(ptr), space));
}
constexpr std::uintptr_t align_one(std::size_t alignment, std::size_t size, std::uintptr_t ptr) {
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(alignment, ptr, space) + size;
}
template <typename... Args>
constexpr std::size_t aligned_space_for(std::uintptr_t ptr) {
std::uintptr_t end = ptr;
((end = align_one(alignof(Args), sizeof(Args), end)), ...);
return static_cast<std::size_t>(end - ptr);
}
template <typename... Args>
constexpr std::size_t aligned_space_for() {
static_assert(sizeof...(Args) > 0);
constexpr std::size_t max_arg_alignment = (std::max)({ alignof(Args)... });
if constexpr (max_arg_alignment <= alignof(std::max_align_t)) {
// If all types are `good enough`, simply calculate alignment in case of the worst allocator
std::size_t worst_required_size = 0;
for (std::size_t ptr = 0; ptr < max_arg_alignment; ptr++) {
worst_required_size = (std::max)(worst_required_size, aligned_space_for<Args...>(ptr));
}
return worst_required_size;
}
else {
// For over-aligned types let's assume that every Arg in Args starts at the worst aligned address
return (aligned_space_for<Args>(0x1) + ...);
}
}
inline void* align_usertype_pointer(void* ptr) {
using use_align = std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of<void*>::value > 1)
#endif
>;
if (!use_align::value) {
return ptr;
}
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of<void*>::value, ptr, space);
}
template <bool pre_aligned = false, bool pre_shifted = false>
void* align_usertype_unique_destructor(void* ptr) {
using use_align = std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of<unique_destructor>::value > 1)
#endif
>;
if (!pre_aligned) {
ptr = align_usertype_pointer(ptr);
}
if (!pre_shifted) {
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(void*));
}
if (!use_align::value) {
return static_cast<void*>(static_cast<void**>(ptr) + 1);
}
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of<unique_destructor>::value, ptr, space);
}
template <bool pre_aligned = false, bool pre_shifted = false>
void* align_usertype_unique_tag(void* ptr) {
using use_align = std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of<unique_tag>::value > 1)
#endif
>;
if (!pre_aligned) {
ptr = align_usertype_unique_destructor(ptr);
}
if (!pre_shifted) {
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_destructor));
}
if (!use_align::value) {
return ptr;
}
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of<unique_tag>::value, ptr, space);
}
template <typename T, bool pre_aligned = false, bool pre_shifted = false>
void* align_usertype_unique(void* ptr) {
typedef std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of_v<T> > 1)
#endif
>
use_align;
if (!pre_aligned) {
ptr = align_usertype_unique_tag(ptr);
}
if (!pre_shifted) {
ptr = static_cast<void*>(static_cast<char*>(ptr) + sizeof(unique_tag));
}
if (!use_align::value) {
return ptr;
}
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of_v<T>, ptr, space);
}
template <typename T>
void* align_user(void* ptr) {
typedef std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of_v<T> > 1)
#endif
>
use_align;
if (!use_align::value) {
return ptr;
}
std::size_t space = (std::numeric_limits<std::size_t>::max)();
return align(std::alignment_of_v<T>, ptr, space);
}
template <typename T>
T** usertype_allocate_pointer(lua_State* L) {
typedef std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of<T*>::value > 1)
#endif
>
use_align;
if (!use_align::value) {
T** pointerpointer = static_cast<T**>(alloc_newuserdata(L, sizeof(T*)));
return pointerpointer;
}
constexpr std::size_t initial_size = aligned_space_for<T*>();
std::size_t allocated_size = initial_size;
void* unadjusted = alloc_newuserdata(L, initial_size);
void* adjusted = align(std::alignment_of<T*>::value, unadjusted, allocated_size);
if (adjusted == nullptr) {
// trash allocator can burn in hell
lua_pop(L, 1);
// luaL_error(L, "if you are the one that wrote this allocator you should feel bad for doing a
// worse job than malloc/realloc and should go read some books, yeah?");
luaL_error(L, , detail::demangle<T*>().data());
}
return static_cast<T**>(adjusted);
}
template <typename T>
T* usertype_allocate(lua_State* L) {
typedef std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of<T*>::value > 1 || std::alignment_of_v<T> > 1)
#endif
>
use_align;
if (!use_align::value) {
T** pointerpointer = static_cast<T**>(alloc_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& pointerreference = *pointerpointer;
T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);
pointerreference = allocationtarget;
return allocationtarget;
}
constexpr std::size_t initial_size = aligned_space_for<T*, T>();
void* pointer_adjusted;
void* data_adjusted;
bool result
= attempt_alloc(L, std::alignment_of_v<T*>, sizeof(T*), std::alignment_of_v<T>, initial_size, pointer_adjusted, data_adjusted);
if (!result) {
if (pointer_adjusted == nullptr) {
luaL_error(L, , detail::demangle<T>().c_str());
}
else {
luaL_error(L, , detail::demangle<T>().c_str());
}
return nullptr;
}
T** pointerpointer = reinterpret_cast<T**>(pointer_adjusted);
T*& pointerreference = *pointerpointer;
T* allocationtarget = reinterpret_cast<T*>(data_adjusted);
pointerreference = allocationtarget;
return allocationtarget;
}
template <typename T, typename Real>
Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) {
typedef std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of<T*>::value > 1 || std::alignment_of<unique_tag>::value > 1 || std::alignment_of<unique_destructor>::value > 1
|| std::alignment_of<Real>::value > 1)
#endif
>
use_align;
if (!use_align::value) {
pref = static_cast<T**>(alloc_newuserdata(L, sizeof(T*) + sizeof(detail::unique_destructor) + sizeof(unique_tag) + sizeof(Real)));
dx = static_cast<detail::unique_destructor*>(static_cast<void*>(pref + 1));
id = static_cast<unique_tag*>(static_cast<void*>(dx + 1));
Real* mem = static_cast<Real*>(static_cast<void*>(id + 1));
return mem;
}
constexpr std::size_t initial_size = aligned_space_for<T*, unique_destructor, unique_tag, Real>();
void* pointer_adjusted = nullptr;
void* dx_adjusted = nullptr;
void* id_adjusted = nullptr;
void* data_adjusted = nullptr;
bool result = attempt_alloc_unique(L,
std::alignment_of_v<T*>,
sizeof(T*),
std::alignment_of_v<Real>,
initial_size,
pointer_adjusted,
dx_adjusted,
id_adjusted,
data_adjusted);
if (!result) {
if (pointer_adjusted == nullptr) {
luaL_error(L, , detail::demangle<T>().c_str());
}
else if (dx_adjusted == nullptr) {
luaL_error(L, , detail::demangle<T>().c_str());
}
else {
luaL_error(L, , detail::demangle<T>().c_str());
}
return nullptr;
}
pref = static_cast<T**>(pointer_adjusted);
dx = static_cast<detail::unique_destructor*>(dx_adjusted);
id = static_cast<unique_tag*>(id_adjusted);
Real* mem = static_cast<Real*>(data_adjusted);
return mem;
}
template <typename T>
T* user_allocate(lua_State* L) {
typedef std::integral_constant<bool,
#if SOL_IS_OFF(SOL_ALIGN_MEMORY)
false
#else
(std::alignment_of_v<T> > 1)
#endif
>
use_align;
if (!use_align::value) {
T* pointer = static_cast<T*>(alloc_newuserdata(L, sizeof(T)));
return pointer;
}
constexpr std::size_t initial_size = aligned_space_for<T>();
std::size_t allocated_size = initial_size;
void* unadjusted = alloc_newuserdata(L, allocated_size);
void* adjusted = align(std::alignment_of_v<T>, unadjusted, allocated_size);
if (adjusted == nullptr) {
lua_pop(L, 1);
luaL_error(L, , detail::demangle<T>().data());
}
return static_cast<T*>(adjusted);
}
template <typename T>
int usertype_alloc_destroy(lua_State* L) noexcept {
void* memory = lua_touserdata(L, 1);
memory = align_usertype_pointer(memory);
T** pdata = static_cast<T**>(memory);
T* data = *pdata;
std::allocator<T> alloc {};
std::allocator_traits<std::allocator<T>>::destroy(alloc, data);
return 0;
}
template <typename T>
int unique_destroy(lua_State* L) noexcept {
void* memory = lua_touserdata(L, 1);
memory = align_usertype_unique_destructor(memory);
unique_destructor& dx = *static_cast<unique_destructor*>(memory);
memory = align_usertype_unique_tag<true>(memory);
(dx)(memory);
return 0;
}
template <typename T>
int user_alloc_destroy(lua_State* L) noexcept {
void* memory = lua_touserdata(L, 1);
void* aligned_memory = align_user<T>(memory);
T* typed_memory = static_cast<T*>(aligned_memory);
std::allocator<T> alloc;
std::allocator_traits<std::allocator<T>>::destroy(alloc, typed_memory);
return 0;
}
template <typename T, typename Real>
void usertype_unique_alloc_destroy(void* memory) {
void* aligned_memory = align_usertype_unique<Real, true>(memory);
Real* typed_memory = static_cast<Real*>(aligned_memory);
std::allocator<Real> alloc;
std::allocator_traits<std::allocator<Real>>::destroy(alloc, typed_memory);
}
template <typename T>
int cannot_destroy(lua_State* L) {
return luaL_error(L,
,
detail::demangle<T>().data());
}
template <typename T>
void reserve(T&, std::size_t) {
}
template <typename T, typename Al>
void reserve(std::vector<T, Al>& vec, std::size_t hint) {
vec.reserve(hint);
}
template <typename T, typename Tr, typename Al>
void reserve(std::basic_string<T, Tr, Al>& str, std::size_t hint) {
str.reserve(hint);
}
inline bool property_always_true(meta_function) {
return true;
}
struct properties_enrollment_allowed {
int& times_through;
std::bitset<64>& properties;
automagic_enrollments& enrollments;
properties_enrollment_allowed(int& times_through_, std::bitset<64>& properties_, automagic_enrollments& enrollments_)
: times_through(times_through_), properties(properties_), enrollments(enrollments_) {
}
bool operator()(meta_function mf) const {
bool p = properties[static_cast<std::size_t>(mf)];
if (times_through > 0) {
return p;
}
switch (mf) {
case meta_function::length:
return enrollments.length_operator && !p;
case meta_function::pairs:
return enrollments.pairs_operator && !p;
case meta_function::call:
return enrollments.call_operator && !p;
case meta_function::less_than:
return enrollments.less_than_operator && !p;
case meta_function::less_than_or_equal_to:
return enrollments.less_than_or_equal_to_operator && !p;
case meta_function::equal_to:
return enrollments.equal_to_operator && !p;
default:
break;
}
return !p;
}
};
struct indexed_insert {
lua_reg_table& registration_table;
int& index;
indexed_insert(lua_reg_table& registration_table_, int& index_ref_) : registration_table(registration_table_), index(index_ref_) {
}
void operator()(meta_function meta_function_name_, lua_CFunction c_function_) {
registration_table[index] = luaL_Reg { to_string(meta_function_name_).c_str(), c_function_ };
++index;
}
};
} // namespace detail
namespace stack {
template <typename T, bool global = false, bool raw = false, typename = void>
struct field_getter;
template <typename T, typename P, bool global = false, bool raw = false, typename = void>
struct probe_field_getter;
template <typename T, bool global = false, bool raw = false, typename = void>
struct field_setter;
template <typename T, typename = void>
struct unqualified_getter;
template <typename T, typename = void>
struct qualified_getter;
template <typename T, typename = void>
struct qualified_interop_getter;
template <typename T, typename = void>
struct unqualified_interop_getter;
template <typename T, typename = void>
struct popper;
template <typename T, typename = void>
struct unqualified_pusher;
template <typename T, type t, typename = void>
struct unqualified_checker;
template <typename T, type t, typename = void>
struct qualified_checker;
template <typename T, typename = void>
struct unqualified_check_getter;
template <typename T, typename = void>
struct qualified_check_getter;
struct probe {
bool success;
int levels;
probe(bool s, int l) : success(s), levels(l) {
}
operator bool() const {
return success;
};
};
struct record {
int last;
int used;
record() noexcept : last(), used() {
}
void use(int count) noexcept {
last = count;
used += count;
}
};
namespace stack_detail {
template <typename Function>
Function* get_function_pointer(lua_State*, int, record&) noexcept;
template <typename Function, typename Handler>
bool check_function_pointer(lua_State* L, int index, Handler&& handler, record& tracking) noexcept;
} // namespace stack_detail
} // namespace stack
namespace stack {
namespace stack_detail {
constexpr const char* not_enough_stack_space = ;
constexpr const char* not_enough_stack_space_floating = ;
constexpr const char* not_enough_stack_space_integral = ;
constexpr const char* not_enough_stack_space_string = ;
constexpr const char* not_enough_stack_space_meta_function_name = ;
constexpr const char* not_enough_stack_space_userdata = ;
constexpr const char* not_enough_stack_space_generic = ;
constexpr const char* not_enough_stack_space_environment = ;
template <typename T>
struct strip {
typedef T type;
};
template <typename T>
struct strip<std::reference_wrapper<T>> {
typedef T& type;
};
template <typename T>
struct strip<user<T>> {
typedef T& type;
};
template <typename T>
struct strip<non_null<T>> {
typedef T type;
};
template <typename T>
using strip_t = typename strip<T>::type;
template <typename C>
static int get_size_hint(C& c) {
return static_cast<int>(c.size());
}
template <typename V, typename Al>
static int get_size_hint(const std::forward_list<V, Al>&) {
// forward_list makes me sad
return static_cast<int>(32);
}
template <typename T>
decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_get_v<Tu>) {
return sol_lua_get(types<Tu>(), L, index, tracking);
}
else {
unqualified_getter<Tu> g {};
return g.get(L, index, tracking);
}
}
template <typename T>
decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_get_v<T>) {
return sol_lua_get(types<T>(), L, index, tracking);
}
else {
qualified_getter<T> g {};
return g.get(L, index, tracking);
}
}
template <typename T>
decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<Tu>) {
return sol_lua_interop_get(types<Tu>(), L, index, unadjusted_pointer, tracking);
}
else {
(void)L;
(void)index;
(void)unadjusted_pointer;
(void)tracking;
using Ti = stack_detail::strip_t<Tu>;
return std::pair<bool, Ti*> { false, nullptr };
}
}
template <typename T>
decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v<T>) {
return sol_lua_interop_get(types<T>(), L, index, unadjusted_pointer, tracking);
}
else {
return unqualified_interop_get<T>(L, index, unadjusted_pointer, tracking);
}
}
template <typename T, typename Handler>
bool unqualified_interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v<Tu>) {
return sol_lua_interop_check(types<Tu>(), L, index, index_type, std::forward<Handler>(handler), tracking);
}
else {
(void)L;
(void)index;
(void)index_type;
(void)handler;
(void)tracking;
return false;
}
}
template <typename T, typename Handler>
bool interop_check(lua_State* L, int index, type index_type, Handler&& handler, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_interop_check_v<T>) {
return sol_lua_interop_check(types<T>(), L, index, index_type, std::forward<Handler>(handler), tracking);
}
else {
return unqualified_interop_check<T>(L, index, index_type, std::forward<Handler>(handler), tracking);
}
}
using undefined_method_func = void (*)(stack_reference);
struct undefined_metatable {
lua_State* L;
const char* key;
undefined_method_func on_new_table;
undefined_metatable(lua_State* l, const char* k, undefined_method_func umf) : L(l), key(k), on_new_table(umf) {
}
void operator()() const {
if (luaL_newmetatable(L, key) == 1) {
on_new_table(stack_reference(L, -1));
}
lua_setmetatable(L, -2);
}
};
} // namespace stack_detail
inline bool maybe_indexable(lua_State* L, int index = -1) {
type t = type_of(L, index);
return t == type::userdata || t == type::table;
}
inline int top(lua_State* L) {
return lua_gettop(L);
}
inline bool is_main_thread(lua_State* L) {
int ismainthread = lua_pushthread(L);
lua_pop(L, 1);
return ismainthread == 1;
}
inline void coroutine_create_guard(lua_State* L) {
if (is_main_thread(L)) {
return;
}
int stacksize = lua_gettop(L);
if (stacksize < 1) {
return;
}
if (type_of(L, 1) != type::function) {
return;
}
// well now we're screwed...
// we can clean the stack and pray it doesn't destroy anything?
lua_pop(L, stacksize);
}
inline void clear(lua_State* L, int table_index) {
lua_pushnil(L);
while (lua_next(L, table_index) != 0) {
// remove value
lua_pop(L, 1);
// duplicate key to protect form rawset
lua_pushvalue(L, -1);
// push new value
lua_pushnil(L);
// table_index%[key] = nil
lua_rawset(L, table_index);
}
}
inline void clear(reference& r) {
auto pp = push_pop<false>(r);
int stack_index = pp.index_of(r);
clear(r.lua_state(), stack_index);
}
inline void clear(stack_reference& r) {
clear(r.lua_state(), r.stack_index());
}
inline void clear(lua_State* L_, stateless_reference& r) {
r.push(L_);
int stack_index = absolute_index(L_, -1);
clear(L_, stack_index);
r.pop(L_);
}
inline void clear(lua_State* L_, stateless_stack_reference& r) {
clear(L_, r.stack_index());
}
template <typename T, typename... Args>
int push(lua_State* L, T&& t, Args&&... args) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, T, Args...>) {
return sol_lua_push(types<T>(), L, std::forward<T>(t), std::forward<Args>(args)...);
}
else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, T, Args...>) {
return sol_lua_push(types<Tu>(), L, std::forward<T>(t), std::forward<Args>(args)...);
}
else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<T, Args...>) {
return sol_lua_push(L, std::forward<T>(t), std::forward<Args>(args)...);
}
else {
unqualified_pusher<Tu> p {};
return p.push(L, std::forward<T>(t), std::forward<Args>(args)...);
}
}
// overload allows to use a pusher of a specific type, but pass in any kind of args
template <typename T, typename Arg, typename... Args, typename = std::enable_if_t<!std::is_same<T, Arg>::value>>
int push(lua_State* L, Arg&& arg, Args&&... args) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<T, Arg, Args...>) {
return sol_lua_push(types<T>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
else if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v<Tu, Arg, Args...>) {
return sol_lua_push(types<Tu>(), L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
else if constexpr (meta::meta_detail::is_adl_sol_lua_push_v<Arg, Args...> && !detail::is_tagged_v<Tu>) {
return sol_lua_push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
else {
unqualified_pusher<Tu> p {};
return p.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
}
template <typename T, typename... Args>
int push_userdata(lua_State* L, T&& t, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer_v<U>,
detail::as_pointer_tag<std::remove_pointer_t<U>>,
meta::conditional_t<is_unique_usertype_v<U>, detail::as_unique_tag<U>, detail::as_value_tag<U>>>;
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
using U = meta::unqualified_t<T>;
using Tr = meta::conditional_t<std::is_pointer_v<U>,
detail::as_pointer_tag<std::remove_pointer_t<U>>,
meta::conditional_t<is_unique_usertype_v<U>, detail::as_unique_tag<U>, detail::as_value_tag<U>>>;
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
namespace stack_detail {
template <typename T, typename Arg, typename... Args>
int push_reference(lua_State* L, Arg&& arg, Args&&... args) {
// clang-format off
using use_reference_tag =
meta::all<
meta::neg<is_value_semantic_for_function<T>>
#if SOL_IS_OFF(SOL_FUNCTION_CALL_VALUE_SEMANTICS)
, std::is_lvalue_reference<T>,
meta::neg<std::is_const<std::remove_reference_t<T>>>,
meta::neg<is_lua_primitive<meta::unqualified_t<T>>>,
meta::neg<is_unique_usertype<meta::unqualified_t<T>>>
#endif
>;
// clang-format on
using Tr = meta::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>;
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
} // namespace stack_detail
template <typename T, typename... Args>
int push_reference(lua_State* L, T&& t, Args&&... args) {
return stack_detail::push_reference<T>(L, std::forward<T>(t), std::forward<Args>(args)...);
}
template <typename T, typename Arg, typename... Args>
int push_reference(lua_State* L, Arg&& arg, Args&&... args) {
return stack_detail::push_reference<T>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
inline int multi_push(lua_State*) {
// do nothing
return 0;
}
template <typename T, typename... Args>
int multi_push(lua_State* L, T&& t, Args&&... args) {
int pushcount = push(L, std::forward<T>(t));
void(detail::swallow { (pushcount += stack::push(L, std::forward<Args>(args)), 0)... });
return pushcount;
}
inline int multi_push_reference(lua_State*) {
// do nothing
return 0;
}
template <typename T, typename... Args>
int multi_push_reference(lua_State* L, T&& t, Args&&... args) {
int pushcount = stack::push_reference(L, std::forward<T>(t));
void(detail::swallow { (pushcount += stack::push_reference(L, std::forward<Args>(args)), 0)... });
return pushcount;
}
template <typename T, typename Handler>
bool unqualified_check(lua_State* L, int index, Handler&& handler, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_check_v<Tu>) {
return sol_lua_check(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);
}
else {
unqualified_checker<Tu, lua_type_of_v<Tu>> c{};
return c.check(L, index, std::forward<Handler>(handler), tracking);
}
}
template <typename T, typename Handler>
bool unqualified_check(lua_State* L, int index, Handler&& handler) {
record tracking {};
return unqualified_check<T>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T>
bool unqualified_check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = &no_panic;
return unqualified_check<T>(L, index, handler);
}
template <typename T, typename Handler>
bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_check_v<T>) {
return sol_lua_check(types<T>(), L, index, std::forward<Handler>(handler), tracking);
}
else {
using Tu = meta::unqualified_t<T>;
qualified_checker<T, lua_type_of_v<Tu>> c{};
return c.check(L, index, std::forward<Handler>(handler), tracking);
}
}
template <typename T, typename Handler>
bool check(lua_State* L, int index, Handler&& handler) {
record tracking {};
return check<T>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T>
bool check(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = &no_panic;
return check<T>(L, index, handler);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, type, Handler&& handler, record& tracking) {
using Tu = meta::unqualified_t<T>;
using detail_t = meta::conditional_t<std::is_pointer_v<T>, detail::as_pointer_tag<Tu>, detail::as_value_tag<Tu>>;
return check<detail_t>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) {
using Tu = meta::unqualified_t<T>;
using detail_t = meta::conditional_t<std::is_pointer_v<T>, detail::as_pointer_tag<Tu>, detail::as_value_tag<Tu>>;
return check<detail_t>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler) {
record tracking {};
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T>
bool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = &no_panic;
return check_usertype<T>(L, index, handler);
}
template <typename T, typename Handler>
decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) {
return sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking);
}
else if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<Tu>) {
return sol_lua_check_get(types<Tu>(), L, index, std::forward<Handler>(handler), tracking);
}
else {
unqualified_check_getter<Tu> cg {};
return cg.get(L, index, std::forward<Handler>(handler), tracking);
}
}
template <typename T, typename Handler>
decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) {
record tracking {};
return unqualified_check_get<T>(L, index, handler, tracking);
}
template <typename T>
decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = &no_panic;
return unqualified_check_get<T>(L, index, handler);
}
template <typename T, typename Handler>
decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v<T>) {
return sol_lua_check_get(types<T>(), L, index, std::forward<Handler>(handler), tracking);
}
else {
qualified_check_getter<T> cg {};
return cg.get(L, index, std::forward<Handler>(handler), tracking);
}
}
template <typename T, typename Handler>
decltype(auto) check_get(lua_State* L, int index, Handler&& handler) {
record tracking {};
return check_get<T>(L, index, handler, tracking);
}
template <typename T>
decltype(auto) check_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = &no_panic;
return check_get<T>(L, index, handler);
}
namespace stack_detail {
template <typename Handler>
bool check_types(lua_State*, int, Handler&&, record&) {
return true;
}
template <typename T, typename... Args, typename Handler>
bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) {
if (!stack::check<T>(L, firstargument + tracking.used, handler, tracking))
return false;
return check_types<Args...>(L, firstargument, std::forward<Handler>(handler), tracking);
}
template <typename... Args, typename Handler>
bool check_types(types<Args...>, lua_State* L, int index, Handler&& handler, record& tracking) {
return check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);
}
} // namespace stack_detail
template <typename... Args, typename Handler>
bool multi_check(lua_State* L, int index, Handler&& handler, record& tracking) {
return stack_detail::check_types<Args...>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename... Args, typename Handler>
bool multi_check(lua_State* L, int index, Handler&& handler) {
record tracking {};
return multi_check<Args...>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename... Args>
bool multi_check(lua_State* L, int index) {
return multi_check<Args...>(L, index);
}
template <typename T>
auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get<T>(L, index, tracking)) {
#if SOL_IS_ON(SOL_SAFE_GETTER)
static constexpr bool is_op = meta::is_optional_v<T>;
if constexpr (is_op) {
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
}
else {
if (is_lua_reference<T>::value) {
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
}
auto op = unqualified_check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op);
}
#else
return stack_detail::unchecked_unqualified_get<T>(L, index, tracking);
#endif
}
template <typename T>
decltype(auto) unqualified_get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking {};
return unqualified_get<T>(L, index, tracking);
}
template <typename T>
auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get<T>(L, index, tracking)) {
#if SOL_IS_ON(SOL_SAFE_GETTER)
static constexpr bool is_op = meta::is_optional_v<T>;
if constexpr (is_op) {
return stack_detail::unchecked_get<T>(L, index, tracking);
}
else {
if (is_lua_reference<T>::value) {
return stack_detail::unchecked_get<T>(L, index, tracking);
}
auto op = check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op);
}
#else
return stack_detail::unchecked_get<T>(L, index, tracking);
#endif
}
template <typename T>
decltype(auto) get(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking {};
return get<T>(L, index, tracking);
}
template <typename T>
decltype(auto) get_usertype(lua_State* L, int index, record& tracking) {
using UT = meta::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>;
return get<UT>(L, index, tracking);
}
template <typename T>
decltype(auto) get_usertype(lua_State* L, int index = -lua_size_v<meta::unqualified_t<T>>) {
record tracking {};
return get_usertype<T>(L, index, tracking);
}
template <typename T>
decltype(auto) pop(lua_State* L) {
return popper<T> {}.pop(L);
}
template <bool global = false, bool raw = false, typename Key>
void get_field(lua_State* L, Key&& key) {
field_getter<meta::unqualified_t<Key>, global, raw> {}.get(L, std::forward<Key>(key));
}
template <bool global = false, bool raw = false, typename Key>
void get_field(lua_State* L, Key&& key, int tableindex) {
field_getter<meta::unqualified_t<Key>, global, raw> {}.get(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, typename Key>
void raw_get_field(lua_State* L, Key&& key) {
get_field<global, true>(L, std::forward<Key>(key));
}
template <bool global = false, typename Key>
void raw_get_field(lua_State* L, Key&& key, int tableindex) {
get_field<global, true>(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, bool raw = false, typename C = detail::non_lua_nil_t, typename Key>
probe probe_get_field(lua_State* L, Key&& key) {
return probe_field_getter<meta::unqualified_t<Key>, C, global, raw> {}.get(L, std::forward<Key>(key));
}
template <bool global = false, bool raw = false, typename C = detail::non_lua_nil_t, typename Key>
probe probe_get_field(lua_State* L, Key&& key, int tableindex) {
return probe_field_getter<meta::unqualified_t<Key>, C, global, raw> {}.get(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, typename C = detail::non_lua_nil_t, typename Key>
probe probe_raw_get_field(lua_State* L, Key&& key) {
return probe_get_field<global, true, C>(L, std::forward<Key>(key));
}
template <bool global = false, typename C = detail::non_lua_nil_t, typename Key>
probe probe_raw_get_field(lua_State* L, Key&& key, int tableindex) {
return probe_get_field<global, true, C>(L, std::forward<Key>(key), tableindex);
}
template <bool global = false, bool raw = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value) {
field_setter<meta::unqualified_t<Key>, global, raw> {}.set(L, std::forward<Key>(key), std::forward<Value>(value));
}
template <bool global = false, bool raw = false, typename Key, typename Value>
void set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
field_setter<meta::unqualified_t<Key>, global, raw> {}.set(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
}
template <bool global = false, typename Key, typename Value>
void raw_set_field(lua_State* L, Key&& key, Value&& value) {
set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value));
}
template <bool global = false, typename Key, typename Value>
void raw_set_field(lua_State* L, Key&& key, Value&& value, int tableindex) {
set_field<global, true>(L, std::forward<Key>(key), std::forward<Value>(value), tableindex);
}
template <typename T, typename F>
void modify_unique_usertype_as(const stack_reference& obj, F&& f) {
void* raw = lua_touserdata(obj.lua_state(), obj.stack_index());
void* ptr_memory = detail::align_usertype_pointer(raw);
void* uu_memory = detail::align_usertype_unique<T>(raw);
T& uu = *static_cast<T*>(uu_memory);
f(uu);
*static_cast<void**>(ptr_memory) = static_cast<void*>(detail::unique_get(obj.lua_state(), uu));
}
template <typename F>
void modify_unique_usertype(const stack_reference& obj, F&& f) {
using bt = meta::bind_traits<meta::unqualified_t<F>>;
using T = typename bt::template arg_at<0>;
using Tu = meta::unqualified_t<T>;
modify_unique_usertype_as<Tu>(obj, std::forward<F>(f));
}
namespace stack_detail {
template <typename T, typename Handler>
decltype(auto) check_get_arg(lua_State* L_, int index_, Handler&& handler_, record& tracking_) {
if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v<T>) {
sol_lua_check_access(types<meta::unqualified_t<T>>(), L_, index_, tracking_);
}
return check_get<T>(L_, index_, std::forward<Handler>(handler_), tracking_);
}
template <typename T>
decltype(auto) unchecked_get_arg(lua_State* L_, int index_, record& tracking_) {
if constexpr (meta::meta_detail::is_adl_sol_lua_check_access_v<T>) {
sol_lua_check_access(types<meta::unqualified_t<T>>(), L_, index_, tracking_);
}
return unchecked_get<T>(L_, index_, tracking_);
}
} // namespace stack_detail
} // namespace stack
namespace detail {
template <typename T>
lua_CFunction make_destructor(std::true_type) {
if constexpr (is_unique_usertype_v<T>) {
return &unique_destroy<T>;
}
else if constexpr (!std::is_pointer_v<T>) {
return &usertype_alloc_destroy<T>;
}
else {
return &cannot_destroy<T>;
}
}
template <typename T>
lua_CFunction make_destructor(std::false_type) {
return &cannot_destroy<T>;
}
template <typename T>
lua_CFunction make_destructor() {
return make_destructor<T>(std::is_destructible<T>());
}
struct no_comp {
template <typename A, typename B>
bool operator()(A&&, B&&) const {
return false;
}
};
template <typename T>
int is_check(lua_State* L) {
return stack::push(L, stack::check<T>(L, 1, &no_panic));
}
template <typename T>
int member_default_to_string(std::true_type, lua_State* L) {
decltype(auto) ts = stack::get<T>(L, 1).to_string();
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
int member_default_to_string(std::false_type, lua_State* L) {
return luaL_error(L,
,
detail::demangle<T>().data());
}
template <typename T>
int adl_default_to_string(std::true_type, lua_State* L) {
using namespace std;
decltype(auto) ts = to_string(stack::get<T>(L, 1));
return stack::push(L, std::forward<decltype(ts)>(ts));
}
template <typename T>
int adl_default_to_string(std::false_type, lua_State* L) {
return member_default_to_string<T>(meta::supports_to_string_member<T>(), L);
}
template <typename T>
int oss_default_to_string(std::true_type, lua_State* L) {
std::ostringstream oss;
oss << stack::unqualified_get<T>(L, 1);
return stack::push(L, oss.str());
}
template <typename T>
int oss_default_to_string(std::false_type, lua_State* L) {
return adl_default_to_string<T>(meta::supports_adl_to_string<T>(), L);
}
template <typename T>
int default_to_string(lua_State* L) {
return oss_default_to_string<T>(meta::supports_op_left_shift<std::ostream, T>(), L);
}
template <typename T>
int default_size(lua_State* L) {
decltype(auto) self = stack::unqualified_get<T>(L, 1);
return stack::push(L, self.size());
}
template <typename T, typename Op>
int comparsion_operator_wrap(lua_State* L) {
if constexpr (std::is_void_v<T>) {
return stack::push(L, false);
}
else {
auto maybel = stack::unqualified_check_get<T>(L, 1);
if (!maybel) {
return stack::push(L, false);
}
auto mayber = stack::unqualified_check_get<T>(L, 2);
if (!mayber) {
return stack::push(L, false);
}
decltype(auto) l = *maybel;
decltype(auto) r = *mayber;
if constexpr (std::is_same_v<no_comp, Op>) {
std::equal_to<> op;
return stack::push(L, op(detail::ptr(l), detail::ptr(r)));
}
else {
if constexpr (std::is_same_v<std::equal_to<>, Op> // clang-format hack
|| std::is_same_v<std::less_equal<>, Op> //
|| std::is_same_v<std::less_equal<>, Op>) { //
if (detail::ptr(l) == detail::ptr(r)) {
return stack::push(L, true);
}
}
Op op;
return stack::push(L, op(detail::deref(l), detail::deref(r)));
}
}
}
template <typename T, typename IFx, typename Fx>
void insert_default_registrations(IFx&& ifx, Fx&& fx);
template <typename T, bool, bool>
struct get_is_primitive : is_lua_primitive<T> { };
template <typename T>
struct get_is_primitive<T, true, false>
: meta::neg<std::is_reference<decltype(sol_lua_get(types<T>(), nullptr, -1, std::declval<stack::record&>()))>> { };
template <typename T>
struct get_is_primitive<T, false, true>
: meta::neg<std::is_reference<decltype(sol_lua_get(types<meta::unqualified_t<T>>(), nullptr, -1, std::declval<stack::record&>()))>> { };
template <typename T>
struct get_is_primitive<T, true, true> : get_is_primitive<T, true, false> { };
} // namespace detail
template <typename T>
struct is_proxy_primitive
: detail::get_is_primitive<T, meta::meta_detail::is_adl_sol_lua_get_v<T>, meta::meta_detail::is_adl_sol_lua_get_v<meta::unqualified_t<T>>> { };
} // namespace sol
#endif // SOL_STACK_CORE_HPP
namespace sol {
namespace detail {
template <typename T>
struct is_speshul : std::false_type { };
} // namespace detail
template <typename T>
struct tie_size : std::tuple_size<T> { };
template <typename T>
struct is_tieable : std::integral_constant<bool, (::sol::tie_size<T>::value > 0)> { };
template <typename... Tn>
struct tie_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> {
private:
typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t;
template <typename T>
void set(std::false_type, T&& target) {
std::get<0>(*this) = std::forward<T>(target);
}
template <typename T>
void set(std::true_type, T&& target) {
typedef tie_size<meta::unqualified_t<T>> value_size;
typedef tie_size<std::tuple<Tn...>> tie_size;
typedef meta::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;
typedef std::make_index_sequence<indices_size::value> indices;
set_extra(detail::is_speshul<meta::unqualified_t<T>>(), indices(), std::forward<T>(target));
}
template <std::size_t... I, typename T>
void set_extra(std::true_type, std::index_sequence<I...>, T&& target) {
using std::get;
(void)detail::swallow { 0, (get<I>(static_cast<base_t&>(*this)) = get<I>(types<Tn...>(), target), 0)..., 0 };
}
template <std::size_t... I, typename T>
void set_extra(std::false_type, std::index_sequence<I...>, T&& target) {
using std::get;
(void)detail::swallow { 0, (get<I>(static_cast<base_t&>(*this)) = get<I>(target), 0)..., 0 };
}
public:
using base_t::base_t;
template <typename T>
tie_t& operator=(T&& value) {
typedef is_tieable<meta::unqualified_t<T>> tieable;
set(tieable(), std::forward<T>(value));
return *this;
}
};
template <typename... Tn>
struct tie_size<tie_t<Tn...>> : std::tuple_size<std::tuple<Tn...>> { };
namespace adl_barrier_detail {
template <typename... Tn>
inline tie_t<std::remove_reference_t<Tn>...> tie(Tn&&... argn) {
return tie_t<std::remove_reference_t<Tn>...>(std::forward<Tn>(argn)...);
}
} // namespace adl_barrier_detail
using namespace adl_barrier_detail;
} // namespace sol
#endif // SOL_TIE_HPP
namespace sol {
template <typename T>
struct usertype_container;
namespace container_detail {
template <typename T>
struct has_clear_test {
private:
template <typename C>
static meta::sfinae_yes_t test(decltype(&C::clear));
template <typename C>
static meta::sfinae_no_t test(...);
public:
static constexpr bool value = std::is_same_v<decltype(test<T>(0)), meta::sfinae_yes_t>;
};
template <typename X>
struct usertype_container_default<X,
std::enable_if_t<meta::all<is_forced_container<meta::unqualified_t<X>>, meta::has_value_type<meta::unqualified_t<container_decay_t<X>>>,
meta::has_iterator<meta::unqualified_t<container_decay_t<X>>>>::value>> {
private:
using T = std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>>;
private:
using deferred_uc = usertype_container<X>;
using is_associative = meta::is_associative<T>;
using is_lookup = meta::is_lookup<T>;
using is_ordered = meta::is_ordered<T>;
using is_matched_lookup = meta::is_matched_lookup<T>;
using iterator = typename T::iterator;
using sentinel = meta::sentinel_or_t<T, iterator>;
using value_type = typename T::value_type;
typedef meta::conditional_t<is_matched_lookup::value, std::pair<value_type, value_type>,
meta::conditional_t<is_associative::value || is_lookup::value, value_type, std::pair<std::ptrdiff_t, value_type>>>
KV;
typedef typename KV::first_type K;
typedef typename KV::second_type V;
typedef meta::conditional_t<is_matched_lookup::value, std::ptrdiff_t, K> next_K;
typedef decltype(*std::declval<iterator&>()) iterator_return;
typedef meta::conditional_t<is_associative::value || is_matched_lookup::value, std::add_lvalue_reference_t<V>,
meta::conditional_t<is_lookup::value, V, iterator_return>>
captured_type;
typedef typename meta::iterator_tag<iterator>::type iterator_category;
typedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator;
typedef meta::conditional_t<is_input_iterator::value, V, decltype(detail::deref_move_only(std::declval<captured_type>()))> push_type;
typedef std::is_copy_assignable<V> is_copyable;
typedef meta::neg<meta::any<std::is_const<V>, std::is_const<std::remove_reference_t<iterator_return>>, meta::neg<is_copyable>>> is_writable;
typedef meta::unqualified_t<decltype(get_key(is_associative(), std::declval<std::add_lvalue_reference_t<value_type>>()))> key_type;
typedef meta::all<std::is_integral<K>, meta::neg<meta::any<is_associative, is_lookup>>> is_linear_integral;
struct iter : detail::ebco<iterator, 0>, detail::ebco<sentinel, 1> {
using it_base = detail::ebco<iterator, 0>;
using sen_base = detail::ebco<sentinel, 1>;
main_reference keep_alive;
std::size_t index;
iter(lua_State* L_, int stack_index_, iterator it_, sentinel sen_) noexcept
: it_base(std::move(it_)), sen_base(std::move(sen_)), keep_alive(L_, stack_index_), index(0) {
}
iterator& it() noexcept {
return it_base::value();
}
const iterator& it() const noexcept {
return it_base::value();
}
sentinel& sen() noexcept {
return sen_base::value();
}
const sentinel& sen() const noexcept {
return sen_base::value();
}
};
static auto& get_src(lua_State* L_) {
#if SOL_IS_ON(SOL_SAFE_USERTYPE)
auto p = stack::unqualified_check_get<T*>(L_, 1);
if (!p) {
luaL_error(L_,
,
detail::demangle<T>().c_str());
}
if (p.value() == nullptr) {
luaL_error(
L_, , detail::demangle<T>().c_str());
}
return *p.value();
#else
return stack::unqualified_get<T>(L_, 1);
#endif // Safe getting with error
}
static detail::error_result at_category(std::input_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) {
pos += deferred_uc::index_adjustment(L_, self);
if (pos < 0) {
return stack::push(L_, lua_nil);
}
auto it = deferred_uc::begin(L_, self);
auto e = deferred_uc::end(L_, self);
if (it == e) {
return stack::push(L_, lua_nil);
}
while (pos > 0) {
--pos;
++it;
if (it == e) {
return stack::push(L_, lua_nil);
}
}
return get_associative(is_associative(), L_, it);
}
static detail::error_result at_category(std::random_access_iterator_tag, lua_State* L_, T& self, std::ptrdiff_t pos) {
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self));
pos += deferred_uc::index_adjustment(L_, self);
if (pos < 0 || pos >= len) {
return stack::push(L_, lua_nil);
}
auto it = std::next(deferred_uc::begin(L_, self), pos);
return get_associative(is_associative(), L_, it);
}
static detail::error_result at_start(lua_State* L_, T& self, std::ptrdiff_t pos) {
return at_category(iterator_category(), L_, self, pos);
}
template <typename Iter>
static detail::error_result get_associative(std::true_type, lua_State* L_, Iter& it) {
decltype(auto) v = *it;
return stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(v.second));
}
template <typename Iter>
static detail::error_result get_associative(std::false_type, lua_State* L_, Iter& it) {
return stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(*it));
}
static detail::error_result get_category(std::input_iterator_tag, lua_State* L_, T& self, K& key) {
key = static_cast<K>(key + deferred_uc::index_adjustment(L_, self));
if (key < 0) {
return stack::push(L_, lua_nil);
}
auto it = deferred_uc::begin(L_, self);
auto e = deferred_uc::end(L_, self);
if (it == e) {
return stack::push(L_, lua_nil);
}
while (key > 0) {
--key;
++it;
if (it == e) {
return stack::push(L_, lua_nil);
}
}
return get_associative(is_associative(), L_, it);
}
static detail::error_result get_category(std::random_access_iterator_tag, lua_State* L_, T& self, K& key) {
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self));
key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
if (key < 0 || key >= len) {
return stack::push(L_, lua_nil);
}
auto it = std::next(deferred_uc::begin(L_, self), key);
return get_associative(is_associative(), L_, it);
}
static detail::error_result get_it(std::true_type, lua_State* L_, T& self, K& key) {
return get_category(iterator_category(), L_, self, key);
}
static detail::error_result get_comparative(std::true_type, lua_State* L_, T& self, K& key) {
auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); };
auto e = deferred_uc::end(L_, self);
auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx));
if (it == e) {
return stack::push(L_, lua_nil);
}
return get_associative(is_associative(), L_, it);
}
static detail::error_result get_comparative(std::false_type, lua_State*, T&, K&) {
return detail::error_result(,
detail::demangle<T>().data(),
detail::demangle<K>().data());
}
static detail::error_result get_it(std::false_type, lua_State* L_, T& self, K& key) {
return get_comparative(meta::supports_op_equal<K, key_type>(), L_, self, key);
}
static detail::error_result set_associative(std::true_type, iterator& it, stack_object value) {
decltype(auto) v = *it;
v.second = value.as<V>();
return {};
}
static detail::error_result set_associative(std::false_type, iterator& it, stack_object value) {
decltype(auto) v = *it;
v = value.as<V>();
return {};
}
static detail::error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) {
return set_associative(is_associative(), it, std::move(value));
}
static detail::error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) {
return detail::error_result(
, detail::demangle<T>().data());
}
static detail::error_result set_category(std::input_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
auto e = deferred_uc::end(L_, self);
auto it = deferred_uc::begin(L_, self);
auto backit = it;
for (; key > 0 && it != e; --key, ++it) {
backit = it;
}
if (it == e) {
if (key == 0) {
return add_copyable(is_copyable(), L_, self, std::move(value), meta::has_insert_after<T>::value ? backit : it);
}
return detail::error_result(, detail::demangle<T>().c_str());
}
return set_writable(is_writable(), L_, self, it, std::move(value));
}
static detail::error_result set_category(std::random_access_iterator_tag, lua_State* L_, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
if (key < 0) {
return detail::error_result(, detail::demangle<T>().c_str());
}
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L_, self));
if (key == len) {
return add_copyable(is_copyable(), L_, self, std::move(value));
}
else if (key >= len) {
return detail::error_result(, detail::demangle<T>().c_str());
}
auto it = std::next(deferred_uc::begin(L_, self), key);
return set_writable(is_writable(), L_, self, it, std::move(value));
}
static detail::error_result set_comparative(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
if (!is_writable::value) {
return detail::error_result(
, detail::demangle<T>().data());
}
auto fx = [&](const value_type& r) -> bool { return key == get_key(is_associative(), r); };
auto e = deferred_uc::end(L_, self);
auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx));
if (it == e) {
return {};
}
return set_writable(is_writable(), L_, self, it, std::move(value));
}
static detail::error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) {
return detail::error_result(,
detail::demangle<T>().data(),
detail::demangle<K>().data());
}
template <typename Iter>
static detail::error_result set_associative_insert(std::true_type, lua_State*, T& self, Iter& it, K& key, stack_object value) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(it, value_type(key, value.as<V>()));
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(value_type(key, value.as<V>()));
return {};
}
else {
(void)self;
(void)it;
(void)key;
return detail::error_result(
, detail::demangle<T>().c_str());
}
}
template <typename Iter>
static detail::error_result set_associative_insert(std::false_type, lua_State*, T& self, Iter& it, K& key, stack_object) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(it, key);
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(key);
return {};
}
else {
(void)self;
(void)it;
(void)key;
return detail::error_result(
, detail::demangle<T>().c_str());
}
}
static detail::error_result set_associative_find(std::true_type, lua_State* L_, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
auto it = self.find(key);
if (it == deferred_uc::end(L_, self)) {
return set_associative_insert(is_associative(), L_, self, it, key, std::move(value));
}
return set_writable(is_writable(), L_, self, it, std::move(value));
}
static detail::error_result set_associative_find(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) {
return set_comparative(meta::supports_op_equal<K, key_type>(), L_, self, std::move(key), std::move(value));
}
static detail::error_result set_it(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) {
return set_category(iterator_category(), L_, self, std::move(key), std::move(value));
}
static detail::error_result set_it(std::false_type, lua_State* L_, T& self, stack_object key, stack_object value) {
return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L_, self, std::move(key), std::move(value));
}
template <bool idx_of = false>
static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L_, T& self) {
if constexpr (!is_ordered::value && idx_of) {
(void)L_;
(void)self;
return detail::error_result(, detail::demangle<T>().data());
}
else {
decltype(auto) key = stack::unqualified_get<K>(L_, 2);
auto it = self.find(key);
if (it == deferred_uc::end(L_, self)) {
return stack::push(L_, lua_nil);
}
if constexpr (idx_of) {
auto dist = std::distance(deferred_uc::begin(L_, self), it);
dist -= deferred_uc::index_adjustment(L_, self);
return stack::push(L_, dist);
}
else {
return get_associative(is_associative(), L_, it);
}
}
}
template <bool idx_of = false>
static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L_, T& self) {
if constexpr (!is_ordered::value && idx_of) {
(void)L_;
(void)self;
return detail::error_result(, detail::demangle<T>().data());
}
else {
decltype(auto) value = stack::unqualified_get<V>(L_, 2);
auto it = self.find(value);
if (it == deferred_uc::end(L_, self)) {
return stack::push(L_, lua_nil);
}
if constexpr (idx_of) {
auto dist = std::distance(deferred_uc::begin(L_, self), it);
dist -= deferred_uc::index_adjustment(L_, self);
return stack::push(L_, dist);
}
else {
return get_associative(is_associative(), L_, it);
}
}
}
template <bool idx_of = false>
static detail::error_result find_has(std::true_type, lua_State* L_, T& self) {
return find_has_associative_lookup<idx_of>(meta::any<is_lookup, is_associative>(), L_, self);
}
template <typename Iter>
static detail::error_result find_associative_lookup(std::true_type, lua_State* L_, T&, Iter& it, std::size_t) {
return get_associative(is_associative(), L_, it);
}
template <typename Iter>
static detail::error_result find_associative_lookup(std::false_type, lua_State* L_, T& self, Iter&, std::size_t idx) {
idx = static_cast<std::size_t>(static_cast<std::ptrdiff_t>(idx) - deferred_uc::index_adjustment(L_, self));
return stack::push(L_, idx);
}
template <bool = false>
static detail::error_result find_comparative(std::false_type, lua_State*, T&) {
return detail::error_result(,
detail::demangle<T>().c_str());
}
template <bool idx_of = false>
static detail::error_result find_comparative(std::true_type, lua_State* L_, T& self) {
decltype(auto) value = stack::unqualified_get<V>(L_, 2);
auto it = deferred_uc::begin(L_, self);
auto e = deferred_uc::end(L_, self);
std::size_t idx = 0;
for (;; ++it, ++idx) {
if (it == e) {
return stack::push(L_, lua_nil);
}
if (value == get_value(is_associative(), *it)) {
break;
}
}
return find_associative_lookup(meta::all<meta::boolean<!idx_of>, meta::any<is_lookup, is_associative>>(), L_, self, it, idx);
}
template <bool idx_of = false>
static detail::error_result find_has(std::false_type, lua_State* L_, T& self) {
return find_comparative<idx_of>(meta::supports_op_equal<V>(), L_, self);
}
template <typename Iter>
static detail::error_result add_insert_after(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) {
return add_insert_after(std::false_type(), L_, self, value);
}
static detail::error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) {
return detail::error_result(, detail::demangle<T>().data());
}
template <typename Iter>
static detail::error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) {
self.insert_after(pos, value.as<V>());
return {};
}
static detail::error_result add_insert_after(std::true_type, lua_State* L_, T& self, stack_object value) {
auto backit = self.before_begin();
{
auto e = deferred_uc::end(L_, self);
for (auto it = deferred_uc::begin(L_, self); it != e; ++backit, ++it) { }
}
return add_insert_after(std::true_type(), L_, self, value, backit);
}
template <typename Iter>
static detail::error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, Iter& pos) {
self.insert(pos, value.as<V>());
return {};
}
static detail::error_result add_insert(std::true_type, lua_State* L_, T& self, stack_object value) {
auto pos = deferred_uc::end(L_, self);
return add_insert(std::true_type(), L_, self, value, pos);
}
template <typename Iter>
static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) {
return add_insert_after(meta::has_insert_after<T>(), L_, self, std::move(value), pos);
}
static detail::error_result add_insert(std::false_type, lua_State* L_, T& self, stack_object value) {
return add_insert_after(meta::has_insert_after<T>(), L_, self, std::move(value));
}
template <typename Iter>
static detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, Iter&) {
self.push_back(value.as<V>());
return {};
}
static detail::error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) {
self.push_back(value.as<V>());
return {};
}
template <typename Iter>
static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) {
return add_insert(
std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L_, self, value, pos);
}
static detail::error_result add_push_back(std::false_type, lua_State* L_, T& self, stack_object value) {
return add_insert(
std::integral_constant < bool, meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (), L_, self, value);
}
template <typename Iter>
static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key, Iter& pos) {
if constexpr (meta::has_insert_with_iterator<T>::value) {
self.insert(pos, value_type(key.as<K>(), stack::unqualified_get<V>(L_, 3)));
return {};
}
else if constexpr (meta::has_insert<T>::value) {
self.insert(value_type(key.as<K>(), stack::unqualified_get<V>(L_, 3)));
return {};
}
else {
(void)L_;
(void)self;
(void)key;
(void)pos;
return detail::error_result(
, detail::demangle<T>().c_str());
}
}
static detail::error_result add_associative(std::true_type, lua_State* L_, T& self, stack_object key) {
auto pos = deferred_uc::end(L_, self);
return add_associative(std::true_type(), L_, self, std::move(key), pos);
}
template <typename Iter>
static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value, Iter& pos) {
return add_push_back(meta::has_push_back<T>(), L_, self, value, pos);
}
static detail::error_result add_associative(std::false_type, lua_State* L_, T& self, stack_object value) {
return add_push_back(meta::has_push_back<T>(), L_, self, value);
}
template <typename Iter>
static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value, Iter& pos) {
return add_associative(is_associative(), L_, self, std::move(value), pos);
}
static detail::error_result add_copyable(std::true_type, lua_State* L_, T& self, stack_object value) {
return add_associative(is_associative(), L_, self, value);
}
template <typename Iter>
static detail::error_result add_copyable(std::false_type, lua_State* L_, T& self, stack_object value, Iter&) {
return add_copyable(std::false_type(), L_, self, std::move(value));
}
static detail::error_result add_copyable(std::false_type, lua_State*, T&, stack_object) {
return detail::error_result(, detail::demangle<T>().data());
}
static detail::error_result insert_lookup(std::true_type, lua_State* L_, T& self, stack_object, stack_object value) {
// TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity?
return add_copyable(std::true_type(), L_, self, std::move(value));
}
static detail::error_result insert_lookup(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) {
auto it = deferred_uc::begin(L_, self);
auto key = where.as<K>();
key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
std::advance(it, key);
self.insert(it, value.as<V>());
return {};
}
static detail::error_result insert_after_has(std::true_type, lua_State* L_, T& self, stack_object where, stack_object value) {
auto key = where.as<K>();
auto backit = self.before_begin();
{
key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
auto e = deferred_uc::end(L_, self);
for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) {
if (backit == e) {
return detail::error_result(, detail::demangle<T>().c_str());
}
}
}
self.insert_after(backit, value.as<V>());
return {};
}
static detail::error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) {
return detail::error_result(
, detail::demangle<T>().data());
}
static detail::error_result insert_has(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) {
return insert_lookup(meta::any<is_associative, is_lookup>(), L_, self, std::move(key), std::move(value));
}
static detail::error_result insert_has(std::false_type, lua_State* L_, T& self, stack_object where, stack_object value) {
return insert_after_has(meta::has_insert_after<T>(), L_, self, where, value);
}
static detail::error_result insert_copyable(std::true_type, lua_State* L_, T& self, stack_object key, stack_object value) {
return insert_has(std::integral_constant < bool,
meta::has_insert<T>::value || meta::has_insert_with_iterator<T>::value > (),
L_,
self,
std::move(key),
std::move(value));
}
static detail::error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) {
return detail::error_result(, detail::demangle<T>().data());
}
static detail::error_result erase_integral(std::true_type, lua_State* L_, T& self, K& key) {
auto it = deferred_uc::begin(L_, self);
key = (static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
std::advance(it, key);
self.erase(it);
return {};
}
static detail::error_result erase_integral(std::false_type, lua_State* L_, T& self, const K& key) {
auto fx = [&](const value_type& r) -> bool { return key == r; };
auto e = deferred_uc::end(L_, self);
auto it = std::find_if(deferred_uc::begin(L_, self), e, std::ref(fx));
if (it == e) {
return {};
}
self.erase(it);
return {};
}
static detail::error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) {
self.erase(key);
return {};
}
static detail::error_result erase_associative_lookup(std::false_type, lua_State* L_, T& self, K& key) {
return erase_integral(std::is_integral<K>(), L_, self, key);
}
static detail::error_result erase_after_has(std::true_type, lua_State* L_, T& self, K& key) {
auto backit = self.before_begin();
{
key = static_cast<K>(static_cast<std::ptrdiff_t>(key) + deferred_uc::index_adjustment(L_, self));
auto e = deferred_uc::end(L_, self);
for (auto it = deferred_uc::begin(L_, self); key > 0; ++backit, ++it, --key) {
if (backit == e) {
return detail::error_result(, detail::demangle<T>().c_str());
}
}
}
self.erase_after(backit);
return {};
}
static detail::error_result erase_after_has(std::false_type, lua_State*, T&, const K&) {
return detail::error_result(, detail::demangle<T>().c_str());
}
static detail::error_result erase_key_has(std::true_type, lua_State* L_, T& self, K& key) {
return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L_, self, key);
}
static detail::error_result erase_key_has(std::false_type, lua_State* L_, T& self, K& key) {
return erase_after_has(has_erase_after<T>(), L_, self, key);
}
static detail::error_result erase_has(std::true_type, lua_State* L_, T& self, K& key) {
return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L_, self, key);
}
static detail::error_result erase_has(std::false_type, lua_State* L_, T& self, K& key) {
return erase_key_has(has_erase_key<T>(), L_, self, key);
}
static auto size_has(std::false_type, lua_State* L_, T& self) {
return std::distance(deferred_uc::begin(L_, self), deferred_uc::end(L_, self));
}
static auto size_has(std::true_type, lua_State*, T& self) {
return self.size();
}
static void clear_has(std::true_type, lua_State*, T& self) {
self.clear();
}
static void clear_has(std::false_type, lua_State* L_, T&) {
luaL_error(L_, , detail::demangle<T>().c_str());
}
static bool empty_has(std::true_type, lua_State*, T& self) {
return self.empty();
}
static bool empty_has(std::false_type, lua_State* L_, T& self) {
return deferred_uc::begin(L_, self) == deferred_uc::end(L_, self);
}
static detail::error_result get_associative_find(std::true_type, lua_State* L_, T& self, K& key) {
auto it = self.find(key);
if (it == deferred_uc::end(L_, self)) {
stack::push(L_, lua_nil);
return {};
}
return get_associative(std::true_type(), L_, it);
}
static detail::error_result get_associative_find(std::false_type, lua_State* L_, T& self, K& key) {
return get_it(is_linear_integral(), L_, self, key);
}
static detail::error_result get_start(lua_State* L_, T& self, K& key) {
return get_associative_find(std::integral_constant < bool, is_associative::value&& has_find<T>::value > (), L_, self, key);
}
static detail::error_result set_start(lua_State* L_, T& self, stack_object key, stack_object value) {
return set_it(is_linear_integral(), L_, self, std::move(key), std::move(value));
}
static std::size_t size_start(lua_State* L_, T& self) {
return static_cast<std::size_t>(size_has(meta::has_size<T>(), L_, self));
}
static void clear_start(lua_State* L_, T& self) {
clear_has(has_clear<T>(), L_, self);
}
static bool empty_start(lua_State* L_, T& self) {
return empty_has(has_empty<T>(), L_, self);
}
static detail::error_result erase_start(lua_State* L_, T& self, K& key) {
return erase_has(has_erase<T>(), L_, self, key);
}
template <bool ip>
static int next_associative(std::true_type, lua_State* L_) {
iter& i = stack::unqualified_get<user<iter>>(L_, 1);
auto& it = i.it;
auto& end = i.end;
if (it == end) {
return stack::push(L_, lua_nil);
}
int p;
if constexpr (ip) {
++i.index;
p = stack::push_reference(L_, i.index);
}
else {
p = stack::push_reference(L_, it->first);
}
p += stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(it->second));
std::advance(it, 1);
return p;
}
template <bool>
static int next_associative(std::false_type, lua_State* L_) {
iter& i = stack::unqualified_get<user<iter>>(L_, 1);
auto& it = i.it();
auto& end = i.sen();
next_K k = stack::unqualified_get<next_K>(L_, 2);
if (it == end) {
return stack::push(L_, lua_nil);
}
int p;
if constexpr (std::is_integral_v<next_K>) {
p = stack::push_reference(L_, k + 1);
}
else {
p = stack::stack_detail::push_reference(L_, k + 1);
}
p += stack::stack_detail::push_reference<push_type>(L_, detail::deref_move_only(*it));
std::advance(it, 1);
return p;
}
template <bool ip>
static int next_iter(lua_State* L_) {
typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc;
return next_associative<ip>(is_assoc(), L_);
}
template <bool ip>
static int pairs_associative(std::true_type, lua_State* L_) {
auto& src = get_src(L_);
stack::push(L_, next_iter<ip>);
stack::push<user<iter>>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::begin(L_, src));
stack::push(L_, lua_nil);
return 3;
}
template <bool ip>
static int pairs_associative(std::false_type, lua_State* L_) {
auto& src = get_src(L_);
stack::push(L_, next_iter<ip>);
stack::push<user<iter>>(L_, L_, 1, deferred_uc::begin(L_, src), deferred_uc::end(L_, src));
stack::push(L_, 0);
return 3;
}
public:
static int at(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er;
{
std::ptrdiff_t pos = stack::unqualified_get<std::ptrdiff_t>(L_, 2);
er = at_start(L_, self, pos);
}
return handle_errors(L_, er);
}
static int get(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er;
{
decltype(auto) key = stack::unqualified_get<K>(L_);
er = get_start(L_, self, key);
}
return handle_errors(L_, er);
}
static int index_get(lua_State* L_) {
return get(L_);
}
static int set(lua_State* L_) {
stack_object value = stack_object(L_, raw_index(3));
if constexpr (is_linear_integral::value) {
// for non-associative containers,
// erasure only happens if it is the
// last index in the container
auto key = stack::get<K>(L_, 2);
auto self_size = deferred_uc::size(L_);
if (key == static_cast<K>(self_size)) {
if (type_of(L_, 3) == type::lua_nil) {
return erase(L_);
}
}
}
else {
if (type_of(L_, 3) == type::lua_nil) {
return erase(L_);
}
}
auto& self = get_src(L_);
detail::error_result er = set_start(L_, self, stack_object(L_, raw_index(2)), std::move(value));
return handle_errors(L_, er);
}
static int index_set(lua_State* L_) {
return set(L_);
}
static int add(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er = add_copyable(is_copyable(), L_, self, stack_object(L_, raw_index(2)));
return handle_errors(L_, er);
}
static int insert(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er = insert_copyable(is_copyable(), L_, self, stack_object(L_, raw_index(2)), stack_object(L_, raw_index(3)));
return handle_errors(L_, er);
}
static int find(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er = find_has(has_find<T>(), L_, self);
return handle_errors(L_, er);
}
static int index_of(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er = find_has<true>(has_find<T>(), L_, self);
return handle_errors(L_, er);
}
static iterator begin(lua_State*, T& self) {
if constexpr (meta::has_begin_end_v<T>) {
return self.begin();
}
else {
using std::begin;
return begin(self);
}
}
static sentinel end(lua_State*, T& self) {
if constexpr (meta::has_begin_end_v<T>) {
return self.end();
}
else {
using std::end;
return end(self);
}
}
static int size(lua_State* L_) {
auto& self = get_src(L_);
std::size_t r = size_start(L_, self);
return stack::push(L_, r);
}
static int clear(lua_State* L_) {
auto& self = get_src(L_);
clear_start(L_, self);
return 0;
}
static int erase(lua_State* L_) {
auto& self = get_src(L_);
detail::error_result er;
{
decltype(auto) key = stack::unqualified_get<K>(L_, 2);
er = erase_start(L_, self, key);
}
return handle_errors(L_, er);
}
static int empty(lua_State* L_) {
auto& self = get_src(L_);
return stack::push(L_, empty_start(L_, self));
}
static std::ptrdiff_t index_adjustment(lua_State*, T&) {
return static_cast<std::ptrdiff_t>((SOL_CONTAINER_START_INDEX_I_) == 0 ? 0 : -(SOL_CONTAINER_START_INDEX_I_));
}
static int pairs(lua_State* L_) {
typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc;
return pairs_associative<false>(is_assoc(), L_);
}
static int ipairs(lua_State* L_) {
typedef meta::any<is_associative, meta::all<is_lookup, meta::neg<is_matched_lookup>>> is_assoc;
return pairs_associative<true>(is_assoc(), L_);
}
static int next(lua_State* L_) {
return stack::push(L_, next_iter<false>);
}
};
template <typename X>
struct usertype_container_default<X, std::enable_if_t<std::is_array<std::remove_pointer_t<meta::unwrap_unqualified_t<X>>>::value>> {
private:
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;
typedef usertype_container<X> deferred_uc;
public:
typedef std::remove_extent_t<T> value_type;
typedef value_type* iterator;
typedef iterator sentinel;
private:
struct iter : detail::ebco<iterator, 0>, detail::ebco<sentinel, 1> {
using it_base = detail::ebco<iterator, 0>;
using sen_base = detail::ebco<sentinel, 1>;
reference keep_alive;
iter(lua_State* L_, int stack_index_, iterator it_, sentinel sen_) noexcept
: it_base(std::move(it_)), sen_base(std::move(sen_)), keep_alive(sol::main_thread(L_, L_), stack_index_) {
}
iterator& it() noexcept {
return it_base::value();
}
const iterator& it() const noexcept {
return it_base::value();
}
sentinel& sen() noexcept {
return sen_base::value();
}
const sentinel& sen() const noexcept {
return sen_base::value();
}
};
namespace sol {
namespace meta {
namespace meta_detail {
template <typename T>
using is_dereferenceable_test = decltype(*std::declval<T>());
template <typename T>
using is_explicitly_dereferenceable_test = decltype(std::declval<T>().operator*());
} // namespace meta_detail
template <typename T>
using is_pointer_like = std::integral_constant<bool,
!std::is_array_v<T> && (std::is_pointer_v<T> || is_detected_v<meta_detail::is_explicitly_dereferenceable_test, T>)>;
template <typename T>
constexpr inline bool is_pointer_like_v = is_pointer_like<T>::value;
} // namespace meta
namespace detail {
template <typename T>
auto unwrap(T&& item) -> decltype(std::forward<T>(item)) {
return std::forward<T>(item);
}
template <typename T>
T& unwrap(std::reference_wrapper<T> arg) {
return arg.get();
}
template <typename T>
inline decltype(auto) deref(T&& item) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::is_pointer_like_v<Tu>) {
return *std::forward<T>(item);
}
else {
return std::forward<T>(item);
}
}
template <typename T>
inline decltype(auto) deref_move_only(T&& item) {
using Tu = meta::unqualified_t<T>;
if constexpr (meta::is_pointer_like_v<Tu> && !std::is_pointer_v<Tu> && !std::is_copy_constructible_v<Tu>) {
return *std::forward<T>(item);
}
else {
return std::forward<T>(item);
}
}
template <typename T>
inline T* ptr(T& val) {
return std::addressof(val);
}
template <typename T>
inline T* ptr(std::reference_wrapper<T> val) {
return std::addressof(val.get());
}
template <typename T>
inline T* ptr(T* val) {
return val;
}
} // namespace detail
} // namespace sol
#endif // SOL_POINTER_LIKE_HPP
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iosfwd> // for forward declaration of vector
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <version>
template <class _Tp, class _Allocator /* = allocator<_Tp> */>
class _LIBCPP_TEMPLATE_VIS vector
{
private:
typedef allocator<_Tp> __default_allocator_type;
public:
typedef vector __self;
typedef _Tp value_type;
typedef _Allocator allocator_type;
typedef allocator_traits<allocator_type> __alloc_traits;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef typename __alloc_traits::size_type size_type;
typedef typename __alloc_traits::difference_type difference_type;
typedef typename __alloc_traits::pointer pointer;
typedef typename __alloc_traits::const_pointer const_pointer;
// TODO: Implement iterator bounds checking without requiring the global database.
typedef __wrap_iter<pointer> iterator;
typedef __wrap_iter<const_pointer> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
static_assert((is_same<typename allocator_type::value_type, value_type>::value),
);
static_assert(is_same<allocator_type, __rebind_alloc<__alloc_traits, value_type> >::value,
);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector() _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value)
{
std::__debug_db_insert_c(this);
}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit vector(const allocator_type& __a)
#if _LIBCPP_STD_VER <= 14
_NOEXCEPT_(is_nothrow_copy_constructible<allocator_type>::value)
#else
_NOEXCEPT
#endif
: __end_cap_(nullptr, __a)
{
std::__debug_db_insert_c(this);
}
template <class = __enable_if_t<__is_allocator<_Allocator>::value> >
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(size_type __n, const value_type& __x, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
std::__debug_db_insert_c(this);
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__n, __x);
}
}
template <class _InputIterator,
__enable_if_t<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<value_type, typename iterator_traits<_InputIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_InputIterator __first, _InputIterator __last);
template <class _InputIterator,
__enable_if_t<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<value_type, typename iterator_traits<_InputIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a);
template <
class _ForwardIterator,
__enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<value_type, typename iterator_traits<_ForwardIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(_ForwardIterator __first, _ForwardIterator __last);
template <class _ForwardIterator,
__enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<value_type, typename iterator_traits<_ForwardIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a);
private:
class __destroy_vector {
public:
_LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() {
__vec_.__annotate_delete();
std::__debug_db_erase_c(std::addressof(__vec_));
if (__vec_.__begin_ != nullptr) {
__vec_.__clear();
__alloc_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.capacity());
}
}
private:
vector& __vec_;
};
public:
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~vector() { __destroy_vector(*this)(); }
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x, const __type_identity_t<allocator_type>& __a);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector& operator=(const vector& __x);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(initializer_list<value_type> __il);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(initializer_list<value_type> __il, const allocator_type& __a);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector& operator=(initializer_list<value_type> __il)
{assign(__il.begin(), __il.end()); return *this;}
#endif // !_LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(vector&& __x)
#if _LIBCPP_STD_VER > 14
noexcept;
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
#endif
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector(vector&& __x, const __type_identity_t<allocator_type>& __a);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
vector& operator=(vector&& __x)
_NOEXCEPT_((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value));
template <class _InputIterator,
__enable_if_t<__is_exactly_cpp17_input_iterator<_InputIterator>::value &&
is_constructible<value_type, typename iterator_traits<_InputIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_InputIterator __first, _InputIterator __last);
template <
class _ForwardIterator,
__enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<value_type, typename iterator_traits<_ForwardIterator>::reference>::value,
int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const_reference __u);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
void assign(initializer_list<value_type> __il)
{assign(__il.begin(), __il.end());}
#endif
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
allocator_type get_allocator() const _NOEXCEPT
{return this->__alloc();}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT;
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT;
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT;
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT;
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
reverse_iterator rbegin() _NOEXCEPT
{return reverse_iterator(end());}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
const_reverse_iterator rbegin() const _NOEXCEPT
{return const_reverse_iterator(end());}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
reverse_iterator rend() _NOEXCEPT
{return reverse_iterator(begin());}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
const_reverse_iterator rend() const _NOEXCEPT
{return const_reverse_iterator(begin());}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
const_iterator cbegin() const _NOEXCEPT
{return begin();}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
const_iterator cend() const _NOEXCEPT
{return end();}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
const_reverse_iterator crbegin() const _NOEXCEPT
{return rbegin();}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
const_reverse_iterator crend() const _NOEXCEPT
{return rend();}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
size_type size() const _NOEXCEPT
{return static_cast<size_type>(this->__end_ - this->__begin_);}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
size_type capacity() const _NOEXCEPT
{return static_cast<size_type>(__end_cap() - this->__begin_);}
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
bool empty() const _NOEXCEPT
{return this->__begin_ == this->__end_;}
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT;
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n);
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT;
template <class _Tp, class _Allocator>
template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<_Tp, typename iterator_traits<_ForwardIterator>::reference>::value,
int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last, __n);
}
__guard.__complete();
}
template <class _Tp, class _Allocator>
template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_ForwardIterator>::value &&
is_constructible<_Tp, typename iterator_traits<_ForwardIterator>::reference>::value,
int> >
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
: __end_cap_(nullptr, __a)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = static_cast<size_type>(std::distance(__first, __last));
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__first, __last, __n);
}
__guard.__complete();
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(const vector& __x)
: __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc()))
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = __x.size();
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
}
__guard.__complete();
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
: __end_cap_(nullptr, __a)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
size_type __n = __x.size();
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__x.__begin_, __x.__end_, __n);
}
__guard.__complete();
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(vector&& __x)
#if _LIBCPP_STD_VER > 14
noexcept
#else
_NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value)
#endif
: __end_cap_(nullptr, std::move(__x.__alloc()))
{
std::__debug_db_insert_c(this);
std::__debug_db_swap(this, std::addressof(__x));
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
this->__end_cap() = __x.__end_cap();
__x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr;
}
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_type>& __a)
: __end_cap_(nullptr, __a)
{
std::__debug_db_insert_c(this);
if (__a == __x.__alloc())
{
this->__begin_ = __x.__begin_;
this->__end_ = __x.__end_;
this->__end_cap() = __x.__end_cap();
__x.__begin_ = __x.__end_ = __x.__end_cap() = nullptr;
std::__debug_db_swap(this, std::addressof(__x));
}
else
{
typedef move_iterator<iterator> _Ip;
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
assign(_Ip(__x.begin()), _Ip(__x.end()));
__guard.__complete();
}
}
#ifndef _LIBCPP_CXX03_LANG
template <class _Tp, class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
inline _LIBCPP_HIDE_FROM_ABI
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il)
{
auto __guard = std::__make_exception_guard(__destroy_vector(*this));
std::__debug_db_insert_c(this);
if (__il.size() > 0)
{
__vallocate(__il.size());
__construct_at_end(__il.begin(), __il.end(), __il.size());
}
__guard.__complete();
}
// vector<bool>
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20
vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const allocator_type& __a)
: __begin_(nullptr),
__size_(0),
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
{
if (__n > 0)
{
__vallocate(__n);
__construct_at_end(__n, __x);
}
}
template <class _Key, class _Cp, class _Hash, class _Pred,
bool = is_empty<_Hash>::value && !__libcpp_is_final<_Hash>::value>
class __unordered_map_hasher
: private _Hash
{
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_hasher()
_NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value)
: _Hash() {}
_LIBCPP_INLINE_VISIBILITY
__unordered_map_hasher(const _Hash& __h)
_NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
: _Hash(__h) {}
_LIBCPP_INLINE_VISIBILITY
const _Hash& hash_function() const _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Cp& __x) const
{return static_cast<const _Hash&>(*this)(__x.__get_value().first);}
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Key& __x) const
{return static_cast<const _Hash&>(*this)(__x);}
#if _LIBCPP_STD_VER > 17
template <typename _K2>
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _K2& __x) const
{return static_cast<const _Hash&>(*this)(__x);}
#endif
_LIBCPP_INLINE_VISIBILITY
void swap(__unordered_map_hasher& __y)
_NOEXCEPT_(__is_nothrow_swappable<_Hash>::value)
{
using _VSTD::swap;
swap(static_cast<_Hash&>(*this), static_cast<_Hash&>(__y));
}
};
template <class _Key, class _Cp, class _Hash, class _Pred>
class __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, false>
{
_Hash __hash_;
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_hasher()
_NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value)
: __hash_() {}
_LIBCPP_INLINE_VISIBILITY
__unordered_map_hasher(const _Hash& __h)
_NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value)
: __hash_(__h) {}
_LIBCPP_INLINE_VISIBILITY
const _Hash& hash_function() const _NOEXCEPT {return __hash_;}
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Cp& __x) const
{return __hash_(__x.__get_value().first);}
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _Key& __x) const
{return __hash_(__x);}
#if _LIBCPP_STD_VER > 17
template <typename _K2>
_LIBCPP_INLINE_VISIBILITY
size_t operator()(const _K2& __x) const
{return __hash_(__x);}
#endif
_LIBCPP_INLINE_VISIBILITY
void swap(__unordered_map_hasher& __y)
_NOEXCEPT_(__is_nothrow_swappable<_Hash>::value)
{
using _VSTD::swap;
swap(__hash_, __y.__hash_);
}
};
template <class _Key, class _Cp, class _Hash, class _Pred, bool __b>
inline _LIBCPP_INLINE_VISIBILITY
void
swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __x,
__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{
__x.swap(__y);
}
template <class _Key, class _Cp, class _Pred, class _Hash,
bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value>
class __unordered_map_equal
: private _Pred
{
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_equal()
_NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value)
: _Pred() {}
_LIBCPP_INLINE_VISIBILITY
__unordered_map_equal(const _Pred& __p)
_NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value)
: _Pred(__p) {}
_LIBCPP_INLINE_VISIBILITY
const _Pred& key_eq() const _NOEXCEPT {return *this;}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _Cp& __y) const
{return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y.__get_value().first);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _Key& __y) const
{return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);}
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Key& __x, const _Cp& __y) const
{return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);}
#if _LIBCPP_STD_VER > 17
template <typename _K2>
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Cp& __x, const _K2& __y) const
{return static_cast<const _Pred&>(*this)(__x.__get_value().first, __y);}
template <typename _K2>
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _K2& __x, const _Cp& __y) const
{return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first);}
template <typename _K2>
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _Key& __x, const _K2& __y) const
{return static_cast<const _Pred&>(*this)(__x, __y);}
template <typename _K2>
_LIBCPP_INLINE_VISIBILITY
bool operator()(const _K2& __x, const _Key& __y) const
{return static_cast<const _Pred&>(*this)(__x, __y);}
#endif
_LIBCPP_INLINE_VISIBILITY
void swap(__unordered_map_equal& __y)
_NOEXCEPT_(__is_nothrow_swappable<_Pred>::value)
{
using _VSTD::swap;
swap(static_cast<_Pred&>(*this), static_cast<_Pred&>(__y));
}
};
template <class _Key, class _Cp, class _Pred, class _Hash>
class __unordered_map_equal<_Key, _Cp, _Pred, _Hash, false>
{
_Pred __pred_;
public:
_LIBCPP_INLINE_VISIBILITY
__unordered_map_equal()
_NOEXCEPT_(is_nothrow_default_constructibl_x, __y);}
#endif
_LIBCPP_INLINE_VISIBILITY
void swap(__unordered_map_equal& __y)
_NOEXCEPT_(__is_nothrow_swappable<_Pred>::value)
{
using _VSTD::swap;
swap(__pred_, __y.__pred_);
}
};
template <class _Key, class _Cp, class _Pred, class _Hash, bool __b>
inline _LIBCPP_INLINE_VISIBILITY
void
swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __x,
__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{
__x.swap(__y);
}
template <class _Alloc>
class __hash_map_node_destructor
{
typedef _Alloc allocator_type;
typedef allocator_traits<allocator_type> __alloc_traits;
public:
typedef typename __alloc_traits::pointer pointer;
private:
allocator_type& __na_;
__hash_map_node_destructor& operator=(const __hash_map_node_destructor&);
public:
bool __first_constructed;
bool __second_constructed;
_LIBCPP_INLINE_VISIBILITY
explicit __hash_map_node_destructor(allocator_type& __na) _NOEXCEPT
: __na_(__na),
__first_constructed(false),
__second_constructed(false)
{}
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
__hash_map_node_destructor(__hash_node_destructor<allocator_type>&& __x)
_NOEXCEPT
: __na_(__x.__na_),
__first_constructed(__x.__value_constructed),
__second_constructed(__x.__value_constructed)
{
__x.__value_constructed = false;
}
#else // _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
__hash_map_node_destructor(const __hash_node_destructor<allocator_type>& __x)
: __na_(__x.__na_),
__first_constructed(__x.__value_constructed),
__second_constructed(__x.__value_constructed)
{
const_cast<bool&>(__x.__value_constructed) = false;
}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
void operator()(pointer __p) _NOEXCEPT
{
if (__second_constructed)
__alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__get_value().second));
if (__first_constructed)
__alloc_traits::destroy(__na_, _VSTD::addressof(__p->__value_.__get_value().first));
if (__p)
__alloc_traits::deallocate(__na_, __p, 1);
}
};
#ifndef _LIBCPP_CXX03_LANG
template <class _Key, class _Tp>
struct _LIBCPP_STANDALONE_DEBUG __hash_value_type
{
typedef _Key key_type;
typedef _Tp mapped_type;
typedef pair<const key_type, mapped_type> value_type;
typedef pair<key_type&, mapped_type&> __nc_ref_pair_type;
typedef pair<key_type&&, mapped_type&&> __nc_rref_pair_type;
private:
value_type __cc_;
public:
_LIBCPP_INLINE_VISIBILITY
value_type& __get_value()
{
#if _LIBCPP_STD_VER > 14
return *_VSTD::launder(_VSTD::addressof(__cc_));
#else
return __cc_;
#endif
}
_LIBCPP_INLINE_VISIBILITY
const value_type& __get_value() const
{
#if _LIBCPP_STD_VER > 14
return *_VSTD::launder(_VSTD::addressof(__cc_));
#else
return __cc_;
#endif
}
_LIBCPP_INLINE_VISIBILITY
__nc_ref_pair_type __ref()
{
value_type& __v = __get_value();
return __nc_ref_pair_type(const_cast<key_type&>(__v.first), __v.second);
}
_LIBCPP_INLINE_VISIBILITY
__nc_rref_pair_type __move()
{
value_type& __v = __get_value();
return __nc_rref_pair_type(
_VSTD::move(const_cast<key_type&>(__v.first)),
_VSTD::move(__v.second));
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
size_type __n, const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__n);
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
size_type __n, const hasher& __hf, const key_equal& __eql,
const allocator_type& __a)
: __table_(__hf, __eql, typename __table::allocator_type(__a))
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__n);
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const allocator_type& __a)
: __table_(typename __table::allocator_type(__a))
{
_VSTD::__debug_db_insert_c(this);
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _InputIterator>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
_InputIterator __first, _InputIterator __last)
{
_VSTD::__debug_db_insert_c(this);
insert(__first, __last);
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _InputIterator>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
_InputIterator __first, _InputIterator __last, size_type __n,
const hasher& __hf, const key_equal& __eql)
: __table_(__hf, __eql)
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__n);
insert(__first, __last);
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _InputIterator>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
_InputIterator __first, _InputIterator __last, size_type __n,
const hasher& __hf, const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, typename __table::allocator_type(__a))
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__n);
insert(__first, __last);
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const unordered_map& __u)
: __table_(__u.__table_)
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__u.bucket_count());
insert(__u.begin(), __u.end());
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
const unordered_map& __u, const allocator_type& __a)
: __table_(__u.__table_, typename __table::allocator_type(__a))
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__u.bucket_count());
insert(__u.begin(), __u.end());
}
#ifndef _LIBCPP_CXX03_LANG
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
unordered_map&& __u)
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value)
: __table_(_VSTD::move(__u.__table_))
{
_VSTD::__debug_db_insert_c(this);
std::__debug_db_swap(this, std::addressof(__u));
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
unordered_map&& __u, const allocator_type& __a)
: __table_(_VSTD::move(__u.__table_), typename __table::allocator_type(__a))
{
_VSTD::__debug_db_insert_c(this);
if (__a != __u.get_allocator())
{
iterator __i = __u.begin();
while (__u.size() != 0) {
__table_.__emplace_unique(
__u.__table_.remove((__i++).__i_)->__value_.__move());
}
}
else
std::__debug_db_swap(this, std::addressof(__u));
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
initializer_list<value_type> __il)
{
_VSTD::__debug_db_insert_c(this);
insert(__il.begin(), __il.end());
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
initializer_list<value_type> __il, size_type __n, const hasher& __hf,
const key_equal& __eql)
: __table_(__hf, __eql)
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__n);
insert(__il.begin(), __il.end());
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(
initializer_list<value_type> __il, size_type __n, const hasher& __hf,
const key_equal& __eql, const allocator_type& __a)
: __table_(__hf, __eql, typename __table::allocator_type(__a))
{
_VSTD::__debug_db_insert_c(this);
__table_.__rehash_unique(__n);
insert(__il.begin(), __il.end());
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_map&& __u)
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value)
{
__table_ = _VSTD::move(__u.__table_);
return *this;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(
initializer_list<value_type> __il)
{
__table_.__assign_unique(__il.begin(), __il.end());
return *this;
}
#endif // _LIBCPP_CXX03_LANG
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
template <class _InputIterator>
inline
void
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_InputIterator __first,
_InputIterator __last)
{
for (; __first != __last; ++__first)
__table_.__insert_unique(*__first);
}
#ifndef _LIBCPP_CXX03_LANG
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_Tp&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k)
{
return __table_.__emplace_unique_key_args(__k,
piecewise_construct, _VSTD::forward_as_tuple(__k),
_VSTD::forward_as_tuple()).first->__get_value().second;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_Tp&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k)
{
return __table_.__emplace_unique_key_args(__k,
piecewise_construct, _VSTD::forward_as_tuple(_VSTD::move(__k)),
_VSTD::forward_as_tuple()).first->__get_value().second;
}
#else // _LIBCPP_CXX03_LANG
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__construct_node_with_key(const key_type& __k)
{
__node_allocator& __na = __table_.__node_alloc();
__node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na));
__node_traits::construct(__na, _VSTD::addressof(__h->__value_.__get_value().first), __k);
__h.get_deleter().__first_constructed = true;
__node_traits::construct(__na, _VSTD::addressof(__h->__value_.__get_value().second));
__h.get_deleter().__second_constructed = true;
return __h;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_Tp&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k)
{
iterator __i = find(__k);
if (__i != end())
return __i->second;
__node_holder __h = __construct_node_with_key(__k);
pair<iterator, bool> __r = __table_.__node_insert_unique(__h.get());
__h.release();
return __r.first->second;
}
#endif // _LIBCPP_CXX03_LANG
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_Tp&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k)
{
iterator __i = find(__k);
if (__i == end())
__throw_out_of_range();
return __i->second;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
const _Tp&
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k) const
{
const_iterator __i = find(__k);
if (__i == end())
__throw_out_of_range();
return __i->second;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline _LIBCPP_INLINE_VISIBILITY
void
swap(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
_NOEXCEPT_(_NOEXCEPT_(__x.swap(__y)))
{
__x.swap(__y);
}
#if _LIBCPP_STD_VER > 17
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc,
class _Predicate>
inline _LIBCPP_INLINE_VISIBILITY
typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type
erase_if(unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __c,
_Predicate __pred) {
return _VSTD::__libcpp_erase_if_container(__c, __pred);
}
#endif
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
_LIBCPP_HIDE_FROM_ABI bool
operator==(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
{
if (__x.size() != __y.size())
return false;
typedef typename unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::const_iterator
const_iterator;
for (const_iterator __i = __x.begin(), __ex = __x.end(), __ey = __y.end();
__i != __ex; ++__i)
{
const_iterator __j = __y.find(__i->first);
if (__j == __ey || !(*__i == *__j))
return false;
}
return true;
}
template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc>
inline _LIBCPP_INLINE_VISIBILITY
bool
operator!=(const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __x,
const unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& __y)
{
return !(__x == __y);
}
template <class _Key, class _Tp, class _Hash = hash<_Key>, class _Pred = equal_to<_Key>,
class _Alloc = allocator<pair<const _Key, _Tp> > >
class _LIBCPP_TEMPLATE_VIS unordered_multimap
{
public:
// types
typedef _Key key_type;
typedef _Tp mapped_type;
typedef __type_identity_t<_Hash> hasher;
typedef __type_identity_t<_Pred> key_equal;
typedef __type_identity_t<_Alloc> allocator_type;
typedef pair<const key_type, mapped_type> value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
static_assert((is_same<value_type, typename allocator_type::value_type>::value),
);
private:
typedef __hash_value_type<key_type, mapped_type> __value_type;
typedef __unordered_map_hasher<key_type, __value_type, hasher, key_equal> __hasher;
typedef __unordered_map_equal<key_type, __value_type, key_equal, hasher> __key_equal;
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
typedef __hash_table<__value_type, __hasher,
__key_equal, __allocator_type> __table;
__table __table_;
typedef typename __table::_NodeTypes _NodeTypes;
typedef typename __table::__node_traits __node_traits;
typedef typename __table::__node_allocator __node_allocator;
typedef typename __table::__node __node;
typedef __hash_map_node_destructor<__node_allocator> _Dp;
typedef unique_ptr<__node, _Dp> __node_holder;
typedef allocator_traits<allocator_type> __alloc_traits;
static_assert((is_same<typename __node_traits::size_type,
typename __alloc_traits::size_type>::value),
);
static_assert(is_same<allocator_type, __rebind_alloc<__alloc_traits, value_type> >::value,
);
public:
typedef typename __alloc_traits::pointer pointer;
typedef typename __alloc_traits::const_pointer const_pointer;
typedef typename __table::size_type size_type;
typedef typename __table::difference_type difference_type;
typedef __hash_map_iterator<typename __table::iterator> iterator;
typedef __hash_map_const_iterator<typename __table::const_iterator> const_iterator;
typedef __hash_map_iterator<typename __table::local_iterator> local_iterator;
typedef __hash_map_const_iterator<typename __table::const_local_iterator> const_local_iterator;
#if _LIBCPP_STD_VER > 14
typedef __map_node_handle<__node, allocator_type> node_type;
#endif
template <class _Key2, class _Tp2, class _Hash2, class _Pred2, class _Alloc2>
friend class _LIBCPP_TEMPLATE_VIS unordered_map;
template <class _Key2, class _Tp2, class _Hash2, class _Pred2, class _Alloc2>
friend class _LIBCPP_TEMPLATE_VIS unordered_multimap;
_LIBCPP_INLINE_VISIBILITY
unordered_multimap()
_NOEXCEPT_(is_nothrow_default_constructible<__table>::value)
{
_VSTD::__debug_db_insert_c(this);
}
explicit unordered_multimap(size_type __n, const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
unordered_multimap(size_type __n, const hasher& __hf,
const key_equal& __eql,
const allocator_type& __a);
template <class _InputIterator>
unordered_multimap(_InputIterator __first, _InputIterator __last);
template <class _InputIterator>
unordered_multimap(_InputIterator __first, _InputIterator __last,
size_type __n, const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
template <class _InputIterator>
unordered_multimap(_InputIterator __first, _InputIterator __last,
size_type __n, const hasher& __hf,
const key_equal& __eql,
const allocator_type& __a);
_LIBCPP_INLINE_VISIBILITY
explicit unordered_multimap(const allocator_type& __a);
unordered_multimap(const unordered_multimap& __u);
unordered_multimap(const unordered_multimap& __u, const allocator_type& __a);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(unordered_multimap&& __u)
_NOEXCEPT_(is_nothrow_move_constructible<__table>::value);
unordered_multimap(unordered_multimap&& __u, const allocator_type& __a);
unordered_multimap(initializer_list<value_type> __il);
unordered_multimap(initializer_list<value_type> __il, size_type __n,
const hasher& __hf = hasher(),
const key_equal& __eql = key_equal());
unordered_multimap(initializer_list<value_type> __il, size_type __n,
const hasher& __hf, const key_equal& __eql,
const allocator_type& __a);
#endif // _LIBCPP_CXX03_LANG
#if _LIBCPP_STD_VER > 11
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(size_type __n, const allocator_type& __a)
: unordered_multimap(__n, hasher(), key_equal(), __a) {}
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(size_type __n, const hasher& __hf, const allocator_type& __a)
: unordered_multimap(__n, __hf, key_equal(), __a) {}
template <class _InputIterator>
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(_InputIterator __first, _InputIterator __last, size_type __n, const allocator_type& __a)
: unordered_multimap(__first, __last, __n, hasher(), key_equal(), __a) {}
template <class _InputIterator>
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(_InputIterator __first, _InputIterator __last, size_type __n, const hasher& __hf,
const allocator_type& __a)
: unordered_multimap(__first, __last, __n, __hf, key_equal(), __a) {}
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(initializer_list<value_type> __il, size_type __n, const allocator_type& __a)
: unordered_multimap(__il, __n, hasher(), key_equal(), __a) {}
_LIBCPP_INLINE_VISIBILITY
unordered_multimap(initializer_list<value_type> __il, size_type __n, const hasher& __hf,
const allocator_type& __a)
: unordered_multimap(__il, __n, __hf, key_equal(), __a) {}
#endif
_LIBCPP_INLINE_VISIBILITY
~unordered_multimap() {
static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), );
}
_LIBCPP_INLINE_VISIBILITY
unordered_multimap& operator=(const unordered_multimap& __u)
{
#ifndef _LIBCPP_CXX03_LANG
__table_ = __u.__table_;
#else
if (this != _VSTD::addressof(__u)) {
__table_.clear();
__table_.hash_function() = __u.__table_.hash_function();
__table_.key_eq() = __u.__table_.key_eq();
__table_.max_load_factor() = __u.__table_.max_load_factor();
__table_.__copy_assign_alloc(__u.__table_);
insert(__u.begin(), __u.end());
}
#endif
return *this;
}
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
unordered_multimap& operator=(unordered_multimap&& __u)
_NOEXCEPT_(is_nothrow_move_assignable<__table>::value);
_LIBCPP_INLINE_VISIBILITY
unordered_multimap& operator=(initializer_list<value_type> __il);
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
allocator_type get_allocator() const _NOEXCEPT
{return allocator_type(__table_.__node_alloc());}
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
bool empty() const _NOEXCEPT {return __table_.size() == 0;}
_LIBCPP_INLINE_VISIBILITY
size_type size() const _NOEXCEPT {return __table_.size();}
_LIBCPP_INLINE_VISIBILITY
size_type max_size() const _NOEXCEPT {return __table_.max_size();}
_LIBCPP_INLINE_VISIBILITY
iterator begin() _NOEXCEPT {return __table_.begin();}
_LIBCPP_INLINE_VISIBILITY
iterator end() _NOEXCEPT {return __table_.end();}
_LIBCPP_INLINE_VISIBILITY
const_iterator begin() const _NOEXCEPT {return __table_.begin();}
_LIBCPP_INLINE_VISIBILITY
const_iterator end() const _NOEXCEPT {return __table_.end();}
_LIBCPP_INLINE_VISIBILITY
const_iterator cbegin() const _NOEXCEPT {return __table_.begin();}
_LIBCPP_INLINE_VISIBILITY
const_iterator cend() const _NOEXCEPT {return __table_.end();}
_LIBCPP_INLINE_VISIBILITY
iterator insert(const value_type& __x) {return __table_.__insert_multi(__x);}
_LIBCPP_INLINE_VISIBILITY
iterator insert(const_iterator __p, const value_type& __x)
{return __table_.__insert_multi(__p.__i_, __x);}
template <class _InputIterator>
_LIBCPP_INLINE_VISIBILITY
void insert(_InputIterator __first, _InputIterator __last);
#ifndef _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
void insert(initializer_list<value_type> __il)
{insert(__il.begin(), __il.end());}
_LIBCPP_INLINE_VISIBILITY
iterator insert(value_type&& __x) {return __table_.__insert_multi(_VSTD::move(__x));}
_LIBCPP_INLINE_VISIBILITY
iterator insert(const_iterator __p, value_type&& __x)
{return __table_.__insert_multi(__p.__i_, _VSTD::move(__x));}
template <class _Pp,
class = __enable_if_t<is_constructible<value_type, _Pp>::value> >
_LIBCPP_INLINE_VISIBILITY
iterator insert(_Pp&& __x)
{return __table_.__insert_multi(_VSTD::forward<_Pp>(__x));}
template <class _Pp,
class = __enable_if_t<is_constructible<value_type, _Pp>::value> >
_LIBCPP_INLINE_VISIBILITY
iterator insert(const_iterator __p, _Pp&& __x)
{return __table_.__insert_multi(__p.__i_, _VSTD::forward<_Pp>(__x));}
template <class... _Args>
iterator emplace(_Args&&... __args) {
return __table_.__emplace_multi(_VSTD::forward<_Args>(__args)...);
}
template <class... _Args>
iterator emplace_hint(const_iterator __p, _Args&&... __args) {
return __table_.__emplace_hint_multi(__p.__i_, _VSTD::forward<_Args>(__args)...);
}
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_INLINE_VISIBILITY
iterator erase(const_iterator __p) {return __table_.erase(__p.__i_);}
_LIBCPP_INLINE_VISIBILITY
iterator erase(iterator __p) {return __table_.erase(__p.__i_);}
_LIBCPP_INLINE_VISIBILITY
size_type erase(const key_type& __k) {return __table_.__erase_multi(__k);}
_LIBCPP_INLINE_VISIBILITY
iterator erase(const_iterator __first, const_iterator __last)
{return __table_.erase(__first.__i_, __last.__i_);}
_LIBCPP_INLINE_VISIBILITY
void clear() _NOEXCEPT {__table_.clear();}
#if _LIBCPP_STD_VER > 14
_LIBCPP_INLINE_VISIBILITY
iterator insert(node_type&& __nh)
{
_LIBCPP_ASSERT(__nh.empty() || __nh.get_allocator() == get_allocator(),
);
return __table_.template __node_handle_insert_multi<node_type>(
_VSTD::move(__nh));
}
_LIBCPP_INLINE_VISIBILITY
iterator insert(const_iterator __hint, node_type&& __nh)
{
_LIBCPP_ASSERT(__nh.empty() || __nh.get_allocator() == get_allocator(),
);
return __table_.template __node_handle_insert_multi<node_type>(
__hint.__i_, _VSTD::move(__nh));
}
_LIBCPP_INLINE_VISIBILITY
node_type extract(key_type const& __key)
{
return __table_.template __node_handle_extract<node_type>(__key);
}
_LIBCPP_INLINE_VISIBILITY
node_type extract(const_iterator __it)
{
return __table_.template __node_handle_extract<node_type>(
__it.__i_);
}
template <class _H2, class _P2>
_LIBCPP_INLINE_VISIBILITY
void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>& __source)
{
_LIBCPP_ASSERT(__source.get_allocator() == get_allocator(),
);
return __table_.__node_handle_merge_multi(__source.__table_);
}
template <class _H2, class _P2>
_LIBCPP_INLINE_VISIBILITY
void merge(unordered_multimap<key_type, mapped_type, _H2, _P2, allocator_type>&& __source)
{
_LIBCPP_ASSERT(__source.get_allocator() == get_allocator(),
);
return __table_.__node_handle_merge_multi(__source.__table_);
}
template <class _H2, class _P2>
_LIBCPP_INLINE_VISIBILITY
void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>& __source)
{
_LIBCPP_ASSERT(__source.get_allocator() == get_allocator(),
);
return __table_.__node_handle_merge_multi(__source.__table_);
}
template <class _H2, class _P2>
_LIBCPP_INLINE_VISIBILITY
void merge(unordered_map<key_type, mapped_type, _H2, _P2, allocator_type>&& __source)
{
_LIBCPP_ASSERT(__source.get_allocator() == get_allocator(),
);
return __table_.__node_handle_merge_multi(__source.__table_);
}
#endif
_LIBCPP_INLINE_VISIBILITY
void swap(unordered_multimap& __u)
_NOEXCEPT_(__is_nothrow_swappable<__table>::value)
{__table_.swap(__u.__table_);}
_LIBCPP_INLINE_VISIBILITY
hasher hash_function() const
{return __table_.hash_function().hash_function();}
_LIBCPP_INLINE_VISIBILITY
key_equal key_eq() const
{return __table_.key_eq().key_eq();}
_LIBCPP_INLINE_VISIBILITY
iterator find(const key_type& __k) {return __table_.find(__k);}
_LIBCPP_INLINE_VISIBILITY
const_iterator find(const key_type& __k) const {return __table_.find(__k);}
#if _LIBCPP_STD_VER > 17
template <class _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value>* = nullptr>
_LIBCPP_INLINE_VISIBILITY
iterator find(const _K2& __k) {return __table_.find(__k);}
template <class _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value>* = nullptr>
_LIBCPP_INLINE_VISIBILITY
const_iterator find(const _K2& __k) const {return __table_.find(__k);}
#endif // _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY
size_type count(const key_type& __k) const {return __table_.__count_multi(__k);}
#if _LIBCPP_STD_VER > 17
template <class _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value>* = nullptr>
_LIBCPP_INLINE_VISIBILITY
size_type count(const _K2& __k) const {return __table_.__count_multi(__k);}
#endif // _LIBCPP_STD_VER > 17
#if _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY
bool contains(const key_type& __k) const {return find(__k) != end();}
template <class _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value>* = nullptr>
_LIBCPP_INLINE_VISIBILITY
bool contains(const _K2& __k) const {return find(__k) != end();}
#endif // _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY
pair<iterator, iterator> equal_range(const key_type& __k)
{return __table_.__equal_range_multi(__k);}
_LIBCPP_INLINE_VISIBILITY
pair<const_iterator, const_iterator> equal_range(const key_type& __k) const
{return __table_.__equal_range_multi(__k);}
#if _LIBCPP_STD_VER > 17
template <class _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value>* = nullptr>
_LIBCPP_INLINE_VISIBILITY
pair<iterator, iterator> equal_range(const _K2& __k)
{return __table_.__equal_range_multi(__k);}
template <class _K2, enable_if_t<__is_transparent<hasher, _K2>::value && __is_transparent<key_equal, _K2>::value>* = nullptr>
_LIBCPP_INLINE_VISIBILITY
pair<const_iterator, const_iterator> equal_range(const _K2& __k) const
{return __table_.__equal_range_multi(__k);}
#endif // _LIBCPP_STD_VER > 17
_LIBCPP_INLINE_VISIBILITY
size_type bucket_count() const _NOEXCEPT {return __table_.bucket_count();}
_LIBCPP_INLINE_VISIBILITY
size_type max_bucket_count() const _NOEXCEPT
{return __table_.max_bucket_count();}
_LIBCPP_INLINE_VISIBILITY
size_type bucket_size(size_type __n) const
{return __table_.bucket_size(__n);}
_LIBCPP_INLINE_VISIBILITY
size_type bucket(const key_type& __k) const {return __table_.bucket(__k);}
_LIBCPP_INLINE_VISIBILITY
local_iterator begin(size_type __n) {return __table_.begin(__n);}
_LIBCPP_INLINE_VISIBILITY
local_iterator end(size_type __n) {return __table_.end(__n);}
_LIBCPP_INLINE_VISIBILITY
const_local_iterator begin(size_type __n) const {return __table_.cbegin(__n);}
_LIBCPP_INLINE_VISIBILITY
const_local_iterator end(size_type __n) const {return __table_.cend(__n);}
_LIBCPP_INLINE_VISIBILITY
const_local_iterator cbegin(size_type __n) const {return __table_.cbegin(__n);}
_LIBCPP_INLINE_VISIBILITY
const_local_iterator cend(size_type __n) const {return __table_.cend(__n);}
_LIBCPP_INLINE_VISIBILITY
float load_factor() const _NOEXCEPT {return __table_.load_factor();}
_LIBCPP_INLINE_VISIBILITY
float max_load_factor() const _NOEXCEPT {return __table_.max_load_factor();}
_LIBCPP_INLINE_VISIBILITY
void max_load_factor(float __mlf) {__table_.max_load_factor(__mlf);}
_LIBCPP_INLINE_VISIBILITY
void rehash(size_type __n) {__table_.__rehash_multi(__n);}
_LIBCPP_INLINE_VISIBILITY
void reserve(size_type __n) {__table_.__reserve_multi(__n);}
#ifdef _LIBCPP_ENABLE_DEBUG_MODE
bool __dereferenceable(const const_iterator* __i) const
{return __table_.__dereferenceable(_VSTD::addressof(__i->__i_));}
bool __decrementable(const const_iterator* __i) const
{return __table_.__decrementable(_VSTD::addressof(__i->__i_));}
bool __addable(const const_iterator* __i, ptrdiff_t __n) const
{return __table_.__addable(_VSTD::addressof(__i->__i_), __n);}
bool __subscriptable(const const_iterator* __i, ptrdiff_t __n) const
{return __table_.__addable(_VSTD::addressof(__i->__i_), __n);}
#endif // _LIBCPP_ENABLE_DEBUG_MODE
};
#if _LIBCPP_STD_VER >= 17
template<class _InputIterator,
class _Hash = hash<__iter_key_type<_InputIterator>>,
class _Pred = equal_to<__iter_key_type<_InputIterator>>,
class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>,
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
class = enable_if_t<!__is_allocator<_Hash>::value>,
class = enable_if_t<!is_integral<_Hash>::value>,
class = enable_if_t<!__is_allocator<_Pred>::value>,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0,
_Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
-> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Hash, _Pred, _Allocator>;
template<class _Key, class _Tp, class _Hash = hash<remove_const_t<_Key>>,
class _Pred = equal_to<remove_const_t<_Key>>,
class _Allocator = allocator<pair<const _Key, _Tp>>,
class = enable_if_t<!__is_allocator<_Hash>::value>,
class = enable_if_t<!is_integral<_Hash>::value>,
class = enable_if_t<!__is_allocator<_Pred>::value>,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type = 0,
_Hash = _Hash(), _Pred = _Pred(), _Allocator = _Allocator())
-> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>;
template<class _InputIterator, class _Allocator,
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator)
-> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
template<class _InputIterator, class _Allocator,
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(_InputIterator, _InputIterator, _Allocator)
-> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
hash<__iter_key_type<_InputIterator>>, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
template<class _InputIterator, class _Hash, class _Allocator,
class = enable_if_t<__is_cpp17_input_iterator<_InputIterator>::value>,
class = enable_if_t<!__is_allocator<_Hash>::value>,
class = enable_if_t<!is_integral<_Hash>::value>,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator)
-> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>,
_Hash, equal_to<__iter_key_type<_InputIterator>>, _Allocator>;
template<class _Key, class _Tp, class _Allocator,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Allocator)
-> unordered_multimap<remove_const_t<_Key>, _Tp,
hash<remove_const_t<_Key>>,
equal_to<remove_const_t<_Key>>, _Allocator>;
template<class _Key, class _Tp, class _Allocator,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(initializer_list<pair<_Key, _Tp>>, _Allocator)
-> unordered_multimap<remove_const_t<_Key>, _Tp,
hash<remove_const_t<_Key>>,
equal_to<remove_const_t<_Key>>, _Allocator>;
template<class _Key, class _Tp, class _Hash, class _Allocator,
class = enable_if_t<!__is_allocator<_Hash>::value>,
class = enable_if_t<!is_integral<_Hash>::value>,
class = enable_if_t<__is_allocator<_Allocator>::value>>
unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator)
-> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash,
equal_to<remove_const_t<_Key>>, _Allocator>;
#endif