mirror of
https://github.com/seekrs/MacroLibX.git
synced 2026-01-11 14:43:34 +00:00
fixing macOS issue
This commit is contained in:
@@ -44,10 +44,10 @@ namespace mlx
|
|||||||
private:
|
private:
|
||||||
struct Hook
|
struct Hook
|
||||||
{
|
{
|
||||||
func::function<void(void*)> fn;
|
std::function<void(void*)> fn;
|
||||||
void* param;
|
void* param;
|
||||||
|
|
||||||
Hook(func::function<void(void*)> fn, void* param) : fn(fn), param(param) {}
|
Hook(std::function<void(void*)> fn, void* param) : fn(fn), param(param) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace mlx
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EventListener() = delete;
|
EventListener() = delete;
|
||||||
EventListener(func::function<void(const EventBase&)> functor, std::string name);
|
EventListener(std::function<void(const EventBase&)> functor, std::string name);
|
||||||
|
|
||||||
inline const std::string& GetName() const { return m_name; }
|
inline const std::string& GetName() const { return m_name; }
|
||||||
inline void Call(const EventBase& event) const noexcept { m_listen_functor(event); }
|
inline void Call(const EventBase& event) const noexcept { m_listen_functor(event); }
|
||||||
@@ -17,7 +17,7 @@ namespace mlx
|
|||||||
~EventListener() = default;
|
~EventListener() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
func::function<void(const EventBase&)> m_listen_functor;
|
std::function<void(const EventBase&)> m_listen_functor;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace mlx
|
|||||||
Handle CreateWindow(const mlx_window_create_info* info, std::int32_t& id, bool hidden);
|
Handle CreateWindow(const mlx_window_create_info* info, std::int32_t& id, bool hidden);
|
||||||
void DestroyWindow(Handle window) noexcept;
|
void DestroyWindow(Handle window) noexcept;
|
||||||
|
|
||||||
void InputsFetcher(func::function<void(mlx_event_type, int, int)> functor);
|
void InputsFetcher(std::function<void(mlx_event_type, int, int)> functor);
|
||||||
|
|
||||||
VkSurfaceKHR CreateVulkanSurface(Handle window, VkInstance instance) const noexcept;
|
VkSurfaceKHR CreateVulkanSurface(Handle window, VkInstance instance) const noexcept;
|
||||||
std::vector<const char*> GetRequiredVulkanInstanceExtentions(Handle window) const noexcept;
|
std::vector<const char*> GetRequiredVulkanInstanceExtentions(Handle window) const noexcept;
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ namespace mlx
|
|||||||
public:
|
public:
|
||||||
struct Hook
|
struct Hook
|
||||||
{
|
{
|
||||||
func::function<void(int, void*)> fn;
|
std::function<void(int, void*)> fn;
|
||||||
void* param = nullptr;
|
void* param = nullptr;
|
||||||
|
|
||||||
Hook(func::function<void(int, void*)> fn, void* param) : fn(fn), param(param) {}
|
Hook(std::function<void(int, void*)> fn, void* param) : fn(fn), param(param) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <function.h>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#include "mlx_extended.h"
|
|
||||||
#include <PreCompiled.h>
|
#include <PreCompiled.h>
|
||||||
|
|
||||||
#include <Core/Application.h>
|
#include <Core/Application.h>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace mlx
|
namespace mlx
|
||||||
{
|
{
|
||||||
EventListener::EventListener(func::function<void(const EventBase&)> functor, std::string name)
|
EventListener::EventListener(std::function<void(const EventBase&)> functor, std::string name)
|
||||||
: m_listen_functor(std::move(functor)), m_name(std::move(name))
|
: m_listen_functor(std::move(functor)), m_name(std::move(name))
|
||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace mlx
|
|||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLManager::InputsFetcher(func::function<void(mlx_event_type, int, int)> functor)
|
void SDLManager::InputsFetcher(std::function<void(mlx_event_type, int, int)> functor)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while(SDL_PollEvent(&event))
|
while(SDL_PollEvent(&event))
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace mlx
|
|||||||
};
|
};
|
||||||
p_fragment_shader = std::make_shared<Shader>(fragment_shader_code, ShaderType::Fragment, std::move(fragment_shader_layout));
|
p_fragment_shader = std::make_shared<Shader>(fragment_shader_code, ShaderType::Fragment, std::move(fragment_shader_layout));
|
||||||
|
|
||||||
func::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||||
{
|
{
|
||||||
if(event.What() == Event::ResizeEventCode)
|
if(event.What() == Event::ResizeEventCode)
|
||||||
m_pipeline.Destroy();
|
m_pipeline.Destroy();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace mlx
|
|||||||
};
|
};
|
||||||
p_fragment_shader = std::make_shared<Shader>(fragment_shader_code, ShaderType::Fragment, std::move(fragment_shader_layout));
|
p_fragment_shader = std::make_shared<Shader>(fragment_shader_code, ShaderType::Fragment, std::move(fragment_shader_layout));
|
||||||
|
|
||||||
func::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||||
{
|
{
|
||||||
if(event.What() == Event::ResizeEventCode)
|
if(event.What() == Event::ResizeEventCode)
|
||||||
m_pipeline.Destroy();
|
m_pipeline.Destroy();
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace mlx
|
|||||||
|
|
||||||
m_2Dpass.Init();
|
m_2Dpass.Init();
|
||||||
m_final.Init();
|
m_final.Init();
|
||||||
func::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
||||||
{
|
{
|
||||||
if(event.What() == Event::ResizeEventCode)
|
if(event.What() == Event::ResizeEventCode)
|
||||||
m_main_render_texture.Destroy();
|
m_main_render_texture.Destroy();
|
||||||
|
|||||||
630
third_party/function.h
vendored
630
third_party/function.h
vendored
@@ -1,630 +0,0 @@
|
|||||||
/*
|
|
||||||
This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
distribute this software, either in source code form or as a compiled
|
|
||||||
binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
means.
|
|
||||||
|
|
||||||
In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
of this software dedicate any and all copyright interest in the
|
|
||||||
software to the public domain. We make this dedication for the benefit
|
|
||||||
of the public at large and to the detriment of our heirs and
|
|
||||||
successors. We intend this dedication to be an overt act of
|
|
||||||
relinquishment in perpetuity of all present and future rights to this
|
|
||||||
software under copyright law.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
For more information, please refer to <http://unlicense.org/>
|
|
||||||
*/
|
|
||||||
// despite that it would be nice if you give credit to Malte Skarupke
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <utility>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <functional>
|
|
||||||
#include <exception>
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define FUNC_NOEXCEPT
|
|
||||||
#define FUNC_TEMPLATE_NOEXCEPT(FUNCTOR, ALLOCATOR)
|
|
||||||
#define FUNC_CONSTEXPR const
|
|
||||||
#else
|
|
||||||
#define FUNC_NOEXCEPT noexcept
|
|
||||||
#define FUNC_TEMPLATE_NOEXCEPT(FUNCTOR, ALLOCATOR) noexcept(detail::is_inplace_allocated<FUNCTOR, ALLOCATOR>::value)
|
|
||||||
#define FUNC_CONSTEXPR constexpr
|
|
||||||
#endif
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FUNC_MOVE(value) static_cast<typename std::remove_reference<decltype(value)>::type &&>(value)
|
|
||||||
#define FUNC_FORWARD(type, value) static_cast<type &&>(value)
|
|
||||||
|
|
||||||
namespace func
|
|
||||||
{
|
|
||||||
#ifndef FUNC_NO_EXCEPTIONS
|
|
||||||
struct bad_function_call : std::exception
|
|
||||||
{
|
|
||||||
const char * what() const FUNC_NOEXCEPT override
|
|
||||||
{
|
|
||||||
return "Bad function call";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename>
|
|
||||||
struct force_function_heap_allocation
|
|
||||||
: std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename>
|
|
||||||
class function;
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
struct manager_storage_type;
|
|
||||||
struct function_manager;
|
|
||||||
struct functor_padding
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
size_t padding_first;
|
|
||||||
size_t padding_second;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct empty_struct
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifndef FUNC_NO_EXCEPTIONS
|
|
||||||
template<typename Result, typename... Arguments>
|
|
||||||
Result empty_call(const functor_padding &, Arguments...)
|
|
||||||
{
|
|
||||||
throw bad_function_call();
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
struct is_inplace_allocated
|
|
||||||
{
|
|
||||||
static const bool value
|
|
||||||
// so that it fits
|
|
||||||
= sizeof(T) <= sizeof(functor_padding)
|
|
||||||
// so that it will be aligned
|
|
||||||
&& std::alignment_of<functor_padding>::value % std::alignment_of<T>::value == 0
|
|
||||||
// so that we can offer noexcept move
|
|
||||||
&& std::is_nothrow_move_constructible<T>::value
|
|
||||||
// so that the user can override it
|
|
||||||
&& !force_function_heap_allocation<T>::value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T to_functor(T && func)
|
|
||||||
{
|
|
||||||
return FUNC_FORWARD(T, func);
|
|
||||||
}
|
|
||||||
template<typename Result, typename Class, typename... Arguments>
|
|
||||||
auto to_functor(Result (Class::*func)(Arguments...)) -> decltype(std::mem_fn(func))
|
|
||||||
{
|
|
||||||
return std::mem_fn(func);
|
|
||||||
}
|
|
||||||
template<typename Result, typename Class, typename... Arguments>
|
|
||||||
auto to_functor(Result (Class::*func)(Arguments...) const) -> decltype(std::mem_fn(func))
|
|
||||||
{
|
|
||||||
return std::mem_fn(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct functor_type
|
|
||||||
{
|
|
||||||
typedef decltype(to_functor(std::declval<T>())) type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool is_null(const T &)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
template<typename Result, typename... Arguments>
|
|
||||||
bool is_null(Result (* const & function_pointer)(Arguments...))
|
|
||||||
{
|
|
||||||
return function_pointer == nullptr;
|
|
||||||
}
|
|
||||||
template<typename Result, typename Class, typename... Arguments>
|
|
||||||
bool is_null(Result (Class::* const & function_pointer)(Arguments...))
|
|
||||||
{
|
|
||||||
return function_pointer == nullptr;
|
|
||||||
}
|
|
||||||
template<typename Result, typename Class, typename... Arguments>
|
|
||||||
bool is_null(Result (Class::* const & function_pointer)(Arguments...) const)
|
|
||||||
{
|
|
||||||
return function_pointer == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename, typename>
|
|
||||||
struct is_valid_function_argument
|
|
||||||
{
|
|
||||||
static const bool value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Result, typename... Arguments>
|
|
||||||
struct is_valid_function_argument<function<Result (Arguments...)>, Result (Arguments...)>
|
|
||||||
{
|
|
||||||
static const bool value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Result, typename... Arguments>
|
|
||||||
struct is_valid_function_argument<T, Result (Arguments...)>
|
|
||||||
{
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
// as of january 2013 visual studio doesn't support the SFINAE below
|
|
||||||
static const bool value = true;
|
|
||||||
# else
|
|
||||||
template<typename U>
|
|
||||||
static decltype(to_functor(std::declval<U>())(std::declval<Arguments>()...)) check(U *);
|
|
||||||
template<typename>
|
|
||||||
static empty_struct check(...);
|
|
||||||
|
|
||||||
static const bool value = std::is_convertible<decltype(check<T>(nullptr)), Result>::value;
|
|
||||||
# endif
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef const function_manager * manager_type;
|
|
||||||
|
|
||||||
struct manager_storage_type
|
|
||||||
{
|
|
||||||
template<typename Allocator>
|
|
||||||
Allocator & get_allocator() FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return reinterpret_cast<Allocator &>(manager);
|
|
||||||
}
|
|
||||||
template<typename Allocator>
|
|
||||||
const Allocator & get_allocator() const FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const Allocator &>(manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
functor_padding functor;
|
|
||||||
manager_type manager;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Allocator, typename Enable = void>
|
|
||||||
struct function_manager_inplace_specialization
|
|
||||||
{
|
|
||||||
template<typename Result, typename... Arguments>
|
|
||||||
static Result call(const functor_padding & storage, Arguments... arguments)
|
|
||||||
{
|
|
||||||
// do not call get_functor_ref because I want this function to be fast
|
|
||||||
// in debug when nothing gets inlined
|
|
||||||
return const_cast<T &>(reinterpret_cast<const T &>(storage))(FUNC_FORWARD(Arguments, arguments)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void store_functor(manager_storage_type & storage, T to_store)
|
|
||||||
{
|
|
||||||
new (&get_functor_ref(storage)) T(FUNC_FORWARD(T, to_store));
|
|
||||||
}
|
|
||||||
static void move_functor(manager_storage_type & lhs, manager_storage_type && rhs) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
new (&get_functor_ref(lhs)) T(FUNC_MOVE(get_functor_ref(rhs)));
|
|
||||||
}
|
|
||||||
static void destroy_functor(Allocator &, manager_storage_type & storage) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
get_functor_ref(storage).~T();
|
|
||||||
}
|
|
||||||
static T & get_functor_ref(const manager_storage_type & storage) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return const_cast<T &>(reinterpret_cast<const T &>(storage.functor));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
struct function_manager_inplace_specialization<T, Allocator, typename std::enable_if<!is_inplace_allocated<T, Allocator>::value>::type>
|
|
||||||
{
|
|
||||||
template<typename Result, typename... Arguments>
|
|
||||||
static Result call(const functor_padding & storage, Arguments... arguments)
|
|
||||||
{
|
|
||||||
// do not call get_functor_ptr_ref because I want this function to be fast
|
|
||||||
// in debug when nothing gets inlined
|
|
||||||
return (*reinterpret_cast<const typename std::allocator_traits<Allocator>::pointer &>(storage))(FUNC_FORWARD(Arguments, arguments)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void store_functor(manager_storage_type & self, T to_store)
|
|
||||||
{
|
|
||||||
Allocator & allocator = self.get_allocator<Allocator>();;
|
|
||||||
static_assert(sizeof(typename std::allocator_traits<Allocator>::pointer) <= sizeof(self.functor), "The allocator's pointer type is too big");
|
|
||||||
typename std::allocator_traits<Allocator>::pointer * ptr = new (&get_functor_ptr_ref(self)) typename std::allocator_traits<Allocator>::pointer(std::allocator_traits<Allocator>::allocate(allocator, 1));
|
|
||||||
std::allocator_traits<Allocator>::construct(allocator, *ptr, FUNC_FORWARD(T, to_store));
|
|
||||||
}
|
|
||||||
static void move_functor(manager_storage_type & lhs, manager_storage_type && rhs) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
static_assert(std::is_nothrow_move_constructible<typename std::allocator_traits<Allocator>::pointer>::value, "we can't offer a noexcept swap if the pointer type is not nothrow move constructible");
|
|
||||||
new (&get_functor_ptr_ref(lhs)) typename std::allocator_traits<Allocator>::pointer(FUNC_MOVE(get_functor_ptr_ref(rhs)));
|
|
||||||
// this next assignment makes the destroy function easier
|
|
||||||
get_functor_ptr_ref(rhs) = nullptr;
|
|
||||||
}
|
|
||||||
static void destroy_functor(Allocator & allocator, manager_storage_type & storage) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
typename std::allocator_traits<Allocator>::pointer & pointer = get_functor_ptr_ref(storage);
|
|
||||||
if (!pointer) return;
|
|
||||||
std::allocator_traits<Allocator>::destroy(allocator, pointer);
|
|
||||||
std::allocator_traits<Allocator>::deallocate(allocator, pointer, 1);
|
|
||||||
}
|
|
||||||
static T & get_functor_ref(const manager_storage_type & storage) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return *get_functor_ptr_ref(storage);
|
|
||||||
}
|
|
||||||
static typename std::allocator_traits<Allocator>::pointer & get_functor_ptr_ref(manager_storage_type & storage) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return reinterpret_cast<typename std::allocator_traits<Allocator>::pointer &>(storage.functor);
|
|
||||||
}
|
|
||||||
static const typename std::allocator_traits<Allocator>::pointer & get_functor_ptr_ref(const manager_storage_type & storage) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const typename std::allocator_traits<Allocator>::pointer &>(storage.functor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static const function_manager & get_default_manager();
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static void create_manager(manager_storage_type & storage, Allocator && allocator)
|
|
||||||
{
|
|
||||||
new (&storage.get_allocator<Allocator>()) Allocator(FUNC_MOVE(allocator));
|
|
||||||
storage.manager = &get_default_manager<T, Allocator>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// this struct acts as a vtable. it is an optimization to prevent
|
|
||||||
// code-bloat from rtti. see the documentation of boost::function
|
|
||||||
struct function_manager
|
|
||||||
{
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
inline static FUNC_CONSTEXPR function_manager create_default_manager()
|
|
||||||
{
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
function_manager result =
|
|
||||||
# else
|
|
||||||
return function_manager
|
|
||||||
# endif
|
|
||||||
{
|
|
||||||
&templated_call_move_and_destroy<T, Allocator>,
|
|
||||||
&templated_call_copy<T, Allocator>,
|
|
||||||
&templated_call_copy_functor_only<T, Allocator>,
|
|
||||||
&templated_call_destroy<T, Allocator>,
|
|
||||||
# ifndef FUNC_NO_RTTI
|
|
||||||
&templated_call_type_id<T, Allocator>,
|
|
||||||
&templated_call_target<T, Allocator>
|
|
||||||
# endif
|
|
||||||
};
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
return result;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void (* const call_move_and_destroy)(manager_storage_type & lhs, manager_storage_type && rhs);
|
|
||||||
void (* const call_copy)(manager_storage_type & lhs, const manager_storage_type & rhs);
|
|
||||||
void (* const call_copy_functor_only)(manager_storage_type & lhs, const manager_storage_type & rhs);
|
|
||||||
void (* const call_destroy)(manager_storage_type & manager);
|
|
||||||
# ifndef FUNC_NO_RTTI
|
|
||||||
const std::type_info & (* const call_type_id)();
|
|
||||||
void * (* const call_target)(const manager_storage_type & manager, const std::type_info & type);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static void templated_call_move_and_destroy(manager_storage_type & lhs, manager_storage_type && rhs)
|
|
||||||
{
|
|
||||||
typedef function_manager_inplace_specialization<T, Allocator> specialization;
|
|
||||||
specialization::move_functor(lhs, FUNC_MOVE(rhs));
|
|
||||||
specialization::destroy_functor(rhs.get_allocator<Allocator>(), rhs);
|
|
||||||
create_manager<T, Allocator>(lhs, FUNC_MOVE(rhs.get_allocator<Allocator>()));
|
|
||||||
rhs.get_allocator<Allocator>().~Allocator();
|
|
||||||
}
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static void templated_call_copy(manager_storage_type & lhs, const manager_storage_type & rhs)
|
|
||||||
{
|
|
||||||
typedef function_manager_inplace_specialization<T, Allocator> specialization;
|
|
||||||
create_manager<T, Allocator>(lhs, Allocator(rhs.get_allocator<Allocator>()));
|
|
||||||
specialization::store_functor(lhs, specialization::get_functor_ref(rhs));
|
|
||||||
}
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static void templated_call_destroy(manager_storage_type & self)
|
|
||||||
{
|
|
||||||
typedef function_manager_inplace_specialization<T, Allocator> specialization;
|
|
||||||
specialization::destroy_functor(self.get_allocator<Allocator>(), self);
|
|
||||||
self.get_allocator<Allocator>().~Allocator();
|
|
||||||
}
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static void templated_call_copy_functor_only(manager_storage_type & lhs, const manager_storage_type & rhs)
|
|
||||||
{
|
|
||||||
typedef function_manager_inplace_specialization<T, Allocator> specialization;
|
|
||||||
specialization::store_functor(lhs, specialization::get_functor_ref(rhs));
|
|
||||||
}
|
|
||||||
# ifndef FUNC_NO_RTTI
|
|
||||||
template<typename T, typename>
|
|
||||||
static const std::type_info & templated_call_type_id()
|
|
||||||
{
|
|
||||||
return typeid(T);
|
|
||||||
}
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
static void * templated_call_target(const manager_storage_type & self, const std::type_info & type)
|
|
||||||
{
|
|
||||||
typedef function_manager_inplace_specialization<T, Allocator> specialization;
|
|
||||||
if (type == typeid(T))
|
|
||||||
return &specialization::get_functor_ref(self);
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
};
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
inline static const function_manager & get_default_manager()
|
|
||||||
{
|
|
||||||
static FUNC_CONSTEXPR function_manager default_manager = function_manager::create_default_manager<T, Allocator>();
|
|
||||||
return default_manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Result, typename...>
|
|
||||||
struct typedeffer
|
|
||||||
{
|
|
||||||
typedef Result result_type;
|
|
||||||
};
|
|
||||||
template<typename Result, typename Argument>
|
|
||||||
struct typedeffer<Result, Argument>
|
|
||||||
{
|
|
||||||
typedef Result result_type;
|
|
||||||
typedef Argument argument_type;
|
|
||||||
};
|
|
||||||
template<typename Result, typename First_Argument, typename Second_Argument>
|
|
||||||
struct typedeffer<Result, First_Argument, Second_Argument>
|
|
||||||
{
|
|
||||||
typedef Result result_type;
|
|
||||||
typedef First_Argument first_argument_type;
|
|
||||||
typedef Second_Argument second_argument_type;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Result, typename... Arguments>
|
|
||||||
class function<Result (Arguments...)>
|
|
||||||
: public detail::typedeffer<Result, Arguments...>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
function() FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
initialize_empty();
|
|
||||||
}
|
|
||||||
function(std::nullptr_t) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
initialize_empty();
|
|
||||||
}
|
|
||||||
function(function && other) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
initialize_empty();
|
|
||||||
swap(other);
|
|
||||||
}
|
|
||||||
function(const function & other)
|
|
||||||
: call(other.call)
|
|
||||||
{
|
|
||||||
other.manager_storage.manager->call_copy(manager_storage, other.manager_storage);
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
function(T functor,
|
|
||||||
typename std::enable_if<detail::is_valid_function_argument<T, Result (Arguments...)>::value, detail::empty_struct>::type = detail::empty_struct()) FUNC_TEMPLATE_NOEXCEPT(T, std::allocator<typename detail::functor_type<T>::type>)
|
|
||||||
{
|
|
||||||
if (detail::is_null(functor))
|
|
||||||
{
|
|
||||||
initialize_empty();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
typedef typename detail::functor_type<T>::type functor_type;
|
|
||||||
initialize(detail::to_functor(FUNC_FORWARD(T, functor)), std::allocator<functor_type>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<typename Allocator>
|
|
||||||
function(std::allocator_arg_t, const Allocator &)
|
|
||||||
{
|
|
||||||
// ignore the allocator because I don't allocate
|
|
||||||
initialize_empty();
|
|
||||||
}
|
|
||||||
template<typename Allocator>
|
|
||||||
function(std::allocator_arg_t, const Allocator &, std::nullptr_t)
|
|
||||||
{
|
|
||||||
// ignore the allocator because I don't allocate
|
|
||||||
initialize_empty();
|
|
||||||
}
|
|
||||||
template<typename Allocator, typename T>
|
|
||||||
function(std::allocator_arg_t, const Allocator & allocator, T functor,
|
|
||||||
typename std::enable_if<detail::is_valid_function_argument<T, Result (Arguments...)>::value, detail::empty_struct>::type = detail::empty_struct())
|
|
||||||
FUNC_TEMPLATE_NOEXCEPT(T, Allocator)
|
|
||||||
{
|
|
||||||
if (detail::is_null(functor))
|
|
||||||
{
|
|
||||||
initialize_empty();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
initialize(detail::to_functor(FUNC_FORWARD(T, functor)), Allocator(allocator));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<typename Allocator>
|
|
||||||
function(std::allocator_arg_t, const Allocator & allocator, const function & other)
|
|
||||||
: call(other.call)
|
|
||||||
{
|
|
||||||
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<function> MyAllocator;
|
|
||||||
|
|
||||||
// first try to see if the allocator matches the target type
|
|
||||||
detail::manager_type manager_for_allocator = &detail::get_default_manager<typename std::allocator_traits<Allocator>::value_type, Allocator>();
|
|
||||||
if (other.manager_storage.manager == manager_for_allocator)
|
|
||||||
{
|
|
||||||
detail::create_manager<typename std::allocator_traits<Allocator>::value_type, Allocator>(manager_storage, Allocator(allocator));
|
|
||||||
manager_for_allocator->call_copy_functor_only(manager_storage, other.manager_storage);
|
|
||||||
}
|
|
||||||
// if it does not, try to see if the target contains my type. this
|
|
||||||
// breaks the recursion of the last case. otherwise repeated copies
|
|
||||||
// would allocate more and more memory
|
|
||||||
else
|
|
||||||
{
|
|
||||||
detail::manager_type manager_for_function = &detail::get_default_manager<function, MyAllocator>();
|
|
||||||
if (other.manager_storage.manager == manager_for_function)
|
|
||||||
{
|
|
||||||
detail::create_manager<function, MyAllocator>(manager_storage, MyAllocator(allocator));
|
|
||||||
manager_for_function->call_copy_functor_only(manager_storage, other.manager_storage);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// else store the other function as my target
|
|
||||||
initialize(other, MyAllocator(allocator));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template<typename Allocator>
|
|
||||||
function(std::allocator_arg_t, const Allocator &, function && other) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
// ignore the allocator because I don't allocate
|
|
||||||
initialize_empty();
|
|
||||||
swap(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
function & operator=(function other) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
swap(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
~function() FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
manager_storage.manager->call_destroy(manager_storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result operator()(Arguments... arguments) const
|
|
||||||
{
|
|
||||||
return call(manager_storage.functor, FUNC_FORWARD(Arguments, arguments)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
void assign(T && functor, const Allocator & allocator) FUNC_TEMPLATE_NOEXCEPT(T, Allocator)
|
|
||||||
{
|
|
||||||
function(std::allocator_arg, allocator, functor).swap(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap(function & other) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
detail::manager_storage_type temp_storage;
|
|
||||||
other.manager_storage.manager->call_move_and_destroy(temp_storage, FUNC_MOVE(other.manager_storage));
|
|
||||||
manager_storage.manager->call_move_and_destroy(other.manager_storage, FUNC_MOVE(manager_storage));
|
|
||||||
temp_storage.manager->call_move_and_destroy(manager_storage, FUNC_MOVE(temp_storage));
|
|
||||||
|
|
||||||
std::swap(call, other.call);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# ifndef FUNC_NO_RTTI
|
|
||||||
const std::type_info & target_type() const FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return manager_storage.manager->call_type_id();
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
T * target() FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return static_cast<T *>(manager_storage.manager->call_target(manager_storage, typeid(T)));
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
const T * target() const FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return static_cast<const T *>(manager_storage.manager->call_target(manager_storage, typeid(T)));
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
operator bool() const FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
|
|
||||||
# ifdef FUNC_NO_EXCEPTIONS
|
|
||||||
return call != nullptr;
|
|
||||||
# else
|
|
||||||
return call != &detail::empty_call<Result, Arguments...>;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
detail::manager_storage_type manager_storage;
|
|
||||||
Result (*call)(const detail::functor_padding &, Arguments...);
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
|
||||||
void initialize(T functor, Allocator && allocator)
|
|
||||||
{
|
|
||||||
call = &detail::function_manager_inplace_specialization<T, Allocator>::template call<Result, Arguments...>;
|
|
||||||
detail::create_manager<T, Allocator>(manager_storage, FUNC_FORWARD(Allocator, allocator));
|
|
||||||
detail::function_manager_inplace_specialization<T, Allocator>::store_functor(manager_storage, FUNC_FORWARD(T, functor));
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef Result(*Empty_Function_Type)(Arguments...);
|
|
||||||
void initialize_empty() FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
typedef std::allocator<Empty_Function_Type> Allocator;
|
|
||||||
static_assert(detail::is_inplace_allocated<Empty_Function_Type, Allocator>::value, "The empty function should benefit from small functor optimization");
|
|
||||||
|
|
||||||
detail::create_manager<Empty_Function_Type, Allocator>(manager_storage, Allocator());
|
|
||||||
detail::function_manager_inplace_specialization<Empty_Function_Type, Allocator>::store_functor(manager_storage, nullptr);
|
|
||||||
# ifdef FUNC_NO_EXCEPTIONS
|
|
||||||
call = nullptr;
|
|
||||||
# else
|
|
||||||
call = &detail::empty_call<Result, Arguments...>;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool operator==(std::nullptr_t, const function<T> & rhs) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return !rhs;
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
bool operator==(const function<T> & lhs, std::nullptr_t) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return !lhs;
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
bool operator!=(std::nullptr_t, const function<T> & rhs) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
bool operator!=(const function<T> & lhs, std::nullptr_t) FUNC_NOEXCEPT
|
|
||||||
{
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void swap(function<T> & lhs, function<T> & rhs)
|
|
||||||
{
|
|
||||||
lhs.swap(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace func
|
|
||||||
|
|
||||||
namespace std
|
|
||||||
{
|
|
||||||
template<typename Result, typename... Arguments, typename Allocator>
|
|
||||||
struct uses_allocator<func::function<Result (Arguments...)>, Allocator>
|
|
||||||
: std::true_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
#undef FUNC_NOEXCEPT
|
|
||||||
#undef FUNC_TEMPLATE_NOEXCEPT
|
|
||||||
#undef FUNC_FORWARD
|
|
||||||
#undef FUNC_MOVE
|
|
||||||
#undef FUNC_CONSTEXPR
|
|
||||||
Reference in New Issue
Block a user