Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
argument_proxy.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <sysio/vm/types.hpp>
4#include <sysio/vm/span.hpp>
5
6#include <memory>
7namespace sysio { namespace vm {
8
9 // Used for pointer arguments to intrinsics.
10 // T should be a type that points to external memory, such as a pointer or span.
11 // The type that T points to must be trivially copyable.
12 // argument_proxy copies unaligned memory into zero or more objects of the pointee type.
13 // If LegacyAlign is non-zero it will only copy the memory if it is not aligned to LegacyAlign.
14 // If the pointee is mutable, the memory will be written back by the destructor.
15 template <typename T, std::size_t LegacyAlign=0>
16 struct argument_proxy;
17
18 // specialization of argument_proxy for pointers.
19 // copies a single element.
20 template <typename T, std::size_t LegacyAlign>
21 struct argument_proxy<T*, LegacyAlign> {
22 static_assert(LegacyAlign % alignof(T) == 0, "Specified alignment must be at least alignment of T");
23 static_assert(std::is_trivially_copyable_v<T>, "argument_proxy requires a trivially copyable type");
24 inline constexpr argument_proxy(void* ptr) : original_ptr(ptr) {
25 if (!LegacyAlign || reinterpret_cast<std::uintptr_t>(original_ptr) % LegacyAlign != 0) {
26 copy.emplace();
27 memcpy( std::addressof(*copy), original_ptr, sizeof(T) );
28 }
29 }
30 inline constexpr argument_proxy(const argument_proxy&) = delete;
31 inline constexpr argument_proxy(argument_proxy&& other) : original_ptr(other.original_ptr), copy(other.copy) {
32 other.copy.reset();
33 other.original_ptr = nullptr;
34 }
35 inline ~argument_proxy() {
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wnonnull"
38 if constexpr (!std::is_const_v<T>)
39 if (copy)
40 memcpy(original_ptr, std::addressof(*copy), sizeof(T));
41#pragma GCC diagnostic pop
42 }
43 constexpr operator T*() { return get(); }
44 constexpr operator const T*() const { return get(); }
45
46 constexpr T* get() { return const_cast<T*>(const_cast<const argument_proxy*>(this)->get()); }
47 constexpr const T* get() const {
48 if (copy)
49 return std::addressof(*copy);
50 else
51 return static_cast<const T*>(original_ptr);
52 }
53 constexpr T* operator->() { return get(); }
54 constexpr const T* operator->() const { return get(); }
55
56 static constexpr bool is_legacy() { return LegacyAlign != 0; }
57 using pointee_type = T;
58 using proxy_type = T*;
59 constexpr const void* get_original_pointer() const { return original_ptr; }
60
61 private:
62 void* original_ptr;
63 std::optional<std::remove_cv_t<T>> copy;
64 };
65
66 template <typename T, std::size_t LegacyAlign>
67 struct argument_proxy<span<T>, LegacyAlign> : span<T> {
68 static_assert(LegacyAlign % alignof(T) == 0, "Specified alignment must be at least alignment of T");
69 static_assert(std::is_trivially_copyable_v<T>, "argument_proxy requires a trivially copyable type");
70 using pointee_type = T;
72 inline constexpr argument_proxy(void* ptr, uint32_t size)
73 : original_ptr(ptr),
74 copy( is_aligned(ptr) ? nullptr : new std::remove_cv_t<T>[size] ) {
75 *static_cast<span<T>*>(this) = span<T>( copy ? copy.get() : static_cast<T*>(ptr), size );
76 if (copy)
77 memcpy( copy.get(), original_ptr, this->size_bytes() );
78 }
79 inline constexpr argument_proxy(const argument_proxy&) = delete;
80 inline constexpr argument_proxy(argument_proxy&&) = default;
81 inline ~argument_proxy() {
82#pragma GCC diagnostic push
83#pragma GCC diagnostic ignored "-Wnonnull"
84 if constexpr (!std::is_const_v<T>)
85 if (copy)
86 memcpy(original_ptr, copy.get(), this->size_bytes());
87#pragma GCC diagnostic pop
88 }
89 static constexpr bool is_legacy() { return LegacyAlign != 0; }
90 constexpr const void* get_original_pointer() const { return original_ptr; }
91
92 private:
93 inline static constexpr bool is_aligned(void* ptr) { return reinterpret_cast<std::uintptr_t>(ptr) % LegacyAlign == 0; }
94 void* original_ptr;
95 std::unique_ptr<std::remove_cv_t<T>[]> copy = nullptr;
96 };
97
98 namespace detail {
99 template <typename T>
100 constexpr inline std::true_type is_argument_proxy_type(argument_proxy<T>);
101 template <typename T, std::size_t LA>
102 constexpr inline std::true_type is_argument_proxy_type(argument_proxy<T, LA>);
103 template <typename T>
104 constexpr inline std::false_type is_argument_proxy_type(T);
105 }
106
107 template <typename T>
108 constexpr inline static bool is_argument_proxy_type_v = std::is_same_v<decltype(detail::is_argument_proxy_type(std::declval<T>())), std::true_type>;
109
110}} // ns sysio::vm
void copy(const path &from, const path &to)
Definition name.hpp:106
sysio::vm::span< T, Extent > span
Definition common.hpp:26
constexpr std::true_type is_argument_proxy_type(argument_proxy< T >)
#define T(meth, val, expected)
unsigned int uint32_t
Definition stdint.h:126
constexpr const void * get_original_pointer() const
constexpr argument_proxy(argument_proxy &&other)
constexpr argument_proxy(const argument_proxy &)=delete
constexpr argument_proxy(argument_proxy &&)=default
constexpr argument_proxy(const argument_proxy &)=delete
constexpr argument_proxy(void *ptr, uint32_t size)
memcpy((char *) pInfo->slotDescription, s, l)