Skip to content

Commit

Permalink
Add more samples (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
mingxwa authored Aug 8, 2024
1 parent 9e74c52 commit 093b55c
Show file tree
Hide file tree
Showing 36 changed files with 859 additions and 9 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ if (BUILD_TESTING)
FetchContent_MakeAvailable(googletest)

add_subdirectory(tests)
add_subdirectory(samples)
endif()
22 changes: 19 additions & 3 deletions samples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
19 changes: 19 additions & 0 deletions samples/PRO_DEF_FREE_DISPATCH.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <string>

#include "proxy.h"

PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString);

struct Stringable : pro::facade_builder
::add_convention<FreeToString, std::string()>
::build {};

int main() {
pro::proxy<Stringable> p = pro::make_proxy<Stringable>(123);
std::cout << ToString(*p) << "\n"; // Prints: "123"
}
21 changes: 21 additions & 0 deletions samples/PRO_DEF_MEM_DISPATCH.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <string>
#include <vector>

#include "proxy.h"

PRO_DEF_MEM_DISPATCH(MemAt, at);

struct Dictionary : pro::facade_builder
::add_convention<MemAt, std::string(int index) const>
::build {};

int main() {
std::vector<const char*> v{"hello", "world"};
pro::proxy<Dictionary> p = &v;
std::cout << p->at(1) << "\n"; // Prints: "world"
}
35 changes: 35 additions & 0 deletions samples/PRO_DEF_WEAK_DISPATCH.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <string>
#include <vector>

#include "proxy.h"

struct NotImplemented {
explicit NotImplemented(auto&&...) { throw std::runtime_error{ "Not implemented!" }; }

template <class T>
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<WeakMemAt, std::string(int index) const>
::build {};

int main() {
std::vector<const char*> v{"hello", "world"};
pro::proxy<WeakDictionary> p1 = &v;
std::cout << p1->at(1) << "\n"; // Prints: "world"
pro::proxy<WeakDictionary> p2 = pro::make_proxy<WeakDictionary>(123);
try {
p2->at(1);
} catch (const std::runtime_error& e) {
std::cout << e.what() << "\n"; // Prints: "Not implemented!"
}
}
15 changes: 15 additions & 0 deletions samples/__msft_lib_proxy.cpp
Original file line number Diff line number Diff line change
@@ -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 <cstdio>

#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
}
32 changes: 32 additions & 0 deletions samples/access_proxy.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <string>

#include "proxy.h"

PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString);

struct Stringable : pro::facade_builder
::add_convention<FreeToString, std::string()>
::build {};

int main() {
pro::proxy<Stringable> p = pro::make_proxy<Stringable>(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<Stringable>;
static_assert(std::is_base_of_v<Accessor, std::remove_reference_t<decltype(*p)>>);
Accessor& a = static_cast<Accessor&>(*p);
pro::proxy<Stringable>& p2 = pro::access_proxy<Stringable>(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<Convention>(p2);
std::cout << result << "\n"; // Prints: "123"
}
18 changes: 18 additions & 0 deletions samples/allocate_proxy.cpp
Original file line number Diff line number Diff line change
@@ -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 <array>

#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<int, 100>) 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<int, 100>;
pro::proxy<Any> p1 = pro::allocate_proxy<Any, Target>(std::allocator<Target>{});
}
39 changes: 39 additions & 0 deletions samples/basic_facade_builder.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>

#include "proxy.h"

template <class... Overloads>
struct MovableCallable : pro::facade_builder
::add_convention<pro::operator_dispatch<"()">, Overloads...>
::build {};

template <class... Overloads>
struct CopyableCallable : pro::facade_builder
::support_copy<pro::constraint_level::nontrivial>
::add_facade<MovableCallable<Overloads...>>
::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 <class... Overloads>
using MyFunction = pro::proxy<CopyableCallable<Overloads...>>;
template <class... Overloads>
using MyMoveOnlyFunction = pro::proxy<MovableCallable<Overloads...>>;

int main() {
auto f = [](auto&&... v) {
std::cout << "f() called. Args: ";
((std::cout << v << ":" << typeid(decltype(v)).name() << ", "), ...);
std::cout << "\n";
};
MyFunction<void(int)> p0{&f};
(*p0)(123); // Prints "f() called. Args: 123:i," (assuming GCC)
MyMoveOnlyFunction<void(), void(int), void(double)> 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,"
}
32 changes: 32 additions & 0 deletions samples/basic_facade_builder/add_convention.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <memory>
#include <string>

#include "proxy.h"

PRO_DEF_FREE_DISPATCH(FreeToString, std::to_string, ToString);

struct BasicStringable : pro::facade_builder
::add_convention<FreeToString, std::string() const>
::build {};

struct Stringable : pro::facade_builder
::add_facade<BasicStringable>
::support_copy<pro::constraint_level::nontrivial>
::add_direct_convention<pro::conversion_dispatch<pro::proxy<BasicStringable>>,
pro::proxy<BasicStringable>() &&>
::build {};

int main() {
pro::proxy<Stringable> p1 = std::make_shared<int>(123);
pro::proxy<Stringable> p2 = p1;
pro::proxy<BasicStringable> p3 = static_cast<pro::proxy<BasicStringable>>(std::move(p2));
pro::proxy<BasicStringable> p4 = std::move(p3);
// pro::proxy<BasicStringable> p5 = p4; // Won't compile
std::cout << ToString(*p4) << "\n"; // Prints: "123"
std::cout << std::boolalpha << p3.has_value() << "\n"; // Prints: "false"
}
50 changes: 50 additions & 0 deletions samples/basic_facade_builder/add_facade.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <unordered_map>

#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<pro::constraint_level::nontrivial>
::build {};

struct BasicContainer : pro::facade_builder
::add_convention<MemSize, std::size_t() const noexcept>
::build {};

struct StringDictionary : pro::facade_builder
::add_facade<BasicContainer>
::add_facade<Copyable>
::add_convention<MemAt, std::string(std::size_t key) const>
::build {};

struct MutableStringDictionary : pro::facade_builder
::add_facade<StringDictionary>
::add_convention<MemEmplace, void(std::size_t key, std::string value)>
::build {};

int main() {
pro::proxy<MutableStringDictionary> p1 =
pro::make_proxy<MutableStringDictionary, std::unordered_map<std::size_t, std::string>>();
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"
}
40 changes: 40 additions & 0 deletions samples/basic_facade_builder/add_reflection.cpp
Original file line number Diff line number Diff line change
@@ -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 <iostream>
#include <typeinfo>

#include "proxy.h"

class DebugReflection {
public:
template <class P>
constexpr explicit DebugReflection(std::in_place_type_t<P>)
: pointer_type_(typeid(P)),
element_type_(typeid(typename std::pointer_traits<P>::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<DebugReflection>
::build {};

int main() {
pro::proxy<TestFacade> p1 = std::make_shared<int>(123);
pro::proxy_reflect<DebugReflection>(p1).PrintDebugInfo(); // Prints: "Pointer type: St10shared_ptrIiE"
// "Element type: i" (assuming GCC)

double v = 3.14;
pro::proxy<TestFacade> p2 = &v;
pro::proxy_reflect<DebugReflection>(p2).PrintDebugInfo(); // Prints: "Pointer type: Pd"
// "Element type: d" (assuming GCC)
}
35 changes: 35 additions & 0 deletions samples/basic_facade_builder/build.cpp
Original file line number Diff line number Diff line change
@@ -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 <type_traits>

#include "proxy.h"

struct DefaultBase : pro::facade_builder
::build {};

struct CopyableBase : pro::facade_builder
::support_copy<pro::constraint_level::nontrivial>
::build {};

struct TrivialBase : pro::facade_builder
::support_copy<pro::constraint_level::trivial>
::support_relocation<pro::constraint_level::trivial>
::support_destruction<pro::constraint_level::trivial>
::restrict_layout<sizeof(void*)>
::build {};

int main() {
static_assert(!std::is_copy_constructible_v<pro::proxy<DefaultBase>>);
static_assert(std::is_nothrow_move_constructible_v<pro::proxy<DefaultBase>>);
static_assert(std::is_nothrow_destructible_v<pro::proxy<DefaultBase>>);

static_assert(std::is_copy_constructible_v<pro::proxy<CopyableBase>>);
static_assert(std::is_nothrow_move_constructible_v<pro::proxy<CopyableBase>>);
static_assert(std::is_nothrow_destructible_v<pro::proxy<CopyableBase>>);

static_assert(std::is_trivially_copy_constructible_v<pro::proxy<TrivialBase>>);
static_assert(std::is_trivially_move_constructible_v<pro::proxy<TrivialBase>>);
static_assert(std::is_trivially_destructible_v<pro::proxy<TrivialBase>>);
}
Loading

0 comments on commit 093b55c

Please sign in to comment.