Skip to content

Commit aa384eb

Browse files
authored
Implement make_proxy_inplace and inplace_proxiable_target with freestanding (#92)
* Implement make_proxy_inplace and inplace_proxiable_target with freestanding * Add freestanding tests * Merge * Fix regression in code generation for `copying_default_dispatcher` * Fix build * Add noexcept * Remove empty line * Resolve comments
1 parent 60ecacd commit aa384eb

File tree

6 files changed

+154
-44
lines changed

6 files changed

+154
-44
lines changed

Diff for: CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if (BUILD_TESTING)
3232
googletest
3333
URL https://github.com/google/googletest/archive/e2239ee6043f73722e7aa812a459f54a28552929.zip
3434
)
35-
35+
3636
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # For Windows: Prevent overriding the parent project's compiler/linker settings
3737
set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) # Disable GMock
3838
FetchContent_MakeAvailable(googletest)

Diff for: proxy.h

+50-22
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#ifndef _MSFT_PROXY_
55
#define _MSFT_PROXY_
66

7-
#include <cstring>
87
#include <bit>
98
#include <concepts>
109
#include <initializer_list>
@@ -197,8 +196,8 @@ void copying_dispatcher(char* self, const char* rhs)
197196
}
198197
template <std::size_t Len, std::size_t Align>
199198
void copying_default_dispatcher(char* self, const char* rhs) noexcept {
200-
std::memcpy(std::assume_aligned<Align>(self),
201-
std::assume_aligned<Align>(rhs), Len);
199+
std::uninitialized_copy_n(
200+
std::assume_aligned<Align>(rhs), Len, std::assume_aligned<Align>(self));
202201
}
203202
template <class P>
204203
void relocation_dispatcher(char* self, const char* rhs)
@@ -525,7 +524,7 @@ class proxy {
525524
if (rhs.meta_.has_value()) {
526525
if constexpr (F::constraints.relocatability ==
527526
constraint_level::trivial) {
528-
memcpy(ptr_, rhs.ptr_, F::constraints.max_size);
527+
std::ranges::uninitialized_copy(rhs.ptr_, ptr_);
529528
} else {
530529
rhs.meta_->Traits::relocatability_meta::dispatcher(ptr_, rhs.ptr_);
531530
}
@@ -698,23 +697,25 @@ constexpr proxiable_ptr_constraints trivial_ptr_constraints{
698697
namespace details {
699698

700699
template <class T>
701-
class sbo_ptr {
700+
class inplace_ptr {
702701
public:
703702
template <class... Args>
704-
sbo_ptr(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
703+
inplace_ptr(Args&&... args)
704+
noexcept(std::is_nothrow_constructible_v<T, Args...>)
705705
requires(std::is_constructible_v<T, Args...>)
706706
: value_(std::forward<Args>(args)...) {}
707-
sbo_ptr(const sbo_ptr&) noexcept(std::is_nothrow_copy_constructible_v<T>)
708-
= default;
709-
sbo_ptr(sbo_ptr&&) noexcept(std::is_nothrow_move_constructible_v<T>)
710-
= default;
707+
inplace_ptr(const inplace_ptr&)
708+
noexcept(std::is_nothrow_copy_constructible_v<T>) = default;
709+
inplace_ptr(inplace_ptr&&)
710+
noexcept(std::is_nothrow_move_constructible_v<T>) = default;
711711

712712
T* operator->() const noexcept { return &value_; }
713713

714714
private:
715715
mutable T value_;
716716
};
717717

718+
#if __STDC_HOSTED__
718719
template <class T, class Alloc>
719720
static auto rebind_allocator(const Alloc& alloc) {
720721
return typename std::allocator_traits<Alloc>::template rebind_alloc<T>(alloc);
@@ -761,7 +762,6 @@ class allocated_ptr {
761762
Alloc alloc_;
762763
T* ptr_;
763764
};
764-
765765
template <class T, class Alloc>
766766
class compact_ptr {
767767
public:
@@ -782,36 +782,63 @@ class compact_ptr {
782782
struct storage {
783783
template <class... Args>
784784
explicit storage(const Alloc& alloc, Args&&... args)
785-
: alloc(alloc), value(std::forward<Args>(args)...) {}
785+
: value(std::forward<Args>(args)...), alloc(alloc) {}
786786

787-
Alloc alloc;
788787
T value;
788+
Alloc alloc;
789789
};
790790

791791
storage* ptr_;
792792
};
793-
794793
template <class F, class T, class Alloc, class... Args>
795794
proxy<F> allocate_proxy_impl(const Alloc& alloc, Args&&... args) {
796-
if constexpr (proxiable<details::sbo_ptr<T>, F>) {
797-
return proxy<F>{std::in_place_type<details::sbo_ptr<T>>,
798-
std::forward<Args>(args)...};
799-
} else if constexpr (proxiable<details::allocated_ptr<T, Alloc>, F>) {
800-
return proxy<F>{std::in_place_type<details::allocated_ptr<T, Alloc>>,
795+
if constexpr (proxiable<allocated_ptr<T, Alloc>, F>) {
796+
return proxy<F>{std::in_place_type<allocated_ptr<T, Alloc>>,
801797
alloc, std::forward<Args>(args)...};
802798
} else {
803-
return proxy<F>{std::in_place_type<details::compact_ptr<T, Alloc>>,
799+
return proxy<F>{std::in_place_type<compact_ptr<T, Alloc>>,
804800
alloc, std::forward<Args>(args)...};
805801
}
806802
}
807803
template <class F, class T, class... Args>
808804
proxy<F> make_proxy_impl(Args&&... args) {
809-
return allocate_proxy_impl<F, T>(
810-
std::allocator<T>{}, std::forward<Args>(args)...);
805+
if constexpr (proxiable<inplace_ptr<T>, F>) {
806+
return proxy<F>{std::in_place_type<inplace_ptr<T>>,
807+
std::forward<Args>(args)...};
808+
} else {
809+
return allocate_proxy_impl<F, T>(
810+
std::allocator<T>{}, std::forward<Args>(args)...);
811+
}
811812
}
813+
#endif // __STDC_HOSTED__
812814

813815
} // namespace details
814816

817+
template <class T, class F>
818+
concept inplace_proxiable_target = proxiable<details::inplace_ptr<T>, F>;
819+
820+
template <facade F, inplace_proxiable_target<F> T, class... Args>
821+
proxy<F> make_proxy_inplace(Args&&... args)
822+
noexcept(std::is_nothrow_constructible_v<T, Args...>) {
823+
return proxy<F>{std::in_place_type<details::inplace_ptr<T>>,
824+
std::forward<Args>(args)...};
825+
}
826+
template <facade F, inplace_proxiable_target<F> T, class U, class... Args>
827+
proxy<F> make_proxy_inplace(std::initializer_list<U> il, Args&&... args)
828+
noexcept(std::is_nothrow_constructible_v<
829+
T, std::initializer_list<U>&, Args...>) {
830+
return proxy<F>{std::in_place_type<details::inplace_ptr<T>>,
831+
il, std::forward<Args>(args)...};
832+
}
833+
template <facade F, class T>
834+
proxy<F> make_proxy_inplace(T&& value)
835+
noexcept(std::is_nothrow_constructible_v<std::decay_t<T>, T>)
836+
requires(inplace_proxiable_target<std::decay_t<T>, F>) {
837+
return proxy<F>{std::in_place_type<details::inplace_ptr<std::decay_t<T>>>,
838+
std::forward<T>(value)};
839+
}
840+
841+
#if __STDC_HOSTED__
815842
template <facade F, class T, class Alloc, class... Args>
816843
proxy<F> allocate_proxy(const Alloc& alloc, Args&&... args) {
817844
return details::allocate_proxy_impl<F, T>(alloc, std::forward<Args>(args)...);
@@ -837,6 +864,7 @@ template <facade F, class T>
837864
proxy<F> make_proxy(T&& value) {
838865
return details::make_proxy_impl<F, std::decay_t<T>>(std::forward<T>(value));
839866
}
867+
#endif // __STDC_HOSTED__
840868

841869
// The following types and macros aim to simplify definition of dispatch and
842870
// facade types prior to C++26

Diff for: tests/CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,13 @@ endif()
2020

2121
include(GoogleTest)
2222
gtest_discover_tests(msft_proxy_tests)
23+
24+
if(NOT MSVC)
25+
add_executable(msft_proxy_freestanding_tests freestanding/proxy_freestanding_tests.cpp)
26+
target_include_directories(msft_proxy_freestanding_tests PRIVATE .)
27+
target_compile_features(msft_proxy_freestanding_tests PRIVATE cxx_std_20)
28+
target_compile_options(msft_proxy_freestanding_tests PRIVATE -ffreestanding -fno-exceptions -fno-rtti -Wall -Wextra -Wpedantic -Werror)
29+
target_link_options(msft_proxy_freestanding_tests PRIVATE -nodefaultlibs -lc)
30+
target_link_libraries(msft_proxy_freestanding_tests PRIVATE msft_proxy)
31+
add_test(NAME ProxyFreestandingTests COMMAND msft_proxy_freestanding_tests)
32+
endif()

Diff for: tests/freestanding/proxy_freestanding_tests.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#if __STDC_HOSTED__
2+
#error "This file shall be compiled targeting a freestanding environment."
3+
#endif // __STDC_HOSTED__
4+
5+
#include "proxy.h"
6+
7+
unsigned GetHash(int v) { return static_cast<unsigned>(v + 3) * 31; }
8+
unsigned GetHash(double v) { return static_cast<unsigned>(v * v + 5) * 87; }
9+
unsigned GetHash(const char* v) {
10+
unsigned result = 91u;
11+
for (int i = 0; v[i]; ++i) {
12+
result = result * 47u + v[i];
13+
}
14+
return result;
15+
}
16+
unsigned GetDefaultHash() { return -1; }
17+
18+
namespace spec {
19+
20+
PRO_DEF_FREE_DISPATCH_WITH_DEFAULT(GetHash, ::GetHash, ::GetDefaultHash, unsigned());
21+
PRO_DEF_FACADE(Hashable, GetHash);
22+
23+
} // namespace spec
24+
25+
extern "C" int main() {
26+
int i = 123;
27+
double d = 3.14159;
28+
const char* s = "lalala";
29+
std::tuple<int, double> t{11, 22};
30+
pro::proxy<spec::Hashable> p;
31+
p = &i;
32+
if (p() != GetHash(i)) {
33+
return 1;
34+
}
35+
p = &d;
36+
if (p() != GetHash(d)) {
37+
return 1;
38+
}
39+
p = pro::make_proxy_inplace<spec::Hashable>(s);
40+
if (p() != GetHash(s)) {
41+
return 1;
42+
}
43+
p = &t;
44+
if (p() != GetDefaultHash()) {
45+
return 1;
46+
}
47+
return 0;
48+
}

0 commit comments

Comments
 (0)