2 #ifndef UVCC_UTILITY__HPP 3 #define UVCC_UTILITY__HPP 5 #include "uvcc/debug.hpp" 31 using value_type =
typename std::decay< _T_ >::type;
33 constexpr default_delete()
noexcept =
default;
38 typename = std::enable_if_t< std::is_convertible< _U_*, _T_* >::value >
41 void operator ()(value_type *_)
const { Delete(_); }
44 static void Delete(
void *_)
46 static_assert(!std::is_void< value_type >::value,
"void type");
47 static_assert(
sizeof(value_type) > 0,
"incomplete type");
48 delete static_cast< value_type* >(_);
62 using value_type =
typename std::decay< _T_ >::type;
64 constexpr default_destroy()
noexcept =
default;
69 typename = std::enable_if_t< std::is_convertible< _U_*, _T_* >::value >
72 void operator ()(value_type *_)
const { Destroy(_); }
75 static void Destroy(
void *_)
77 static_assert(!std::is_void< value_type >::value,
"void type");
78 static_assert(
sizeof(value_type) > 0,
"incomplete type");
79 static_cast< value_type* >(_)->~value_type();
92 template<
typename _T_,
typename... _Ts_ >
struct is_one_of;
94 template<
typename _T_ >
struct is_one_of< _T_ >
96 constexpr static const std::size_t value = 0;
98 template<
typename _T_,
typename... _Ts_ >
struct is_one_of< _T_, _T_, _Ts_... >
100 constexpr static const std::size_t value = 1;
102 template<
typename _T_,
typename _U_,
typename... _Ts_ >
struct is_one_of< _T_, _U_, _Ts_... >
105 constexpr static const std::size_t value_ = is_one_of< _T_, _Ts_... >::value;
107 constexpr static const std::size_t value = value_ ? value_+1 : 0;
115 template<
typename _T_,
typename... _Ts_ >
struct is_convertible_to_one_of;
117 template<
typename _T_ >
struct is_convertible_to_one_of< _T_ >
119 constexpr static const std::size_t value = 0;
121 template<
typename _T_,
typename _U_,
typename... _Ts_ >
struct is_convertible_to_one_of< _T_, _U_, _Ts_... >
124 constexpr static const std::size_t value_ = is_convertible_to_one_of< _T_, _Ts_... >::value;
126 constexpr static const std::size_t value = std::is_convertible< _T_, _U_ >::value ? 1 : (value_ ? value_+1 : 0);
132 template< std::size_t _index_,
typename... _Ts_ >
struct type_at;
134 template<
typename... _Ts_ >
struct type_at< 0, _Ts_... > {};
135 template< std::size_t _index_ >
struct type_at< _index_ > {};
136 template<
typename _T_,
typename... _Ts_ >
struct type_at< 1, _T_, _Ts_...> {
using type = _T_; };
137 template< std::size_t _index_,
typename _T_,
typename... _Ts_ >
struct type_at< _index_, _T_, _Ts_...>
138 {
using type =
typename type_at< _index_-1, _Ts_... >::type; };
143 template<
typename _T_ >
146 auto greatest(_T_&& _v) ->
decltype(_v)
148 return std::forward< _T_ >(_v);
159 template<
typename _T_,
typename... _Ts_ >
164 return _v < greatest(std::forward< _Ts_ >(_vs)...) ? greatest(std::forward< _Ts_ >(_vs)...) : _v;
168 template<
typename _T_ >
171 auto lowest(_T_&& _v) ->
decltype(_v)
173 return std::forward< _T_ >(_v);
177 template<
typename _T_,
typename... _Ts_ >
182 return lowest(std::forward< _Ts_ >(_vs)...) < _v ? lowest(std::forward< _Ts_ >(_vs)...) : _v;
187 template<
typename _T_ >
189 auto sum(_T_&& _v) ->
decltype(_v)
191 return std::forward< _T_ >(_v);
195 template<
typename _T_,
typename... _Ts_ >
199 return _v + sum(std::forward< _Ts_ >(_vs)...);
235 std::atomic< type > count;
238 ~ref_count() =
default;
240 ref_count()
noexcept : count(1) {}
249 type get_value()
const noexcept {
return count.load(std::memory_order_acquire); }
250 void set_value(type _count)
noexcept { count.store(_count, std::memory_order_release); }
254 auto c = count.load(std::memory_order_relaxed);
257 throw std::runtime_error(
__PRETTY_FUNCTION__);
258 while (!count.compare_exchange_weak(c, c+1, std::memory_order_relaxed, std::memory_order_relaxed));
264 auto c = count.fetch_sub(1, std::memory_order_release);
272 struct adopt_ref_t {
constexpr adopt_ref_t() =
default; };
279 template<
class _T_ >
283 using target_type = _T_;
289 ~ref_guard() { t.unref(); }
291 explicit ref_guard(target_type &_t) : t(_t) { t.ref(); }
292 explicit ref_guard(target_type &_t,
const adopt_ref_t) : t(_t) {}
307 std::atomic_flag flag;
310 ~spinlock() =
default;
311 spinlock() : flag(ATOMIC_FLAG_INIT) {}
320 void lock(std::memory_order _o = std::memory_order_acquire)
noexcept 322 while (flag.test_and_set(_o));
325 void unlock(std::memory_order _o = std::memory_order_release)
noexcept 338 template< std::size_t _LEN_, std::size_t _ALIGN_ >
342 const std::type_info *type_tag =
nullptr;
343 void (*Destroy)(
void*) =
nullptr;
344 typename std::aligned_storage< _LEN_, _ALIGN_ >::type storage;
347 ~aligned_storage() { destroy(); }
359 using type =
typename std::decay< _T_ >::type;
360 static_assert(
sizeof(type) <= _LEN_,
"insufficient storage size");
361 static_assert(
alignof(type) <= _ALIGN_,
"not adjusted storage alignment");
363 new(
static_cast<
void* >(&storage)) type{ _value };
365 type_tag = &
typeid(type);
370 using type =
typename std::decay< _T_ >::type;
371 static_assert(
sizeof(type) <= _LEN_,
"insufficient storage size");
372 static_assert(
alignof(type) <= _ALIGN_,
"not adjusted storage alignment");
374 new(
static_cast<
void* >(&storage)) type{ std::move(_value) };
376 type_tag = &
typeid(type);
380 void destroy()
noexcept 382 if (Destroy) Destroy(&storage);
392 template<
typename _T_ >
void reset()
394 using type =
typename std::decay< _T_ >::type;
395 static_assert(
sizeof(type) <= _LEN_,
"insufficient storage size");
396 static_assert(
alignof(type) <= _ALIGN_,
"not adjusted storage alignment");
400 new(
static_cast<
void* >(&storage)) type{};
402 type_tag = &
typeid(type);
405 template<
typename _T_,
typename... _Args_ >
void reset(_Args_&&... _args)
407 using type =
typename std::decay< _T_ >::type;
408 static_assert(
sizeof(type) <= _LEN_,
"insufficient storage size");
409 static_assert(
alignof(type) <= _ALIGN_,
"not adjusted storage alignment");
413 new(
static_cast<
void* >(&storage)) type{ std::forward< _Args_ >(_args)... };
415 type_tag = &
typeid(type);
418 template<
typename _T_ >
void reset(
const _T_ &_value)
420 using type =
typename std::decay< _T_ >::type;
421 static_assert(
sizeof(type) <= _LEN_,
"insufficient storage size");
422 static_assert(
alignof(type) <= _ALIGN_,
"not adjusted storage alignment");
424 if (
reinterpret_cast< type* >(&storage) == std::addressof(
static_cast<
const type& >(_value)))
return;
428 new(
static_cast<
void* >(&storage)) type{ _value };
430 type_tag = &
typeid(type);
433 template<
typename _T_ >
void reset(_T_ &&_value)
435 using type =
typename std::decay< _T_ >::type;
436 static_assert(
sizeof(type) <= _LEN_,
"insufficient storage size");
437 static_assert(
alignof(type) <= _ALIGN_,
"not adjusted storage alignment");
439 if (
reinterpret_cast< type* >(&storage) == std::addressof(
static_cast< type& >(_value)))
return;
443 new(
static_cast<
void* >(&storage)) type{ std::move(_value) };
445 type_tag = &
typeid(type);
451 template<
typename _T_ >
452 const typename std::decay< _T_ >::type& get()
const noexcept 453 {
return *
reinterpret_cast<
const typename std::decay< _T_ >::type* >(&storage); }
454 template<
typename _T_ >
455 typename std::decay< _T_ >::type& get()
noexcept 456 {
return *
reinterpret_cast<
typename std::decay< _T_ >::type* >(&storage); }
463 const std::type_info*
tag()
const noexcept {
return type_tag; }
474 template<
typename _T_ >
478 using value_type =
typename std::decay< _T_ >::type;
479 using storage_type =
typename std::aligned_storage<
sizeof(value_type),
alignof(value_type) >::type;
482 storage_type storage;
485 ~type_storage() { value().~value_type(); }
486 type_storage() {
new(
static_cast<
void* >(&storage)) value_type{}; }
494 template<
typename... _Args_ > type_storage(_Args_&&... _args)
496 new(
static_cast<
void* >(&storage)) value_type{ std::forward< _Args_ >(_args)... };
498 type_storage(
const value_type &_value)
500 new(
static_cast<
void* >(&storage)) value_type{ _value };
502 type_storage(value_type &&_value)
504 new(
static_cast<
void* >(&storage)) value_type{ std::move(_value) };
508 const value_type& value()
const noexcept {
return *
reinterpret_cast<
const value_type* >(&storage); }
509 value_type& value()
noexcept {
return *
reinterpret_cast< value_type* >(&storage); }
515 template<
typename... _Ts_ >
516 using aligned_union = std::aligned_storage< greatest(
sizeof(_Ts_)...), greatest(
alignof(_Ts_)...) >;
526 template<
typename... _Ts_ >
533 const std::type_info *type_tag =
nullptr;
534 void (*Destroy)(
void*) =
nullptr;
535 storage_type storage;
538 ~union_storage() { destroy(); }
551 constexpr const std::size_t tag = is_convertible_to_one_of< _T_, _Ts_... >::value;
552 using type =
typename std::decay<
typename type_at< tag, _Ts_... >::type >::type;
554 new(
static_cast<
void* >(&storage)) type{ _value };
556 type_tag = &
typeid(type);
562 constexpr const std::size_t tag = is_convertible_to_one_of< _T_, _Ts_... >::value;
563 using type =
typename std::decay<
typename type_at< tag, _Ts_... >::type >::type;
565 new(
static_cast<
void* >(&storage)) type{ std::move(_value) };
567 type_tag = &
typeid(type);
571 void destroy()
noexcept 573 if (Destroy) Destroy(&storage);
584 template<
typename _T_ >
597 template<
typename _T_,
typename...
_Args_ >
610 template<
typename _T_ >
625 template<
typename _T_ >
658 explicit operator bool()
const noexcept {
return (
tag() !=
nullptr); }
667 const std::type_info *type_tag =
nullptr;
668 void (*Delete)(
void*) =
nullptr;
672 ~any_ptr() { destroy(); }
673 constexpr any_ptr() =
default;
675 any_ptr(
const any_ptr&) =
delete;
678 any_ptr(
any_ptr &&_that)
noexcept : type_tag(_that.type_tag), Delete(_that.Delete), ptr(_that.ptr) { _that.release(); }
681 if (ptr != _that.ptr)
684 new (
this) any_ptr(std::move(_that));
689 constexpr any_ptr(std::nullptr_t)
noexcept {}
690 any_ptr& operator =(std::nullptr_t) { destroy();
return *
this; }
692 template<
typename _T_ >
explicit any_ptr(_T_* &&_ptr)
noexcept 696 type_tag = &
typeid(_T_);
703 if (Delete) Delete(ptr);
709 void* release()
noexcept 712 ptr =
nullptr; Delete =
nullptr; type_tag =
nullptr;
716 void reset(std::nullptr_t _ptr =
nullptr) { destroy(); }
717 template<
typename _T_ >
void reset(_T_* &&_ptr)
719 if (ptr == _ptr)
return;
721 new (
this)
any_ptr(std::move(_ptr));
724 template<
typename _T_ =
void >
725 const typename std::decay< _T_ >::type* get()
const noexcept 726 {
return static_cast<
const typename std::decay< _T_ >::type* >(ptr); }
727 template<
typename _T_ =
void >
728 typename std::decay< _T_ >::type* get()
noexcept 729 {
return static_cast<
typename std::decay< _T_ >::type* >(ptr); }
731 const std::type_info* tag()
const noexcept {
return type_tag; }
734 explicit operator bool()
const noexcept {
return (ptr !=
nullptr); }
Namespace for all uvcc definitions.
aligned_storage(_T_ &&_value)
Create a storage space with a move-initialized value from the specified value.
constexpr const adopt_ref_t adopt_ref
The tag to be used to prevent ref_guard constructor from increasing reference count of the protected ...
A wrapper providing the feature of being a standard layout type for the given type _T_...
void reset(_Args_ &&... _args)
Ditto but the value is created from the arguments forwarded to the type constructor.
A simple spinlock mutex built around std::atomic_flag.
The analogue of the uv::default_delete but for the type destructor only.
union_storage()=default
Create an uninitialized union storage.
ref_guard(target_type &_t, const adopt_ref_t)
The constructor to be used with uv::adopt_ref tag.
constexpr auto sum(_T_ &&_v, _Ts_ &&... _vs) -> std::common_type_t< _T_, _Ts_... >
Primarily intended for summation of values from parameter packs if fold expressions are not supported...
union_storage(_T_ &&_value)
Create a union with a move-initialized value from the specified value.
The analogue of the std::default_delete.
The analogue of std::unique_ptr that managed object type is not defined at compile time and can be va...
constexpr auto greatest(_T_ &&_v, _Ts_ &&... _vs) -> std::common_type_t< decltype(_v), decltype(_vs)... >
Intended to be used instead of constexpr T max(std::initializer_list<T>)...
aligned_storage()=default
Create an uninitialized storage.
void reset()
Reinitialize the storage space with a default value of the specified type.
operator bool() const noexcept
Equivalent to (tag() != nullptr).
operator bool() const noexcept
Equivalent to (tag() != nullptr).
A scoped reference counting guard.
A reference counter with atomic increment/decrement.
aligned_storage(const _T_ &_value)
Create a storage space with a copy-initialized value from the specified one.
operator bool() const noexcept
Equivalent to (get() != nullptr).
union_storage(const _T_ &_value)
Create a union with a copy-initialized value from the specified one.
void reset(const _T_ &_value)
Ditto but the value is copy-created from the specified argument.
void reset(_T_ &&_value)
Ditto but the value is move-created from the specified argument.
A wrapper around std::aligned_storage< _LEN_, _ALIGN_ >::type that simplifies initializing the provid...
const std::type_info * tag() const noexcept
The type tag of the stored value.
constexpr auto lowest(_T_ &&_v, _Ts_ &&... _vs) -> std::common_type_t< decltype(_v), decltype(_vs)... >
The counterpart of greatest()