11#include <condition_variable>
27#define KITTY_WHILE_LOOP(x, y, z) \
39template<
typename T,
typename U>
51#define KITTY_USING_MOVE_T(move_t, t, init_val, z) \
60 using element_type = typename argument_type<void(t)>::type; \
73 template<class... Args> \
74 move_t(Args &&...args): \
75 el {std::forward<Args>(args)...} { \
80 move_t(const move_t &) = delete; \
87 move_t(move_t &&other) noexcept: \
88 el {std::move(other.el)} { \
89 other.el = element_type {init_val}; \
95 move_t &operator=(const move_t &) = delete; \
103 move_t &operator=(move_t &&other) { \
104 std::swap(el, other.el); \
112 element_type *operator->() { \
120 const element_type *operator->() const { \
129 inline element_type release() { \
130 element_type val = std::move(el); \
131 el = element_type {init_val}; \
150#define KITTY_DECL_CONSTR(x) \
154 x(x &&) noexcept = default; \
160 x &operator=(x &&) noexcept = default; \
170#define KITTY_DEFAULT_CONSTR_MOVE(x) \
174 x(x &&) noexcept = default; \
180 x &operator=(x &&) noexcept = default;
186#define KITTY_DEFAULT_CONSTR_MOVE_THROW(x) \
196 x &operator=(x &&) = default; \
206#define KITTY_DEFAULT_CONSTR(x) \
207 KITTY_DEFAULT_CONSTR_MOVE(x) \
211 x(const x &) noexcept = default; \
217 x &operator=(const x &) = default;
223#define TUPLE_2D(a, b, expr) \
224 decltype(expr) a##_##b = expr; \
225 auto &a = std::get<0>(a##_##b); \
226 auto &b = std::get<1>(a##_##b)
232#define TUPLE_2D_REF(a, b, expr) \
233 auto &a##_##b = expr; \
234 auto &a = std::get<0>(a##_##b); \
235 auto &b = std::get<1>(a##_##b)
241#define TUPLE_3D(a, b, c, expr) \
242 decltype(expr) a##_##b##_##c = expr; \
243 auto &a = std::get<0>(a##_##b##_##c); \
244 auto &b = std::get<1>(a##_##b##_##c); \
245 auto &c = std::get<2>(a##_##b##_##c)
251#define TUPLE_3D_REF(a, b, c, expr) \
252 auto &a##_##b##_##c = expr; \
253 auto &a = std::get<0>(a##_##b##_##c); \
254 auto &b = std::get<1>(a##_##b##_##c); \
255 auto &c = std::get<2>(a##_##b##_##c)
261#define TUPLE_EL(a, b, expr) \
262 decltype(expr) a##_ = expr; \
263 auto &a = std::get<b>(a##_)
269#define TUPLE_EL_REF(a, b, expr) \
270 auto &a = std::get<b>(expr)
274 template<
template<
typename...>
class X,
class... Y>
277 template<
template<
typename...>
class X,
class... Y>
280 template<
template<
typename...>
class X,
class T,
class... Y>
283 template<
bool V,
class X,
class Y>
289 template<
class X,
class Y>
300 template<
class X,
class Y>
311 template<
bool V,
class X,
class Y>
314 template<
class... Ts>
316 using Ts::operator()...;
321 template<
class... Ts>
322 overloaded(Ts...) -> overloaded<Ts...>;
338 _func {std::forward<T>(f)} {
348 _func {std::move(other._func)} {
349 other.failure =
false;
352 FailGuard(
const FailGuard &) =
delete;
354 FailGuard &operator=(
const FailGuard &) =
delete;
355 FailGuard &operator=(FailGuard &&other) =
delete;
357 ~FailGuard() noexcept {
394 void append_struct(std::vector<uint8_t> &buf,
const T &_struct) {
395 constexpr size_t data_len =
sizeof(_struct);
397 buf.reserve(data_len);
399 auto const *data =
reinterpret_cast<std::byte
const *
>(&_struct);
401 for (
size_t x = 0; x < data_len; ++x) {
402 buf.push_back(std::to_integer<uint8_t>(data[x]));
418 const std::array<char, 16> _bits {
437 std::array<char,
sizeof(
elem_type) * 2> _hex;
448 const auto *data =
reinterpret_cast<const std::byte *
>(&elem) +
sizeof(
elem_type) - 1;
450 *it++ = _bits[std::to_integer<unsigned>(*data) / 16];
451 *it++ = _bits[std::to_integer<unsigned>(*data--) % 16];
454 const auto *data =
reinterpret_cast<const std::byte *
>(&elem);
456 *it++ = _bits[std::to_integer<unsigned>(*data) / 16];
457 *it++ = _bits[std::to_integer<unsigned>(*data++) % 16];
477 return _hex.data() + _hex.size();
485 const char *
begin()
const {
494 const char *
end()
const {
495 return _hex.data() + _hex.size();
503 const char *
cbegin()
const {
512 const char *
cend()
const {
513 return _hex.data() + _hex.size();
543 Hex<T> hex(
const T &elem,
bool rev =
false) {
554 std::string
log_hex(
const T &value) {
555 return "0x" +
Hex<T>(value,
false).to_string();
567 std::string
hex_vec(It begin, It end,
bool rev =
false) {
568 auto str_size = 2 * std::distance(begin, end);
571 hex.resize(str_size);
577 const std::array<char, 16> _bits {
597 for (
auto it = std::begin(
hex); it < std::end(
hex);) {
598 *it++ = _bits[((uint8_t) *begin) / 16];
599 *it++ = _bits[((uint8_t) *begin++) % 16];
603 for (
auto it = std::begin(
hex); it < std::end(
hex);) {
604 *it++ = _bits[((uint8_t) *end) / 16];
605 *it++ = _bits[((uint8_t) *end--) % 16];
620 std::string hex_vec(C &&c,
bool rev =
false) {
621 return hex_vec(std::begin(c), std::end(c), rev);
634 T from_hex(
const std::string_view &hex,
bool rev =
false) {
635 std::array<std::byte,
sizeof(T)> buf;
637 auto is_convertable = [](
char ch) {
642 return (
'a' <= ch && ch <=
'z') || (
'A' <= ch && ch <=
'Z');
645 auto buf_size = std::min<std::size_t>(std::ranges::count_if(
hex, is_convertable) / 2,
sizeof(T));
646 auto padding =
sizeof(T) - buf_size;
648 const char *data =
hex.data() +
hex.size() - 1;
650 auto convert = [](
char ch) {
651 if (ch >=
'0' && ch <=
'9') {
652 return static_cast<std::byte
>(ch -
'0');
655 const auto lowercase = std::byte {
static_cast<unsigned char>(ch)} | std::byte {
'a' -
'A'};
656 return static_cast<std::byte
>(std::to_integer<unsigned>(lowercase) -
'a' + 10);
659 std::fill_n(buf.begin() + buf_size, padding, std::byte {0});
661 std::for_each_n(buf.begin(), buf_size, [&](
auto &el) {
662 while (!is_convertable(*data)) {
665 const auto ch_r = convert(*data--);
667 while (!is_convertable(*data)) {
670 const auto ch_l = convert(*data--);
672 el = (ch_l << 4) | ch_r;
676 std::ranges::reverse(buf);
679 return std::bit_cast<T>(buf);
689 inline std::string
from_hex_vec(
const std::string &
hex,
bool rev =
false) {
692 auto is_convertable = [](
char ch) {
697 return (
'a' <= ch && ch <=
'z') || (
'A' <= ch && ch <=
'Z');
700 auto buf_size = std::ranges::count_if(hex, is_convertable) / 2;
701 buf.resize(buf_size);
703 const char *data = hex.data() + hex.size() - 1;
705 auto convert = [](
char ch) {
706 if (ch >=
'0' && ch <=
'9') {
707 return static_cast<std::byte
>(ch -
'0');
710 const auto lowercase = std::byte {
static_cast<unsigned char>(ch)} | std::byte {
'a' -
'A'};
711 return static_cast<std::byte
>(std::to_integer<unsigned>(lowercase) -
'a' + 10);
714 for (
auto &el : buf) {
715 while (!is_convertable(*data)) {
718 const auto ch_r = convert(*data--);
720 while (!is_convertable(*data)) {
723 const auto ch_l = convert(*data--);
725 el = std::to_integer<char>((ch_l << 4) | ch_r);
729 std::ranges::reverse(buf);
744 using value_type = T;
752 std::size_t operator()(
const value_type &value)
const {
753 const auto bytes = std::bit_cast<std::array<char,
sizeof(value_type)>>(value);
754 return std::hash<std::string_view> {}(std::string_view {bytes.data(), bytes.size()});
765 auto enm(
const T &val) ->
const std::underlying_type_t<T> & {
766 return *
reinterpret_cast<const std::underlying_type_t<T> *
>(&val);
776 auto enm(T &val) -> std::underlying_type_t<T> & {
777 return *
reinterpret_cast<std::underlying_type_t<T> *
>(&val);
787 inline std::int64_t
from_chars(
const char *begin,
const char *end) {
793 std::int64_t mul = 1;
794 while (begin != --end) {
795 res += (std::int64_t) (*end -
'0') * mul;
800 return *begin !=
'-' ? res + (std::int64_t) (*begin -
'0') * mul : -res;
809 inline std::int64_t
from_view(
const std::string_view &number) {
810 return from_chars(std::begin(number), std::end(number));
816 template<
class X,
class Y>
817 class Either:
public std::variant<std::monostate, X, Y> {
819 using std::variant<std::monostate, X, Y>::variant;
826 constexpr bool has_left()
const {
827 return std::holds_alternative<X>(*
this);
835 constexpr bool has_right()
const {
836 return std::holds_alternative<Y>(*
this);
845 return std::get<X>(*
this);
854 return std::get<Y>(*
this);
862 const X &left()
const {
863 return std::get<X>(*
this);
871 const Y &right()
const {
872 return std::get<Y>(*
this);
880 template<
typename T,
typename D = std::default_delete<T>>
903 constexpr uniq_ptr() noexcept = default;
915 uniq_ptr(
const uniq_ptr &other)
noexcept =
delete;
916 uniq_ptr &operator=(
const uniq_ptr &other)
noexcept =
delete;
924 explicit uniq_ptr(V *p)
noexcept:
926 static_assert(std::is_same_v<element_type, void> || std::is_same_v<element_type, V> || std::is_base_of_v<element_type, V>,
"element_type must be base class of V");
938 uniq_ptr(std::unique_ptr<V, deleter_type> &&uniq)
noexcept:
939 _p {uniq.release()} {
940 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>,
"element_type must be base class of V");
953 _p {other.release()} {
954 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>,
"element_type must be base class of V");
965 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>,
"element_type must be base class of V");
966 reset(other.release());
978 uniq_ptr &operator=(std::unique_ptr<V, deleter_type> &&uniq)
noexcept {
979 static_assert(std::is_same_v<element_type, void> || std::is_same_v<T, V> || std::is_base_of_v<element_type, V>,
"element_type must be base class of V");
981 reset(uniq.release());
995 void reset(pointer p = pointer()) {
1037 std::add_lvalue_reference_t<element_type const>
operator*()
const {
1055 const_pointer operator->()
const {
1064 pointer operator->() {
1073 pointer *operator&()
const {
1082 pointer *operator&() {
1091 deleter_type &get_deleter() {
1100 const deleter_type &get_deleter()
const {
1107 explicit operator bool()
const {
1108 return _p !=
nullptr;
1112 pointer _p {
nullptr};
1113 deleter_type _deleter;
1123 template<
class T1,
class D1,
class T2,
class D2>
1125 return x.get() == y.get();
1135 template<
class T1,
class D1,
class T2,
class D2>
1137 return x.get() != y.get();
1147 template<
class T1,
class D1,
class T2,
class D2>
1149 return x.get() == y.get();
1159 template<
class T1,
class D1,
class T2,
class D2>
1160 bool operator!=(
const std::unique_ptr<T1, D1> &x,
const uniq_ptr<T2, D2> &y) {
1161 return x.get() != y.get();
1171 template<
class T1,
class D1,
class T2,
class D2>
1173 return x.get() == y.get();
1183 template<
class T1,
class D1,
class T2,
class D2>
1185 return x.get() != y.get();
1194 template<
class T,
class D>
1205 template<
class T,
class D>
1216 template<
class T,
class D>
1227 template<
class T,
class D>
1236 using shared_t = std::shared_ptr<typename P::element_type>;
1244 template<
class P,
class T>
1246 return shared_t<P>(
reinterpret_cast<typename P::pointer
>(
pointer),
typename P::deleter_type());
1296 explicit wrap_ptr(std::unique_ptr<element_type> &&uniq_p):
1298 _p {uniq_p.release()} {
1306 wrap_ptr(wrap_ptr &&other):
1307 _own_ptr {other._own_ptr},
1309 other._own_ptr =
false;
1325 _own_ptr = other._own_ptr;
1326 other._own_ptr =
false;
1339 static_assert(std::is_base_of_v<element_type, V>,
"element_type must be base class of V");
1376 const_reference operator*()
const {
1385 reference operator*() {
1394 const_pointer operator->()
const {
1403 pointer operator->() {
1417 instantiation_of_v<std::unique_ptr, T> ||
1418 instantiation_of_v<std::shared_ptr, T> ||
1419 instantiation_of_v<uniq_ptr, T> ||
1420 std::is_pointer_v<T>;
1422 template<
class T,
class V =
void>
1429 struct __false_v<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
1430 static constexpr std::nullopt_t value = std::nullopt;
1437 struct __false_v<T, std::enable_if_t<is_pointer_v<T>>> {
1438 static constexpr std::nullptr_t value =
nullptr;
1445 struct __false_v<T, std::enable_if_t<std::is_same_v<T, bool>>> {
1446 static constexpr bool value =
false;
1477 _buf {std::move(o._buf)} {
1486 buffer_t(
const buffer_t &o):
1489 std::ranges::copy(o,
begin());
1498 buffer_t &
operator=(buffer_t &&o)
noexcept {
1499 std::swap(_els, o._els);
1500 std::swap(_buf, o._buf);
1510 explicit buffer_t(
size_t elements):
1521 explicit buffer_t(
size_t elements,
const T &t):
1524 std::fill_n(_buf.data(), elements, t);
1543 const T &operator[](
size_t el)
const {
1552 size_t size()
const {
1561 void fake_resize(std::size_t els) {
1579 const T *begin()
const {
1589 return _buf.data() + _els;
1597 const T *end()
const {
1598 return _buf.data() + _els;
1603 std::vector<T> _buf;
1614 T
either(std::optional<T> &&l, T &&r) {
1616 return std::move(*l);
1619 return std::forward<T>(r);
1625 template<
class ReturnType,
class... Args>
1630 using type = ReturnType (*)(Args...);
1636 template<class T, class ReturnType, typename Function<ReturnType, T>::type function>
1648 void operator()(pointer p)
const {
1656 template<class T, typename Function<void, T *>::type function>
1663 template<class T, class ReturnType, typename Function<ReturnType, T *>::type function>
1681 template<
class T,
class ReturnType, ReturnType (**function)(T *)>
1689 template<
class T,
void (**function)(T *)>
1695 template<
class T,
class ReturnType, ReturnType (**function)(T *)>
1712 std::string_view
view(It begin, It end) {
1713 return std::string_view {(
const char *) begin, (std::size_t) (end - begin)};
1723 std::string_view
view(
const T &data) {
1724 return std::string_view((
const char *) &data,
sizeof(T));
1737 friend std::ostream &operator<<(std::ostream &os,
const point_t &p) {
1738 return (os <<
"Point(x: " << p.
x <<
", y: " << p.
y <<
")");
1746 template<
class T =
void>
1749#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
1750 defined(__BIG_ENDIAN__) || \
1751 defined(__ARMEB__) || \
1752 defined(__THUMBEB__) || \
1753 defined(__AARCH64EB__) || \
1754 defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
1757#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
1758 defined(__LITTLE_ENDIAN__) || \
1759 defined(__ARMEL__) || \
1760 defined(__THUMBEL__) || \
1761 defined(__AARCH64EL__) || \
1762 defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) || \
1766 #error "Unknown Endianness"
1772 template<
class T,
class S =
void>
1773 struct endian_helper {};
1779 struct endian_helper<T, std::enable_if_t<!(instantiation_of_v<std::optional, T>)>> {
1786 static inline T
big(T x) {
1788 auto *data =
reinterpret_cast<std::byte *
>(&x);
1790 std::reverse(data, data +
sizeof(x));
1802 static inline T
little(T x) {
1804 auto *data =
reinterpret_cast<std::byte *
>(&x);
1806 std::reverse(data, data +
sizeof(x));
1817 struct endian_helper<T, std::enable_if_t<instantiation_of_v<std::optional, T>>> {
1824 static inline T little(T x) {
1829 if constexpr (endianness<T>::big) {
1830 auto *data =
reinterpret_cast<std::byte *
>(&*x);
1832 std::reverse(data, data +
sizeof(*x));
1844 static inline T
big(T x) {
1849 if constexpr (endianness<T>::little) {
1850 auto *data =
reinterpret_cast<std::byte *
>(&*x);
1852 std::reverse(data, data +
sizeof(*x));
1866 inline auto little(T x) {
1867 return endian_helper<T>::little(x);
1877 inline auto big(T x) {
1878 return endian_helper<T>::big(x);
Tagged storage for one of two possible value types.
Definition utility.h:750
Scope guard that runs a cleanup action unless it is disabled.
Definition utility.h:261
void disable()
Disable the fail guard so destruction will not run the cleanup action.
Definition utility.h:299
bool failure
Whether the fail guard should run its cleanup action.
Definition utility.h:303
Formatter that exposes a value's bytes as hexadecimal text.
Definition utility.h:343
char * end()
Return an iterator one past the final byte in the buffer view.
Definition utility.h:409
std::string to_string() const
Convert to string.
Definition utility.h:454
const char * cend() const
Return a const iterator one past the last byte in the view.
Definition utility.h:445
char * begin()
Return an iterator to the first byte in the buffer view.
Definition utility.h:400
std::string_view to_string_view() const
Convert to string view.
Definition utility.h:463
const char * cbegin() const
Return a const iterator to the first byte in the view.
Definition utility.h:436
Hex(const elem_type &elem, bool rev)
Format the supplied object's byte representation as hexadecimal text.
Definition utility.h:379
T elem_type
Integral type used for one formatted hex element.
Definition utility.h:348
Owning contiguous buffer with an explicit logical element count.
Definition utility.h:1398
std::uint8_t & operator[](size_t el)
Definition utility.h:1466
buffer_t & operator=(buffer_t &&o) noexcept
Definition utility.h:1431
std::uint8_t * begin()
Definition utility.h:1503
Unique pointer wrapper with customizable pointer and deleter types.
Definition utility.h:814
element_type const * const_pointer
Definition utility.h:827
constexpr uniq_ptr() noexcept=default
element_type * pointer
Definition utility.h:823
void reset(pointer p=pointer())
Definition utility.h:928
pointer release()
Definition utility.h:941
std::add_lvalue_reference_t< element_type const > operator*() const
Definition utility.h:970
deleter_type _deleter
Definition utility.h:1046
safe_hlocal_deleter deleter_type
Definition utility.h:831
T element_type
Definition utility.h:819
pointer _p
Definition utility.h:1045
pointer get()
Definition utility.h:952
Pointer wrapper that may borrow or own the pointee.
Definition utility.h:1186
element_type const & const_reference
Const reference type exposed by the pointer wrapper.
Definition utility.h:1207
element_type & reference
Mutable reference type exposed by the pointer wrapper.
Definition utility.h:1203
element_type * pointer
Mutable pointer type exposed by the pointer wrapper.
Definition utility.h:1195
element_type const * const_pointer
Const pointer type exposed by the pointer wrapper.
Definition utility.h:1199
T element_type
Object type referenced by the pointer wrapper.
Definition utility.h:1191
wrap_ptr & operator=(wrap_ptr &&other) noexcept
Assign state from another instance while preserving ownership semantics.
Definition utility.h:1251
sha256_t hash(const std::string_view &plaintext)
Hashes the given plaintext using SHA-256.
Definition crypto.cpp:341
U type
Type extracted from the matched function signature.
Definition utility.h:44
Deleter adapter that destroys the wrapped pointer.
Definition utility.h:1570
Callable wrapper used by utility metaprogramming helpers.
Definition utility.h:1559
Definition utility.h:1356
static T big(T x)
Convert a value to or from big-endian byte order.
Definition utility.h:1777
static T little(T x)
Convert a value to or from little-endian byte order.
Definition utility.h:1757
Definition utility.h:1706
@ little
little-endian target architecture
Definition utility.h:1697
@ big
big-endian target architecture
Definition utility.h:1701
Two-dimensional integer point.
Definition utility.h:1663
double x
X.
Definition utility.h:1664
double y
Y.
Definition utility.h:1665
safe_ptr< T, dynamic< T, ReturnType, function > > dyn_safe_ptr_v2
Safe pointer wrapper for runtime-resolved release functions with status returns.
Definition utility.h:1629
std::shared_ptr< typename P::element_type > shared_t
Shared pointer type matching a safe pointer wrapper's element type.
Definition utility.h:1169
std::string hex_vec(It begin, It end, bool rev=false)
Convert a value to a vector of hexadecimal bytes.
Definition utility.h:500
bool operator!=(const uniq_ptr< T1, D1 > &x, const uniq_ptr< T2, D2 > &y)
Compare two Sunshine unique pointers by their stored addresses.
Definition utility.h:1069
uniq_ptr< T, Destroy< T *, ReturnType, function > > safe_ptr_v2
Safe pointer wrapper for APIs whose release function returns a status value.
Definition utility.h:1597
void c_free(T *p)
Release memory allocated by C APIs with free.
Definition utility.h:1605
typename __either< V, X, Y >::type either_t
Compile-time selector for one of two types.
Definition utility.h:245
uniq_ptr< T, Destroy< T *, void, function > > safe_ptr
Unique pointer using a compile-time C-style destroy function.
Definition utility.h:1590
bool operator==(const uniq_ptr< T1, D1 > &x, const uniq_ptr< T2, D2 > &y)
Compare two Sunshine unique pointers by their stored addresses.
Definition utility.h:1057
auto fail_guard(T &&f)
Create a scope guard that runs unless it is disabled.
Definition utility.h:316
void append_struct(std::vector< uint8_t > &buf, const T &_struct)
Append the raw bytes of a trivially-copyable structure to a byte buffer.
Definition utility.h:327
auto big(T x)
Convert a value to or from big-endian byte order.
Definition utility.h:1810
std::int64_t from_view(const std::string_view &number)
Convert from view.
Definition utility.h:742
std::string log_hex(const T &value)
Format a value as hexadecimal text for logging.
Definition utility.h:487
std::int64_t from_chars(const char *begin, const char *end)
Convert from chars.
Definition utility.h:720
auto little(T x)
Convert a value to or from little-endian byte order.
Definition utility.h:1799
std::string from_hex_vec(const std::string &hex, bool rev=false)
Decode hexadecimal text into a string containing the decoded bytes.
Definition utility.h:622
T either(std::optional< T > &&l, T &&r)
Build an either value from a left-hand value.
Definition utility.h:1547
auto enm(const T &val) -> const std::underlying_type_t< T > &
Convert between enum values and their string names.
Definition utility.h:698
constexpr bool is_pointer_v
Trait value indicating whether the template argument is a pointer.
Definition utility.h:1349
void dynamic(T *p)
Create a non-owning dynamic buffer view over contiguous memory.
Definition utility.h:1615
shared_t< P > make_shared(T *pointer)
Create a shared object or message.
Definition utility.h:1178
Hex< T > hex(const T &elem, bool rev=false)
Serialize an element as hexadecimal text.
Definition utility.h:476
either_t<(std::is_same_v< T, bool >||is_pointer_v< T >), T, std::optional< T > > optional_t
Optional trait value used by endian serialization helpers.
Definition utility.h:1389
safe_ptr< T, c_free< T > > c_ptr
Safe pointer wrapper for memory released by std::free.
Definition utility.h:1635
std::string_view view(It begin, It end)
Read the current value without removing it from the queue.
Definition utility.h:1645
safe_ptr< T, dynamic< T, void, function > > dyn_safe_ptr
Unique pointer using a runtime-provided destroy function.
Definition utility.h:1623