Skip to content
This repository was archived by the owner on Jan 29, 2026. It is now read-only.
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
5 changes: 2 additions & 3 deletions .github/workflows/pipeline-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ jobs:
- name: pack source
id: run-pack
run: |
file="CMakeLists.txt"
version=$(grep -oP 'msft_proxy\s+VERSION\s+\K[0-9]+\.[0-9]+\.[0-9]+' "$file")
version=$(grep -oP 'msft_proxy\s+VERSION\s+\K[0-9]+\.[0-9]+\.[0-9]+' CMakeLists.txt)
git tag "$version"
git push origin "$version"
tar -czf "proxy-$version.tgz" "proxy.h"
tar -czf "proxy-$version.tgz" proxy.h proxy_fmt.h
echo "PRO_VER=$version" >> $GITHUB_OUTPUT
shell: bash

Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ target_include_directories(msft_proxy INTERFACE $<BUILD_INTERFACE:${CMAKE_CURREN
include(GNUInstallDirs)
install(TARGETS msft_proxy
EXPORT proxyConfig)
install(FILES proxy.h
install(FILES proxy.h proxy_fmt.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/proxy)
install(EXPORT proxyConfig DESTINATION ${CMAKE_INSTALL_DATADIR}/proxy)
export(TARGETS msft_proxy FILE proxyConfig.cmake)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ If so, this library is for you.

"Proxy" was created by Microsoft engineers and has been used in the Windows operating system since 2022. For many years, using inheritance was the main way to achieve polymorphism in C++. However, new programming languages like [Rust](https://doc.rust-lang.org/book/ch10-02-traits.html) offer better ways to do this. We have improved our understanding of object-oriented programming and decided to use *pointers* in C++ as the foundation for "Proxy". Specifically, the "Proxy" library is designed to be:

- **Portable**: "Proxy" was implemented as a single-header library in standard C++20. It can be used on any platform while the compiler supports C++20. The majority of the library is [freestanding](https://en.cppreference.com/w/cpp/freestanding), making it feasible for embedded engineering or kernel design of an operating system.
- **Portable**: "Proxy" was implemented as a header-only library in standard C++20. It can be used on any platform while the compiler supports C++20. The majority of the library is [freestanding](https://en.cppreference.com/w/cpp/freestanding), making it feasible for embedded engineering or kernel design of an operating system.
- **Non-intrusive**: An implementation type is no longer required to inherit from an abstract binding.
- **Well-managed**: "Proxy" provides a GC-like capability that manages the lifetimes of different objects efficiently without the need for an actual garbage collector.
- **Fast**: With typical compiler optimizations, "Proxy" produces high-quality code that is as good as or better than hand-written code. In many cases, "Proxy" performs better than traditional inheritance-based approaches, especially in managing the lifetimes of objects.
Expand Down
4 changes: 2 additions & 2 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

### <a name="what">What is "Proxy" and how does it work?</a>

"Proxy" is a single-header, cross-platform C++20 template library for modern runtime polymorphism based on pointer-semantics. Similar with C++ [virtual functions](https://en.cppreference.com/w/cpp/language/virtual), it generates indirect functions behind the scenes at compile-time but does not require inheritance. It also has [GC](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science))-like behavior that allows different objects of the same `proxy` type to have different lifetime models without requiring runtime GC overhead.
"Proxy" is a header-only, cross-platform C++20 template library for modern runtime polymorphism based on pointer-semantics. Similar with C++ [virtual functions](https://en.cppreference.com/w/cpp/language/virtual), it generates indirect functions behind the scenes at compile-time but does not require inheritance. It also has [GC](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science))-like behavior that allows different objects of the same `proxy` type to have different lifetime models without requiring runtime GC overhead.

### <a name="why-popular">Why is "Proxy" so popular?</a>

Expand All @@ -35,7 +35,7 @@ The fundamental abstraction of "Proxy" is called "facade". It is recommended for

### <a name="how-integrate">How to integrate "Proxy" into my project?</a>

Since "Proxy" is a single-header library, you can simply navigate to the [latest release](https://github.com/microsoft/proxy/releases), download the source code, and include "proxy.h" in your project. Make sure your compiler version meets the [minimum requirements for compilers](../README.md#compiler-req). If your project has already integrated with [vcpkg](https://vcpkg.io/) or [conan](https://conan.io/), just search for the keyword "proxy" and install it. Thanks to the community that helped port "Proxy" to these platforms!
Since "Proxy" is a header-only library, you can simply navigate to the [latest release](https://github.com/microsoft/proxy/releases), download the source code, and include "proxy.h" in your project. Make sure your compiler version meets the [minimum requirements for compilers](../README.md#compiler-req). If your project has already integrated with [vcpkg](https://vcpkg.io/) or [conan](https://conan.io/), just search for the keyword "proxy" and install it. Thanks to the community that helped port "Proxy" to these platforms!

### <a name="how-migrate">My existing project uses virtual functions. How should I migrate to "Proxy"?</a>

Expand Down
1 change: 0 additions & 1 deletion proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -2545,7 +2545,6 @@ struct formatter<pro::proxy_indirect_accessor<F>, CharT> {
} // namespace std
#endif // __STDC_HOSTED__ && __has_include(<format>)

#undef ___PRO_THROW
#undef ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE

#endif // _MSFT_PROXY_
102 changes: 102 additions & 0 deletions proxy_fmt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#ifndef _MSFT_PROXY_FMT_
#define _MSFT_PROXY_FMT_

#include <string_view>
#include <type_traits>

#ifndef __msft_lib_proxy
#error Please ensure that proxy.h is included before proxy_fmt.h.
#endif // __msft_lib_proxy

#if FMT_VERSION >= 60100
static_assert(fmt::is_char<wchar_t>::value,
"The {fmt} library must have wchar_t support enabled. "
"Include fmt/xchar.h before including proxy_fmt.h.");
#else
#error Please ensure that the appropriate {fmt} headers (version 6.1.0 or \
later) are included before proxy_fmt.h.
#endif // FMT_VERSION >= 60100

namespace pro {

namespace details {

template <class CharT> struct fmt_format_overload_traits;
template <>
struct fmt_format_overload_traits<char>
: std::type_identity<fmt::format_context::iterator(
std::string_view spec, fmt::format_context& fc) const> {};
template <>
struct fmt_format_overload_traits<wchar_t>
: std::type_identity<fmt::wformat_context::iterator(
std::wstring_view spec, fmt::wformat_context& fc) const> {};
template <class CharT>
using fmt_format_overload_t = typename fmt_format_overload_traits<CharT>::type;

struct fmt_format_dispatch {
template <class T, class CharT, class FormatContext>
___PRO_STATIC_CALL(auto, const T& self, std::basic_string_view<CharT> spec,
FormatContext& fc)
requires(std::is_default_constructible_v<fmt::formatter<T, CharT>>) {
fmt::formatter<T, CharT> impl;
{
fmt::basic_format_parse_context<CharT> pc{spec};
impl.parse(pc);
}
return impl.format(self, fc);
}
};

} // namespace details

namespace skills {

template <class FB>
using fmt_format = typename FB::template add_convention<
details::fmt_format_dispatch, details::fmt_format_overload_t<char>>;

template <class FB>
using fmt_wformat = typename FB::template add_convention<
details::fmt_format_dispatch, details::fmt_format_overload_t<wchar_t>>;

} // namespace skills

} // namespace pro

namespace fmt {

template <pro::facade F, class CharT>
requires(pro::details::facade_traits<F>::template is_invocable<
false, pro::details::fmt_format_dispatch,
pro::details::fmt_format_overload_t<CharT>>)
struct formatter<pro::proxy_indirect_accessor<F>, CharT> {
constexpr auto parse(basic_format_parse_context<CharT>& pc) {
for (auto it = pc.begin(); it != pc.end(); ++it) {
if (*it == '}') {
spec_ = std::basic_string_view<CharT>{pc.begin(), it + 1};
return it;
}
}
return pc.end();
}

template <class FormatContext>
auto format(const pro::proxy_indirect_accessor<F>& ia, FormatContext& fc)
const -> typename FormatContext::iterator {
auto& p = pro::access_proxy<F>(ia);
if (!p.has_value()) [[unlikely]]
{ ___PRO_THROW(format_error{"null proxy"}); }
return pro::proxy_invoke<false, pro::details::fmt_format_dispatch,
pro::details::fmt_format_overload_t<CharT>>(p, spec_, fc);
}

private:
std::basic_string_view<CharT> spec_;
};

} // namespace fmt

#endif // _MSFT_PROXY_FMT_
10 changes: 9 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,17 @@ set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) # Disable GMock
FetchContent_MakeAvailable(googletest)
include(GoogleTest)

FetchContent_Declare(
fmt
URL https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz
URL_HASH SHA256=ac366b7b4c2e9f0dde63a59b3feb5ee59b67974b14ee5dc9ea8ad78aa2c1ee1e
)
FetchContent_MakeAvailable(fmt)

add_executable(msft_proxy_tests
proxy_creation_tests.cpp
proxy_dispatch_tests.cpp
proxy_fmt_format_tests.cpp
proxy_format_tests.cpp
proxy_integration_tests.cpp
proxy_invocation_tests.cpp
Expand All @@ -31,7 +39,7 @@ add_executable(msft_proxy_tests
proxy_view_tests.cpp
)
target_include_directories(msft_proxy_tests PRIVATE .)
target_link_libraries(msft_proxy_tests PRIVATE msft_proxy gtest_main)
target_link_libraries(msft_proxy_tests PRIVATE msft_proxy gtest_main fmt::fmt)

if(MSVC)
target_compile_options(msft_proxy_tests PRIVATE /W4 /WX)
Expand Down
75 changes: 75 additions & 0 deletions tests/proxy_fmt_format_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include <gtest/gtest.h>

#if defined(__NVCOMPILER)
#pragma diagnostic push
#pragma diag_suppress inline_gnu_noinline_conflict
#pragma diagnostic push
#pragma diag_suppress code_is_unreachable
#endif // defined(__NVCOMPILER)
#include <fmt/format.h>
#include <fmt/xchar.h>
#if defined(__NVCOMPILER)
#pragma diagnostic pop
#pragma diagnostic pop
#endif // defined(__NVCOMPILER)

#include "proxy.h"
#include "proxy_fmt.h"

namespace proxy_fmt_format_tests_details {

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

static_assert(!std::is_default_constructible_v<fmt::formatter<pro::proxy_indirect_accessor<NonFormattable>, char>>);
static_assert(!std::is_default_constructible_v<fmt::formatter<pro::proxy_indirect_accessor<NonFormattable>, wchar_t>>);

struct Formattable : pro::facade_builder
::support<pro::skills::fmt_format>
::support<pro::skills::fmt_wformat>
::build {};

static_assert(std::is_default_constructible_v<fmt::formatter<pro::proxy_indirect_accessor<Formattable>, char>>);
static_assert(std::is_default_constructible_v<fmt::formatter<pro::proxy_indirect_accessor<Formattable>, wchar_t>>);

} // namespace proxy_fmt_format_tests_details

namespace details = proxy_fmt_format_tests_details;

TEST(ProxyFmtFormatTests, TestFormat_Null) {
pro::proxy<details::Formattable> p;
bool exception_thrown = false;
try {
std::ignore = fmt::format("{}", *p);
} catch (const fmt::format_error&) {
exception_thrown = true;
}
ASSERT_TRUE(exception_thrown);
}

TEST(ProxyFmtFormatTests, TestFormat_Value) {
int v = 123;
pro::proxy<details::Formattable> p = &v;
ASSERT_EQ(fmt::format("{}", *p), "123");
ASSERT_EQ(fmt::format("{:*<6}", *p), "123***");
}

TEST(ProxyFmtFormatTests, TestWformat_Null) {
pro::proxy<details::Formattable> p;
bool exception_thrown = false;
try {
std::ignore = fmt::format(L"{}", *p);
} catch (const fmt::format_error&) {
exception_thrown = true;
}
ASSERT_TRUE(exception_thrown);
}

TEST(ProxyFmtFormatTests, TestWformat_Value) {
int v = 123;
pro::proxy<details::Formattable> p = &v;
ASSERT_EQ(fmt::format(L"{}", *p), L"123");
ASSERT_EQ(fmt::format(L"{:*<6}", *p), L"123***");
}