-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from NoAvailableAlias/rework
- Loading branch information
Showing
20 changed files
with
1,630 additions
and
371 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
Benchmarks Have Moved | ||
===================== | ||
|
||
The comprehensive benchmarks have been moved to a new project [signal-slot-benchmarks](https://github.com/NoAvailableAlias/signal-slot-benchmarks/tree/master/#performance). Because links to this page still exist, this readme will remain here for the time being. | ||
The comprehensive benchmarks have been moved to a new project [signal-slot-benchmarks](https://github.com/NoAvailableAlias/signal-slot-benchmarks/tree/master/#performance). | ||
Because links to this page still exist, this readme will remain here for the time being. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,86 @@ | ||
#ifndef NANO_FUNCTION_HPP | ||
#define NANO_FUNCTION_HPP | ||
#pragma once | ||
|
||
#include <cstdint> | ||
#include <array> | ||
|
||
namespace Nano | ||
{ | ||
|
||
using DelegateKey = std::array<std::uintptr_t, 2>; | ||
using Delegate_Key = std::array<const std::uintptr_t, 2>; | ||
|
||
template <typename RT> class Function; | ||
template <typename RT, typename... Args> | ||
class Function<RT(Args...)> | ||
class Function<RT(Args...)> final | ||
{ | ||
using Thunk = RT (*)(void*, Args...); | ||
// Only Nano::Observer is allowed access | ||
template <typename> friend class Observer; | ||
|
||
friend class Observer; | ||
using Thunk = RT(*)(void*, Args&&...); | ||
|
||
void* m_this_ptr; // instance pointer | ||
Thunk m_stub_ptr; // free function pointer | ||
|
||
Function(void* this_ptr, Thunk stub_ptr) : | ||
m_this_ptr(this_ptr), m_stub_ptr(stub_ptr) {} | ||
|
||
Function(DelegateKey delegate_key) : | ||
m_this_ptr(reinterpret_cast<void*>(delegate_key[0])), | ||
m_stub_ptr(reinterpret_cast<Thunk>(delegate_key[1])) {} | ||
static inline Function bind(Delegate_Key const& delegate_key) | ||
{ | ||
return | ||
{ | ||
reinterpret_cast<void*>(delegate_key[0]), | ||
reinterpret_cast<Thunk>(delegate_key[1]) | ||
}; | ||
} | ||
|
||
public: | ||
|
||
template <RT (*fun_ptr) (Args...)> | ||
void* instance_pointer; | ||
const Thunk function_pointer; | ||
|
||
template <auto fun_ptr> | ||
static inline Function bind() | ||
{ | ||
return { nullptr, [](void* /*NULL*/, Args... args) | ||
{ return (*fun_ptr)(std::forward<Args>(args)...); } }; | ||
} | ||
template <typename T, RT (T::* mem_ptr) (Args...)> | ||
static inline Function bind(T* pointer) | ||
{ | ||
return { pointer, [](void* this_ptr, Args... args) | ||
{ return (static_cast<T*>(this_ptr)->*mem_ptr) (std::forward<Args>(args)...); } }; | ||
return | ||
{ | ||
nullptr, [](void* /*NULL*/, Args&&... args) | ||
{ | ||
return (*fun_ptr)(std::forward<Args>(args)...); | ||
} | ||
}; | ||
} | ||
template <typename T, RT (T::* mem_ptr) (Args...) const> | ||
|
||
template <auto mem_ptr, typename T> | ||
static inline Function bind(T* pointer) | ||
{ | ||
return { pointer, [](void* this_ptr, Args... args) | ||
{ return (static_cast<T*>(this_ptr)->*mem_ptr) (std::forward<Args>(args)...); } }; | ||
return | ||
{ | ||
pointer, [](void* this_ptr, Args&&... args) | ||
{ | ||
return (static_cast<T*>(this_ptr)->*mem_ptr)(std::forward<Args>(args)...); | ||
} | ||
}; | ||
} | ||
|
||
template <typename L> | ||
static inline Function bind(L* pointer) | ||
{ | ||
return { pointer, [](void *this_ptr, Args... args) | ||
{ return (static_cast<L*>(this_ptr)->operator()(std::forward<Args>(args)...)); }}; | ||
} | ||
inline operator DelegateKey() const | ||
{ | ||
return | ||
{{ | ||
reinterpret_cast<std::uintptr_t>(m_this_ptr), | ||
reinterpret_cast<std::uintptr_t>(m_stub_ptr) | ||
}}; | ||
{ | ||
pointer, [](void *this_ptr, Args&&... args) | ||
{ | ||
return static_cast<L*>(this_ptr)->operator()(std::forward<Args>(args)...); | ||
} | ||
}; | ||
} | ||
|
||
template <typename... Uref> | ||
inline RT operator() (Uref&&... args) | ||
{ | ||
return (*m_stub_ptr)(m_this_ptr, std::forward<Uref>(args)...); | ||
return (*function_pointer)(instance_pointer, std::forward<Uref>(args)...); | ||
} | ||
|
||
inline operator Delegate_Key() const | ||
{ | ||
return | ||
{ | ||
reinterpret_cast<std::uintptr_t>(instance_pointer), | ||
reinterpret_cast<std::uintptr_t>(function_pointer) | ||
}; | ||
} | ||
}; | ||
|
||
} // namespace Nano ------------------------------------------------------------ | ||
|
||
#endif // NANO_FUNCTION_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#pragma once | ||
|
||
#include <atomic> | ||
#include <thread> | ||
#include <cassert> | ||
|
||
namespace Nano | ||
{ | ||
|
||
// When using a sane optimization level, | ||
// the use of this class with std::shared_lock | ||
// or std::unique_lock will be completely optimized away. | ||
|
||
class Noop_Mutex | ||
{ | ||
public: | ||
|
||
constexpr bool lock() const | ||
{ | ||
return true; | ||
} | ||
|
||
constexpr bool try_lock() const | ||
{ | ||
return true; | ||
} | ||
|
||
constexpr void unlock() noexcept | ||
{ | ||
|
||
} | ||
|
||
constexpr void lock_shared() | ||
{ | ||
|
||
} | ||
|
||
constexpr bool try_lock_shared() const | ||
{ | ||
return true; | ||
} | ||
|
||
constexpr void unlock_shared() | ||
{ | ||
|
||
} | ||
}; | ||
|
||
//------------------------------------------------------------------------------ | ||
|
||
class Recursive_Mutex | ||
{ | ||
std::atomic<std::thread::id> owner_thread_id = std::thread::id(); | ||
std::uint32_t recursive_counter = 0; | ||
std::atomic_flag lock_flag = ATOMIC_FLAG_INIT; | ||
|
||
public: | ||
|
||
bool try_lock() | ||
{ | ||
if (!lock_flag.test_and_set(std::memory_order_acquire)) | ||
{ | ||
owner_thread_id.store(std::this_thread::get_id(), std::memory_order_release); | ||
} | ||
else if (owner_thread_id.load(std::memory_order_acquire) != std::this_thread::get_id()) | ||
{ | ||
return false; | ||
} | ||
++recursive_counter; | ||
return true; | ||
} | ||
|
||
void lock() | ||
{ | ||
while (!try_lock()) | ||
{ | ||
std::this_thread::yield(); | ||
} | ||
} | ||
|
||
void unlock() | ||
{ | ||
assert(owner_thread_id.load(std::memory_order_acquire) == std::this_thread::get_id()); | ||
assert(recursive_counter > 0); | ||
|
||
if (--recursive_counter == 0) | ||
{ | ||
owner_thread_id.store(std::thread::id(), std::memory_order_release); | ||
lock_flag.clear(std::memory_order_release); | ||
} | ||
} | ||
}; | ||
|
||
} // namespace Nano ------------------------------------------------------------ |
Oops, something went wrong.