Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more samples #148

Merged
merged 2 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading