From 093b55cc9a86f0371ae0d7b8d23692e34ecb3128 Mon Sep 17 00:00:00 2001 From: Mingxin Wang Date: Thu, 8 Aug 2024 12:08:46 +0800 Subject: [PATCH] Add more samples (#148) --- CMakeLists.txt | 1 + samples/CMakeLists.txt | 22 ++++++-- samples/PRO_DEF_FREE_DISPATCH.cpp | 19 +++++++ samples/PRO_DEF_MEM_DISPATCH.cpp | 21 ++++++++ samples/PRO_DEF_WEAK_DISPATCH.cpp | 35 +++++++++++++ samples/__msft_lib_proxy.cpp | 15 ++++++ samples/access_proxy.cpp | 32 ++++++++++++ samples/allocate_proxy.cpp | 18 +++++++ samples/basic_facade_builder.cpp | 39 +++++++++++++++ .../basic_facade_builder/add_convention.cpp | 32 ++++++++++++ samples/basic_facade_builder/add_facade.cpp | 50 +++++++++++++++++++ .../basic_facade_builder/add_reflection.cpp | 40 +++++++++++++++ samples/basic_facade_builder/build.cpp | 35 +++++++++++++ .../basic_facade_builder/restrict_layout.cpp | 28 +++++++++++ samples/basic_facade_builder/support_copy.cpp | 21 ++++++++ .../support_destruction.cpp | 19 +++++++ .../support_relocation.cpp | 22 ++++++++ samples/conversion_dispatch.cpp | 41 +++++++++++++++ samples/inplace_proxiable_target.cpp | 20 ++++++++ samples/make_proxy.cpp | 26 ++++++++++ samples/make_proxy_inplace.cpp | 20 ++++++++ samples/operator_dispatch.cpp | 24 +++++++++ samples/proxiable.cpp | 20 ++++++++ .../main.cpp => proxy.cpp} | 10 ++-- samples/proxy/constructor.cpp | 48 ++++++++++++++++++ samples/proxy/destructor.cpp | 17 +++++++ samples/proxy/emplace.cpp | 30 +++++++++++ samples/proxy/friend_operator_equality.cpp | 18 +++++++ samples/proxy/friend_swap.cpp | 25 ++++++++++ samples/proxy/indirection.cpp | 31 ++++++++++++ samples/proxy/operator_bool.cpp | 18 +++++++ samples/proxy/reset.cpp | 16 ++++++ samples/proxy_invoke.cpp | 23 +++++++++ samples/proxy_reflect.cpp | 29 +++++++++++ samples/resource_dictionary/CMakeLists.txt | 2 - tests/CMakeLists.txt | 1 - 36 files changed, 859 insertions(+), 9 deletions(-) create mode 100644 samples/PRO_DEF_FREE_DISPATCH.cpp create mode 100644 samples/PRO_DEF_MEM_DISPATCH.cpp create mode 100644 samples/PRO_DEF_WEAK_DISPATCH.cpp create mode 100644 samples/__msft_lib_proxy.cpp create mode 100644 samples/access_proxy.cpp create mode 100644 samples/allocate_proxy.cpp create mode 100644 samples/basic_facade_builder.cpp create mode 100644 samples/basic_facade_builder/add_convention.cpp create mode 100644 samples/basic_facade_builder/add_facade.cpp create mode 100644 samples/basic_facade_builder/add_reflection.cpp create mode 100644 samples/basic_facade_builder/build.cpp create mode 100644 samples/basic_facade_builder/restrict_layout.cpp create mode 100644 samples/basic_facade_builder/support_copy.cpp create mode 100644 samples/basic_facade_builder/support_destruction.cpp create mode 100644 samples/basic_facade_builder/support_relocation.cpp create mode 100644 samples/conversion_dispatch.cpp create mode 100644 samples/inplace_proxiable_target.cpp create mode 100644 samples/make_proxy.cpp create mode 100644 samples/make_proxy_inplace.cpp create mode 100644 samples/operator_dispatch.cpp create mode 100644 samples/proxiable.cpp rename samples/{resource_dictionary/main.cpp => proxy.cpp} (68%) create mode 100644 samples/proxy/constructor.cpp create mode 100644 samples/proxy/destructor.cpp create mode 100644 samples/proxy/emplace.cpp create mode 100644 samples/proxy/friend_operator_equality.cpp create mode 100644 samples/proxy/friend_swap.cpp create mode 100644 samples/proxy/indirection.cpp create mode 100644 samples/proxy/operator_bool.cpp create mode 100644 samples/proxy/reset.cpp create mode 100644 samples/proxy_invoke.cpp create mode 100644 samples/proxy_reflect.cpp delete mode 100644 samples/resource_dictionary/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 88a9513..5201ef3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,4 +38,5 @@ if (BUILD_TESTING) FetchContent_MakeAvailable(googletest) add_subdirectory(tests) + add_subdirectory(samples) endif() diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 505e20f..46b53b3 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,3 +1,19 @@ -cmake_minimum_required(VERSION 3.14) -find_package(proxy CONFIG REQUIRED) -add_subdirectory(resource_dictionary) +project(msft_proxy_samples) + +file(GLOB_RECURSE SOURCES "*.cpp") + +foreach(SOURCE ${SOURCES}) + file(RELATIVE_PATH REL_PATH ${CMAKE_SOURCE_DIR} ${SOURCE}) + get_filename_component(DIR ${REL_PATH} DIRECTORY) + string(REPLACE "/" "_" DIR_UNDERSCORE ${DIR}) + get_filename_component(EXECUTABLE_NAME ${SOURCE} NAME_WE) + set(FULL_EXECUTABLE_NAME "${DIR_UNDERSCORE}_${EXECUTABLE_NAME}") + add_executable(${FULL_EXECUTABLE_NAME} ${SOURCE}) + target_link_libraries(${FULL_EXECUTABLE_NAME} PRIVATE msft_proxy) +endforeach() + +if (MSVC) + add_compile_options(/W4) +else() + add_compile_options(-Wall -Wextra -Wpedantic) +endif() diff --git a/samples/PRO_DEF_FREE_DISPATCH.cpp b/samples/PRO_DEF_FREE_DISPATCH.cpp new file mode 100644 index 0000000..72e6235 --- /dev/null +++ b/samples/PRO_DEF_FREE_DISPATCH.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from PRO_DEF_FREE_DISPATCH.md. + +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + pro::proxy p = pro::make_proxy(123); + std::cout << ToString(*p) << "\n"; // Prints: "123" +} diff --git a/samples/PRO_DEF_MEM_DISPATCH.cpp b/samples/PRO_DEF_MEM_DISPATCH.cpp new file mode 100644 index 0000000..8244fb3 --- /dev/null +++ b/samples/PRO_DEF_MEM_DISPATCH.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from PRO_DEF_MEM_DISPATCH.md. + +#include +#include +#include + +#include "proxy.h" + +PRO_DEF_MEM_DISPATCH(MemAt, at); + +struct Dictionary : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + std::vector v{"hello", "world"}; + pro::proxy p = &v; + std::cout << p->at(1) << "\n"; // Prints: "world" +} diff --git a/samples/PRO_DEF_WEAK_DISPATCH.cpp b/samples/PRO_DEF_WEAK_DISPATCH.cpp new file mode 100644 index 0000000..6b5edcb --- /dev/null +++ b/samples/PRO_DEF_WEAK_DISPATCH.cpp @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from PRO_DEF_WEAK_DISPATCH.md. + +#include +#include +#include + +#include "proxy.h" + +struct NotImplemented { + explicit NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; } + + template + operator T() const noexcept { std::terminate(); } // Or std::unreachable() in C++23 +}; + +PRO_DEF_MEM_DISPATCH(MemAt, at); +PRO_DEF_WEAK_DISPATCH(WeakMemAt, MemAt, NotImplemented); + +struct WeakDictionary : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + std::vector v{"hello", "world"}; + pro::proxy p1 = &v; + std::cout << p1->at(1) << "\n"; // Prints: "world" + pro::proxy p2 = pro::make_proxy(123); + try { + p2->at(1); + } catch (const std::runtime_error& e) { + std::cout << e.what() << "\n"; // Prints: "Not implemented!" + } +} diff --git a/samples/__msft_lib_proxy.cpp b/samples/__msft_lib_proxy.cpp new file mode 100644 index 0000000..fc9c0ca --- /dev/null +++ b/samples/__msft_lib_proxy.cpp @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from __msft_lib_proxy.md. + +#include + +#include "proxy.h" + +int main() { +#if defined(__msft_lib_proxy) && __msft_lib_proxy >= 202408L + puts("Compiled with library Proxy 3.0.0 or above."); +#else + puts("Cannot determine the version of library Proxy."); +#endif +} diff --git a/samples/access_proxy.cpp b/samples/access_proxy.cpp new file mode 100644 index 0000000..a82e923 --- /dev/null +++ b/samples/access_proxy.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from access_proxy.md. + +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + pro::proxy p = pro::make_proxy(123); + + // Invokes with accessibility API + std::cout << ToString(*p) << "\n"; // Prints: "123" + + // How it works behind the scenes + using Convention = std::tuple_element_t<0u, Stringable::convention_types>; + using Accessor = Convention::accessor; + static_assert(std::is_base_of_v>); + Accessor& a = static_cast(*p); + pro::proxy& p2 = pro::access_proxy(a); + std::cout << std::boolalpha << (&p == &p2) << "\n"; // Prints: "true" because access_proxy converts + // an accessor back to the original proxy + auto result = pro::proxy_invoke(p2); + std::cout << result << "\n"; // Prints: "123" +} diff --git a/samples/allocate_proxy.cpp b/samples/allocate_proxy.cpp new file mode 100644 index 0000000..e24a5c5 --- /dev/null +++ b/samples/allocate_proxy.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from allocate_proxy.md. + +#include + +#include "proxy.h" + +// By default, the maximum pointer size defined by pro::facade_builder +// is 2 * sizeof(void*). This value can be overridden by `restrict_layout`. +struct Any : pro::facade_builder::build {}; + +int main() { + // sizeof(std::array) is usually greater than 2 * sizeof(void*), + // calling allocate_proxy has no limitation to the size and alignment of the target + using Target = std::array; + pro::proxy p1 = pro::allocate_proxy(std::allocator{}); +} diff --git a/samples/basic_facade_builder.cpp b/samples/basic_facade_builder.cpp new file mode 100644 index 0000000..6060928 --- /dev/null +++ b/samples/basic_facade_builder.cpp @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from basic_facade_builder.md. + +#include + +#include "proxy.h" + +template +struct MovableCallable : pro::facade_builder + ::add_convention, Overloads...> + ::build {}; + +template +struct CopyableCallable : pro::facade_builder + ::support_copy + ::add_facade> + ::build {}; + +// MyFunction has similar functionality as std::function but supports multiple overloads +// MyMoveOnlyFunction has similar functionality as std::move_only_function but supports multiple overloads +template +using MyFunction = pro::proxy>; +template +using MyMoveOnlyFunction = pro::proxy>; + +int main() { + auto f = [](auto&&... v) { + std::cout << "f() called. Args: "; + ((std::cout << v << ":" << typeid(decltype(v)).name() << ", "), ...); + std::cout << "\n"; + }; + MyFunction p0{&f}; + (*p0)(123); // Prints "f() called. Args: 123:i," (assuming GCC) + MyMoveOnlyFunction p1{&f}; + (*p1)(); // Prints "f() called. Args:" + (*p1)(456); // Prints "f() called. Args: 456:i," + (*p1)(1.2); // Prints "f() called. Args: 1.2:d," +} diff --git a/samples/basic_facade_builder/add_convention.cpp b/samples/basic_facade_builder/add_convention.cpp new file mode 100644 index 0000000..f27bd05 --- /dev/null +++ b/samples/basic_facade_builder/add_convention.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from add_convention.md. + +#include +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct BasicStringable : pro::facade_builder + ::add_convention + ::build {}; + +struct Stringable : pro::facade_builder + ::add_facade + ::support_copy + ::add_direct_convention>, + pro::proxy() &&> + ::build {}; + +int main() { + pro::proxy p1 = std::make_shared(123); + pro::proxy p2 = p1; + pro::proxy p3 = static_cast>(std::move(p2)); + pro::proxy p4 = std::move(p3); + // pro::proxy p5 = p4; // Won't compile + std::cout << ToString(*p4) << "\n"; // Prints: "123" + std::cout << std::boolalpha << p3.has_value() << "\n"; // Prints: "false" +} diff --git a/samples/basic_facade_builder/add_facade.cpp b/samples/basic_facade_builder/add_facade.cpp new file mode 100644 index 0000000..496ecbf --- /dev/null +++ b/samples/basic_facade_builder/add_facade.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from add_facade.md. + +#include +#include + +#include "proxy.h" + +PRO_DEF_MEM_DISPATCH(MemSize, size); +PRO_DEF_MEM_DISPATCH(MemAt, at); +PRO_DEF_MEM_DISPATCH(MemEmplace, emplace); + +struct Copyable : pro::facade_builder + ::support_copy + ::build {}; + +struct BasicContainer : pro::facade_builder + ::add_convention + ::build {}; + +struct StringDictionary : pro::facade_builder + ::add_facade + ::add_facade + ::add_convention + ::build {}; + +struct MutableStringDictionary : pro::facade_builder + ::add_facade + ::add_convention + ::build {}; + +int main() { + pro::proxy p1 = + pro::make_proxy>(); + std::cout << p1->size() << "\n"; // Prints "0" + try { + std::cout << p1->at(123) << "\n"; // No output because the expression throws + } catch (const std::out_of_range& e) { + std::cerr << e.what() << "\n"; // Prints error message + } + p1->emplace(123, "lalala"); + auto p2 = p1; // Performs a deep copy + p2->emplace(456, "trivial"); + std::cout << p1->size() << "\n"; // Prints "1" + std::cout << p1->at(123) << "\n"; // Prints "lalala" + std::cout << p2->size() << "\n"; // Prints "2" + std::cout << p2->at(123) << "\n"; // Prints "lalala" + std::cout << p2->at(456) << "\n"; // Prints "trivial" +} diff --git a/samples/basic_facade_builder/add_reflection.cpp b/samples/basic_facade_builder/add_reflection.cpp new file mode 100644 index 0000000..9cc7202 --- /dev/null +++ b/samples/basic_facade_builder/add_reflection.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from add_reflection.md. + +#include +#include + +#include "proxy.h" + +class DebugReflection { + public: + template + constexpr explicit DebugReflection(std::in_place_type_t

) + : pointer_type_(typeid(P)), + element_type_(typeid(typename std::pointer_traits

::element_type)) {} + + void PrintDebugInfo() const { + std::cout << "Pointer type: " << pointer_type_.name() << "\n"; + std::cout << "Element type: " << element_type_.name() << "\n"; + } + + private: + const std::type_info& pointer_type_; + const std::type_info& element_type_; +}; + +struct TestFacade : pro::facade_builder + ::add_reflection + ::build {}; + +int main() { + pro::proxy p1 = std::make_shared(123); + pro::proxy_reflect(p1).PrintDebugInfo(); // Prints: "Pointer type: St10shared_ptrIiE" + // "Element type: i" (assuming GCC) + + double v = 3.14; + pro::proxy p2 = &v; + pro::proxy_reflect(p2).PrintDebugInfo(); // Prints: "Pointer type: Pd" + // "Element type: d" (assuming GCC) +} diff --git a/samples/basic_facade_builder/build.cpp b/samples/basic_facade_builder/build.cpp new file mode 100644 index 0000000..0632097 --- /dev/null +++ b/samples/basic_facade_builder/build.cpp @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from build.md. + +#include + +#include "proxy.h" + +struct DefaultBase : pro::facade_builder + ::build {}; + +struct CopyableBase : pro::facade_builder + ::support_copy + ::build {}; + +struct TrivialBase : pro::facade_builder + ::support_copy + ::support_relocation + ::support_destruction + ::restrict_layout + ::build {}; + +int main() { + static_assert(!std::is_copy_constructible_v>); + static_assert(std::is_nothrow_move_constructible_v>); + static_assert(std::is_nothrow_destructible_v>); + + static_assert(std::is_copy_constructible_v>); + static_assert(std::is_nothrow_move_constructible_v>); + static_assert(std::is_nothrow_destructible_v>); + + static_assert(std::is_trivially_copy_constructible_v>); + static_assert(std::is_trivially_move_constructible_v>); + static_assert(std::is_trivially_destructible_v>); +} diff --git a/samples/basic_facade_builder/restrict_layout.cpp b/samples/basic_facade_builder/restrict_layout.cpp new file mode 100644 index 0000000..4cbf550 --- /dev/null +++ b/samples/basic_facade_builder/restrict_layout.cpp @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from restrict_layout.md. + +#include +#include + +#include "proxy.h" + +struct DefaultFacade : pro::facade_builder::build {}; + +struct SmallFacade : pro::facade_builder + ::restrict_layout + ::build {}; + +int main() { + static_assert(sizeof(pro::proxy) > sizeof(pro::proxy)); + static_assert(pro::proxiable, DefaultFacade>); + static_assert(pro::proxiable, SmallFacade>); + static_assert(pro::proxiable, DefaultFacade>); + static_assert(!pro::proxiable, SmallFacade>); + static_assert(pro::inplace_proxiable_target, DefaultFacade>); + static_assert(!pro::inplace_proxiable_target, SmallFacade>); + static_assert(!pro::inplace_proxiable_target, DefaultFacade>); + static_assert(!pro::inplace_proxiable_target, SmallFacade>); + pro::proxy p1 = std::make_shared(123); + // pro::proxy p2 = std::make_shared(123); // Won't compile +} diff --git a/samples/basic_facade_builder/support_copy.cpp b/samples/basic_facade_builder/support_copy.cpp new file mode 100644 index 0000000..a19935b --- /dev/null +++ b/samples/basic_facade_builder/support_copy.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from support_copy.md. + +#include + +#include "proxy.h" + +struct Movable : pro::facade_builder::build {}; + +struct Copyable : pro::facade_builder + ::support_copy + ::build {}; + +int main() { + pro::proxy p1 = std::make_unique(123); + // pro::proxy p2 = std::make_unique(123); // Won't compile + pro::proxy p3 = std::make_shared(456); + // auto p4 = p1; // Won't compile + auto p5 = p3; +} diff --git a/samples/basic_facade_builder/support_destruction.cpp b/samples/basic_facade_builder/support_destruction.cpp new file mode 100644 index 0000000..9b211b4 --- /dev/null +++ b/samples/basic_facade_builder/support_destruction.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from support_destruction.md. + +#include + +#include "proxy.h" + +struct Movable : pro::facade_builder::build {}; + +struct NonriviallyDestructible : pro::facade_builder + ::support_relocation + ::support_destruction + ::build {}; + +int main() { + static_assert(std::is_nothrow_destructible_v>); + static_assert(!std::is_nothrow_destructible_v>); +} diff --git a/samples/basic_facade_builder/support_relocation.cpp b/samples/basic_facade_builder/support_relocation.cpp new file mode 100644 index 0000000..22202d4 --- /dev/null +++ b/samples/basic_facade_builder/support_relocation.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from support_relocation.md. + +#include + +#include "proxy.h" + +struct Movable : pro::facade_builder::build {}; + +struct Trivial : pro::facade_builder + ::support_copy + ::support_relocation + ::support_destruction + ::build {}; + +int main() { + pro::proxy p1 = std::make_unique(123); + // pro::proxy p2 = std::make_unique(456); // Won't compile + double v = 3.14; + pro::proxy p3 = &v; // Compiles because double* is trivial +} diff --git a/samples/conversion_dispatch.cpp b/samples/conversion_dispatch.cpp new file mode 100644 index 0000000..6a5483d --- /dev/null +++ b/samples/conversion_dispatch.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from conversion_dispatch.md. + +#include +#include + +#include "proxy.h" + +struct DoubleConvertible : pro::facade_builder + ::add_convention, double() const> + ::build {}; + +struct Runnable : pro::facade_builder + ::add_convention, void()> + ::build {}; + +struct CopyableRunnable : pro::facade_builder + ::support_copy + ::add_facade + ::add_direct_convention, false>, + pro::proxy() const&, pro::proxy() &&> + ::build {}; + +int main() { + // Explicit conversion + pro::proxy p1 = pro::make_proxy(123); // p1 holds an integer + std::cout << std::fixed << std::setprecision(10) << std::boolalpha; + std::cout << static_cast(*p1) << "\n"; // Prints: "123.0000000000" + + // Implicit conversion + pro::proxy p2 = pro::make_proxy( + [] { std::cout << "Lambda expression invoked\n"; }); + auto p3 = p2; // Copy construction + pro::proxy p4 = p3; // Implicit conversion via const reference of pro::proxy + std::cout << p3.has_value() << "\n"; // Prints: "true" + // auto p5 = p4; // Won't compile because pro::proxy is not copy-constructible + pro::proxy p6 = std::move(p3); // Implicit conversion via rvalue reference of pro::proxy + std::cout << p3.has_value() << "\n"; // Prints: "false" + (*p6)(); // Prints: "Lambda expression invoked" +} diff --git a/samples/inplace_proxiable_target.cpp b/samples/inplace_proxiable_target.cpp new file mode 100644 index 0000000..9e752ce --- /dev/null +++ b/samples/inplace_proxiable_target.cpp @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from inplace_proxiable_target.md. + +#include + +#include "proxy.h" + +// By default, the maximum pointer size defined by pro::facade_builder +// is 2 * sizeof(void*). This value can be overridden by `restrict_layout`. +struct Any : pro::facade_builder::build {}; + +int main() { + // sizeof(int) is usually not greater than sizeof(void*) for modern + // 32/64-bit compilers + static_assert(pro::inplace_proxiable_target); + + // sizeof(std::array) is usually greater than 2 * sizeof(void*) + static_assert(!pro::inplace_proxiable_target, Any>); +} diff --git a/samples/make_proxy.cpp b/samples/make_proxy.cpp new file mode 100644 index 0000000..c5715aa --- /dev/null +++ b/samples/make_proxy.cpp @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from make_proxy.md. + +#include +#include +#include + +#include "proxy.h" + +struct Printable : pro::facade_builder + ::add_convention, std::ostream&(std::ostream&) const> + ::build {}; + +int main() { + pro::proxy p1 = pro::make_proxy(true); // From bool + pro::proxy p2 = pro::make_proxy(123); // From int + pro::proxy p3 = pro::make_proxy(3.1415926); // From double + pro::proxy p4 = pro::make_proxy("lalala"); // From const char* + pro::proxy p5 = pro::make_proxy(5, 'x'); // From a in-place constructed string + std::cout << std::boolalpha << *p1 << "\n"; // Prints: "true" + std::cout << *p2 << "\n"; // Prints: "123" + std::cout << std::fixed << std::setprecision(10) << *p3 << "\n"; // Prints: "3.1415926000" + std::cout << *p4 << "\n"; // Prints: "lalala" + std::cout << *p5 << "\n"; // Prints: "xxxxx" +} diff --git a/samples/make_proxy_inplace.cpp b/samples/make_proxy_inplace.cpp new file mode 100644 index 0000000..40ac8c3 --- /dev/null +++ b/samples/make_proxy_inplace.cpp @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from make_proxy_inplace.md. + +#include + +#include "proxy.h" + +// By default, the maximum pointer size defined by pro::facade_builder +// is 2 * sizeof(void*). This value can be overridden by `restrict_layout`. +struct Any : pro::facade_builder::build {}; + +int main() { + // sizeof(int) is usually not greater than sizeof(void*) for modern + // 32/64-bit compilers + pro::proxy p1 = pro::make_proxy_inplace(123); + + // sizeof(std::array) is usually greater than 2 * sizeof(void*) + // pro::proxy p2 = pro::make_proxy_inplace>(); // Won't compile +} diff --git a/samples/operator_dispatch.cpp b/samples/operator_dispatch.cpp new file mode 100644 index 0000000..a731cd4 --- /dev/null +++ b/samples/operator_dispatch.cpp @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from operator_dispatch.md. + +#include +#include +#include + +#include "proxy.h" + +struct Number : pro::facade_builder + ::add_convention, void(int)> + ::add_convention, std::ostream&(std::ostream&) const&> + ::build {}; + +int main() { + pro::proxy p1 = pro::make_proxy(std::numbers::pi); + *p1 *= 3; + std::cout << std::setprecision(10) << *p1 << "\n"; // Prints: 9.424777961 + + pro::proxy p2 = pro::make_proxy(10); + *p2 *= 5; + std::cout << *p2 << "\n"; // Prints: 50 +} diff --git a/samples/proxiable.cpp b/samples/proxiable.cpp new file mode 100644 index 0000000..7e802fb --- /dev/null +++ b/samples/proxiable.cpp @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from proxiable.md. + +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + static_assert(pro::proxiable); + static_assert(pro::proxiable, Stringable>); + static_assert(!pro::proxiable*, Stringable>); +} diff --git a/samples/resource_dictionary/main.cpp b/samples/proxy.cpp similarity index 68% rename from samples/resource_dictionary/main.cpp rename to samples/proxy.cpp index 408116d..98ba407 100644 --- a/samples/resource_dictionary/main.cpp +++ b/samples/proxy.cpp @@ -1,10 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from proxy.md. + #include #include #include #include #include -#include +#include "proxy.h" PRO_DEF_MEM_DISPATCH(MemAt, at); @@ -22,6 +26,6 @@ int main() { auto container2 = std::make_shared>(); container2->push_back("hello"); container2->push_back("world"); - PrintDictionary(&container1); // prints: hello\n - PrintDictionary(container2); // prints: world\n + PrintDictionary(&container1); // Prints: "hello" + PrintDictionary(container2); // Prints: "world" } diff --git a/samples/proxy/constructor.cpp b/samples/proxy/constructor.cpp new file mode 100644 index 0000000..266b18d --- /dev/null +++ b/samples/proxy/constructor.cpp @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from constructor.md. + +#include +#include +#include + +#include "proxy.h" + +PRO_DEF_MEM_DISPATCH(MemSize, size); +PRO_DEF_MEM_DISPATCH(MemClear, clear); + +struct BasicContainer : pro::facade_builder + ::add_convention + ::add_convention + ::support_copy + ::build {}; + +int main() { + std::vector v{1, 2, 3}; + + pro::proxy p0; + std::cout << std::boolalpha << p0.has_value() << "\n"; // Prints "false" + + // Construct a proxy with a raw pointer + pro::proxy p1 = &v; + std::cout << p1.has_value() << ", " << p1->size() << "\n"; // Prints "true,3" + + // Construct a proxy with a smart pointer + pro::proxy p2 = std::make_shared>(10); + std::cout << p2.has_value() << ", " << p2->size() << "\n"; // Prints "true,10" + + // Copy construction + pro::proxy p3 = p2; + std::cout << p3.has_value() << ", " << p3->size() << "\n"; // Prints "true,10" + + // Move construction + pro::proxy p4 = std::move(p3); + std::cout << p4.has_value() << ", " << p4->size() << "\n"; // Prints "true,10" + + // p3 no longer contains a value + std::cout << p3.has_value() << "\n"; // Prints "false" + + // p2 and p4 shares the same object of std::deque + p2->clear(); + std::cout << p4.has_value() << ", " << p4->size() << "\n"; // Prints "true,0" +} diff --git a/samples/proxy/destructor.cpp b/samples/proxy/destructor.cpp new file mode 100644 index 0000000..c28e7ac --- /dev/null +++ b/samples/proxy/destructor.cpp @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from destructor.md. + +#include + +#include "proxy.h" + +struct AnyMovable : pro::facade_builder::build {}; + +struct Foo { + ~Foo() { puts("Destroy Foo"); } +}; + +int main() { + pro::proxy p = pro::make_proxy(); +} // The destructor of `Foo` is called when `p` is destroyed diff --git a/samples/proxy/emplace.cpp b/samples/proxy/emplace.cpp new file mode 100644 index 0000000..d69fb19 --- /dev/null +++ b/samples/proxy/emplace.cpp @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from emplace.md. + +#include +#include +#include + +#include "proxy.h" + +struct AnyCopyable : pro::facade_builder + ::support_copy + ::build {}; + +struct Foo { + ~Foo() { puts("Destroy Foo"); } + + int payload[10000]; +}; + +int main() { + static std::pmr::unsynchronized_pool_resource my_memory_pool; + + std::pmr::polymorphic_allocator<> alloc{&my_memory_pool}; + auto deleter = [alloc](auto* ptr) mutable { alloc.delete_object(ptr); }; + + pro::proxy p0; + p0.emplace>(alloc.new_object(), deleter); + pro::proxy p1 = p0; // `Foo` is not copied. Only the reference count is increased. +} // The destructor of `Foo` is called once when both `p0` and `p1` are destroyed diff --git a/samples/proxy/friend_operator_equality.cpp b/samples/proxy/friend_operator_equality.cpp new file mode 100644 index 0000000..3261f87 --- /dev/null +++ b/samples/proxy/friend_operator_equality.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from friend_operator_equality.md. + +#include + +#include "proxy.h" + +struct AnyMovable : pro::facade_builder::build {}; + +int main() { + pro::proxy p; + std::cout << std::boolalpha << (p == nullptr) << "\n"; // Prints "true" + std::cout << (p != nullptr) << "\n"; // Prints "false" + p = std::make_unique(123); + std::cout << (p == nullptr) << "\n"; // Prints "false" + std::cout << (p != nullptr) << "\n"; // Prints "true" +} diff --git a/samples/proxy/friend_swap.cpp b/samples/proxy/friend_swap.cpp new file mode 100644 index 0000000..4ca2465 --- /dev/null +++ b/samples/proxy/friend_swap.cpp @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from friend_swap.md. + +#include +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + pro::proxy p0 = pro::make_proxy(123); + pro::proxy p1 = pro::make_proxy(std::numbers::pi); + std::cout << ToString(*p0) << "\n"; // Prints "10" + std::cout << ToString(*p1) << "\n"; // Prints "3.14..." + std::ranges::swap(p0, p1); // finds the hidden friend + std::cout << ToString(*p0) << "\n"; // Prints "3.14..." + std::cout << ToString(*p1) << "\n"; // Prints "10" +} diff --git a/samples/proxy/indirection.cpp b/samples/proxy/indirection.cpp new file mode 100644 index 0000000..a3591bf --- /dev/null +++ b/samples/proxy/indirection.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from indirection.md. + +#include +#include +#include + +#include "proxy.h" + +PRO_DEF_MEM_DISPATCH(MemSize, size); + +struct BasicContainer : pro::facade_builder + ::add_convention + ::build {}; + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + std::vector v(10); + pro::proxy p0 = &v; + std::cout << p0->size() << "\n"; // Prints "10" + std::cout << (*p0).size() << "\n"; // Prints "10" + + pro::proxy p1 = pro::make_proxy(123); + std::cout << ToString(*p1) << "\n"; // Prints "123" +} diff --git a/samples/proxy/operator_bool.cpp b/samples/proxy/operator_bool.cpp new file mode 100644 index 0000000..e75920f --- /dev/null +++ b/samples/proxy/operator_bool.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from operator_bool.md. + +#include + +#include "proxy.h" + +struct AnyMovable : pro::facade_builder::build {}; + +int main() { + pro::proxy p; + std::cout << std::boolalpha << p.has_value() << "\n"; // Prints "false" + p = pro::make_proxy(123); + std::cout << p.has_value() << "\n"; // Prints "true" + p = nullptr; + std::cout << static_cast(p) << "\n"; // Prints "false" +} diff --git a/samples/proxy/reset.cpp b/samples/proxy/reset.cpp new file mode 100644 index 0000000..b132830 --- /dev/null +++ b/samples/proxy/reset.cpp @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from reset.md. + +#include + +#include "proxy.h" + +struct AnyMovable : pro::facade_builder::build {}; + +int main() { + pro::proxy p = pro::make_proxy(123); + std::cout << std::boolalpha << p.has_value() << "\n"; // Prints "true" + p.reset(); + std::cout << p.has_value() << "\n"; // Prints "false" +} diff --git a/samples/proxy_invoke.cpp b/samples/proxy_invoke.cpp new file mode 100644 index 0000000..ffce4c6 --- /dev/null +++ b/samples/proxy_invoke.cpp @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from proxy_invoke.md. + +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + int a = 123; + pro::proxy p = &a; + std::cout << ToString(*p) << "\n"; // Invokes with accessor, prints: "123" + + using C = std::tuple_element_t<0u, Stringable::convention_types>; + std::cout << pro::proxy_invoke(p) << "\n"; // Invokes with proxy_invoke, also prints: "123" +} diff --git a/samples/proxy_reflect.cpp b/samples/proxy_reflect.cpp new file mode 100644 index 0000000..852e736 --- /dev/null +++ b/samples/proxy_reflect.cpp @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// This file contains example code from proxy_reflect.md. + +#include +#include +#include + +#include "proxy.h" + +struct TraitsRefl { + template + constexpr explicit TraitsRefl(std::in_place_type_t

) + : Copyable(std::is_copy_constructible_v

) {} + + const bool Copyable; +}; + +struct TestFacade : pro::facade_builder + ::add_reflection + ::build {}; + +int main() { + pro::proxy p1 = std::make_unique(); + std::cout << std::boolalpha << pro::proxy_reflect(p1).Copyable << "\n"; // Prints: "false" + + pro::proxy p2 = std::make_shared(); + std::cout << pro::proxy_reflect(p2).Copyable << "\n"; // Prints: "true" +} diff --git a/samples/resource_dictionary/CMakeLists.txt b/samples/resource_dictionary/CMakeLists.txt deleted file mode 100644 index e5cfb35..0000000 --- a/samples/resource_dictionary/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_executable(resource_dictionary main.cpp) -target_link_libraries(resource_dictionary PRIVATE msft_proxy) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bd5d82d..49fa868 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,7 +9,6 @@ add_executable(msft_proxy_tests proxy_traits_tests.cpp ) target_include_directories(msft_proxy_tests PRIVATE .) -target_compile_features(msft_proxy_tests PRIVATE cxx_std_20) target_link_libraries(msft_proxy_tests PRIVATE msft_proxy) target_link_libraries(msft_proxy_tests PRIVATE gtest_main)