From 60a92a87c9fc6c0f2e8e3b545a48351c63a131a4 Mon Sep 17 00:00:00 2001 From: i80287 Date: Tue, 2 Jul 2024 01:16:41 +0300 Subject: [PATCH 1/9] add #include for the assert() macro --- include/field_reflection.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/field_reflection.hpp b/include/field_reflection.hpp index da7ad1c..b25ea68 100644 --- a/include/field_reflection.hpp +++ b/include/field_reflection.hpp @@ -10,6 +10,7 @@ #pragma once +#include #include // CHAR_BIT #include #include @@ -582,7 +583,7 @@ namespace field_reflection static wrapper fake; // NOLINT }; - template // NOLINT + template // NOLINT consteval auto get_ptr() noexcept { #if defined(__clang__) From 523ba495e440d011c755afbf16db11311fd0e90a Mon Sep 17 00:00:00 2001 From: Yoshiki Matsuda Date: Tue, 2 Jul 2024 13:30:35 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=8E=A8=20Refactor=20concept?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/field_reflection.hpp | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/include/field_reflection.hpp b/include/field_reflection.hpp index b25ea68..b260c06 100644 --- a/include/field_reflection.hpp +++ b/include/field_reflection.hpp @@ -89,24 +89,17 @@ namespace field_reflection #endif template - concept constructible = []() { - if constexpr (ArgNum == 0) - { - return requires { T{}; }; - } - else if constexpr (std::is_copy_constructible_v) - { - return [](std::index_sequence) { - return requires { T{std::declval>(), std::declval>()...}; }; - }(std::make_index_sequence()); - } - else - { - return [](std::index_sequence) { - return requires { T{std::declval>(), std::declval>()...}; }; - }(std::make_index_sequence()); - } - }(); + concept constructible = (ArgNum == 0 && requires { T{}; }) || + [](std::index_sequence) { + if constexpr (std::is_copy_constructible_v) + { + return requires { T{any_lref_no_base(), any_lref()...}; }; + } + else + { + return requires { T{any_rref_no_base(), any_rref()...}; }; + } + }(std::make_index_sequence()); template concept has_base = []() { From 164a708f2d9b7bc3ccddbab7be79be48a48644dc Mon Sep 17 00:00:00 2001 From: Yoshiki Matsuda Date: Tue, 2 Jul 2024 13:41:57 +0900 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=94=A7=20Add=20LLVM18=20to=20GitHub?= =?UTF-8?q?=20actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/tests.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 06b5b68..4c80799 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,11 +18,7 @@ jobs: strategy: fail-fast: false matrix: - compiler: - [ - { c: "clang-cl", cxx: "clang-cl" }, - { c: "cl", cxx: "cl" }, - ] + compiler: [{ c: "clang-cl", cxx: "clang-cl" }, { c: "cl", cxx: "cl" }] name: Windows - ${{ matrix.compiler.cxx }} runs-on: windows-latest @@ -58,7 +54,6 @@ jobs: [ { c: "gcc-11", cxx: "g++-11" }, { c: "gcc-12", cxx: "g++-12" }, - { c: "gcc-13", cxx: "g++-13" }, { c: "$(brew --prefix llvm@15)/bin/clang", cxx: "$(brew --prefix llvm@15)/bin/clang++", @@ -71,6 +66,10 @@ jobs: c: "$(brew --prefix llvm@17)/bin/clang", cxx: "$(brew --prefix llvm@17)/bin/clang++", }, + { + c: "$(brew --prefix llvm@18)/bin/clang", + cxx: "$(brew --prefix llvm@18)/bin/clang++", + }, ] name: Ubuntu - ${{ matrix.compiler.cxx }} runs-on: ubuntu-latest @@ -86,10 +85,10 @@ jobs: - name: Install compilers run: | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - brew install ninja llvm@12 llvm@13 llvm@14 llvm@15 llvm@16 llvm@17 + brew install ninja llvm@15 llvm@16 llvm@17 llvm@18 - name: Install dependencies - run: CC=${{ matrix.compiler.c }} CXX=${{ matrix.compiler.cxx }} vcpkg install gtest --triplet ${{ env.triplet }} + run: vcpkg install gtest --triplet ${{ env.triplet }} - name: Build and test run: | @@ -118,12 +117,16 @@ jobs: c: "$(brew --prefix llvm@17)/bin/clang", cxx: "$(brew --prefix llvm@17)/bin/clang++", }, + { + c: "$(brew --prefix llvm@18)/bin/clang", + cxx: "$(brew --prefix llvm@18)/bin/clang++", + }, ] name: MacOS - ${{ matrix.compiler.cxx }} runs-on: macos-latest env: - triplet: x64-osx + triplet: arm64-osx steps: - uses: actions/checkout@v4 @@ -131,7 +134,7 @@ jobs: submodules: true - name: Install compilers - run: brew install ninja llvm@12 llvm@13 llvm@14 llvm@15 llvm@16 llvm@17 + run: brew install ninja llvm@16 llvm@17 llvm@18 - name: Install dependencies run: CC=${{ matrix.compiler.c }} CXX=${{ matrix.compiler.cxx }} vcpkg install gtest --triplet ${{ env.triplet }} From 719c66b6251af9fe2f2a8f450d50f7e5e24bac0b Mon Sep 17 00:00:00 2001 From: Yoshiki Matsuda Date: Tue, 2 Jul 2024 14:04:25 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=94=A7=20Add=20GCC14=20to=20GitHub=20?= =?UTF-8?q?actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/tests.yml | 51 +++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4c80799..1c769e2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,14 +46,52 @@ jobs: ctest --test-dir "${{ github.workspace }}\build" -C Release shell: bash - ubuntu-build: + ubuntu2204-build: strategy: fail-fast: false matrix: compiler: [ { c: "gcc-11", cxx: "g++-11" }, + ] + name: Ubuntu - ${{ matrix.compiler.cxx }} + runs-on: ubuntu-22.04 + + env: + triplet: x64-linux + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install compilers + run: | + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + brew install ninja + + - name: Install dependencies + run: vcpkg install gtest --triplet ${{ env.triplet }} + + - name: Build and test + run: | + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + rm -rf ${{ github.workspace }}/build + cmake -B ${{ github.workspace }}/build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=${{ env.triplet }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -G "Ninja Multi-Config" + cmake --build ${{ github.workspace }}/build --config Debug --clean-first + ctest --test-dir ${{ github.workspace }}/build -C Debug + cmake --build ${{ github.workspace }}/build --config Release --clean-first + ctest --test-dir ${{ github.workspace }}/build -C Release + + ubuntu2404-build: + strategy: + fail-fast: false + matrix: + compiler: + [ { c: "gcc-12", cxx: "g++-12" }, + { c: "gcc-13", cxx: "g++-13" }, + { c: "gcc-14", cxx: "g++-14" }, { c: "$(brew --prefix llvm@15)/bin/clang", cxx: "$(brew --prefix llvm@15)/bin/clang++", @@ -72,7 +110,7 @@ jobs: }, ] name: Ubuntu - ${{ matrix.compiler.cxx }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 env: triplet: x64-linux @@ -108,7 +146,7 @@ jobs: [ { c: "gcc-11", cxx: "g++-11" }, { c: "gcc-12", cxx: "g++-12" }, - { c: "gcc-13", cxx: "g++-13" }, + # { c: "gcc-13", cxx: "g++-13" }, { c: "$(brew --prefix llvm@16)/bin/clang", cxx: "$(brew --prefix llvm@16)/bin/clang++", @@ -137,12 +175,15 @@ jobs: run: brew install ninja llvm@16 llvm@17 llvm@18 - name: Install dependencies - run: CC=${{ matrix.compiler.c }} CXX=${{ matrix.compiler.cxx }} vcpkg install gtest --triplet ${{ env.triplet }} + run: | + git clone --depth=1 https://github.com/microsoft/vcpkg.git + ./vcpkg/bootstrap-vcpkg.sh + CC=${{ matrix.compiler.c }} CXX=${{ matrix.compiler.cxx }} ./vcpkg/vcpkg install gtest --triplet ${{ env.triplet }} - name: Build and test run: | rm -rf ${{ github.workspace }}/build - cmake -B ${{ github.workspace }}/build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=${{ env.triplet }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -G "Ninja Multi-Config" + cmake -B ${{ github.workspace }}/build -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=${{ env.triplet }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -G "Ninja Multi-Config" cmake --build ${{ github.workspace }}/build --config Debug --clean-first ctest --test-dir ${{ github.workspace }}/build -C Debug cmake --build ${{ github.workspace }}/build --config Release --clean-first From a9a401e7b9c30550793fcca6ed6d37c80f634da7 Mon Sep 17 00:00:00 2001 From: Yoshiki Matsuda Date: Tue, 2 Jul 2024 17:22:45 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=94=96=20Release=20v0.2.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5a135c..61d652f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16) project( field_reflection - VERSION 0.0.1 + VERSION 0.2.1 LANGUAGES CXX) # check if the project is top-level From 7b710fdb4f87ab3e42b978a57fce4a745de95cc3 Mon Sep 17 00:00:00 2001 From: Yoshiki Matsuda Date: Sun, 15 Dec 2024 21:16:22 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=92=9A=20Add=20LLVM=2019=20to=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/tests.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1c769e2..714ea58 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -108,6 +108,10 @@ jobs: c: "$(brew --prefix llvm@18)/bin/clang", cxx: "$(brew --prefix llvm@18)/bin/clang++", }, + { + c: "$(brew --prefix llvm@19)/bin/clang", + cxx: "$(brew --prefix llvm@19)/bin/clang++", + }, ] name: Ubuntu - ${{ matrix.compiler.cxx }} runs-on: ubuntu-24.04 @@ -123,7 +127,7 @@ jobs: - name: Install compilers run: | eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - brew install ninja llvm@15 llvm@16 llvm@17 llvm@18 + brew install ninja llvm@15 llvm@16 llvm@17 llvm@18 llvm@19 - name: Install dependencies run: vcpkg install gtest --triplet ${{ env.triplet }} @@ -144,9 +148,9 @@ jobs: matrix: compiler: [ - { c: "gcc-11", cxx: "g++-11" }, { c: "gcc-12", cxx: "g++-12" }, - # { c: "gcc-13", cxx: "g++-13" }, + { c: "gcc-13", cxx: "g++-13" }, + { c: "gcc-14", cxx: "g++-14" }, { c: "$(brew --prefix llvm@16)/bin/clang", cxx: "$(brew --prefix llvm@16)/bin/clang++", @@ -159,6 +163,10 @@ jobs: c: "$(brew --prefix llvm@18)/bin/clang", cxx: "$(brew --prefix llvm@18)/bin/clang++", }, + { + c: "$(brew --prefix llvm@19)/bin/clang", + cxx: "$(brew --prefix llvm@19)/bin/clang++", + }, ] name: MacOS - ${{ matrix.compiler.cxx }} runs-on: macos-latest @@ -172,7 +180,7 @@ jobs: submodules: true - name: Install compilers - run: brew install ninja llvm@16 llvm@17 llvm@18 + run: brew install ninja llvm@16 llvm@17 llvm@18 llvm@19 - name: Install dependencies run: | From a38d55e38c0c338887bb31d85a2183e4a88a4018 Mon Sep 17 00:00:00 2001 From: acd1034 <48613285+acd1034@users.noreply.github.com> Date: Fri, 13 Dec 2024 19:35:13 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=E2=9C=A8=20Add=20`type=5Fname`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/field_reflection.hpp | 52 ++++++++++++++++++++++++++++++++++++ test/test.cpp | 7 +++++ 2 files changed, 59 insertions(+) diff --git a/include/field_reflection.hpp b/include/field_reflection.hpp index b260c06..6a20de3 100644 --- a/include/field_reflection.hpp +++ b/include/field_reflection.hpp @@ -612,6 +612,17 @@ namespace field_reflection #endif } + template + consteval std::string_view get_function_name() + { +#if defined(__clang__) && defined(_WIN32) + // clang-cl returns function_name() as __FUNCTION__ instead of __PRETTY_FUNCTION__ + return std::string_view{__PRETTY_FUNCTION__}; +#else + return std::string_view{std::source_location::current().function_name()}; +#endif + } + template consteval std::string_view get_field_name() { @@ -646,6 +657,46 @@ namespace field_reflection template using field_type = remove_rvalue_reference_t(to_tuple(std::declval())))>; + struct type_name_detector + { + }; + + template + consteval std::string_view get_type_name() + { +#if defined(__GNUC__) || defined(__clang__) + constexpr auto detector_name = get_function_name(); + constexpr auto dummy = std::string_view("T = "); + constexpr auto dummy_begin = detector_name.find(dummy) + dummy.size(); + constexpr auto dummy2 = std::string_view("type_name_detector"); + constexpr auto dummy_suffix_length = detector_name.size() - detector_name.find(dummy2) - dummy2.size(); + + constexpr auto type_name_raw = get_function_name(); + return type_name_raw.substr(dummy_begin, type_name_raw.size() - dummy_begin - dummy_suffix_length); +#else + constexpr auto detector_name = get_function_name(); + constexpr auto dummy = std::string_view("struct field_reflection::detail::type_name_detector"); + constexpr auto dummy_begin = detector_name.find(dummy); + constexpr auto dummy_suffix_length = detector_name.size() - dummy_begin - dummy.size(); + + auto type_name_raw = get_function_name(); + auto type_name = + type_name_raw.substr(dummy_begin, type_name_raw.size() - dummy_begin - dummy_suffix_length); + if (auto s = std::string_view("struct "); type_name.starts_with(s)) + { + type_name.remove_prefix(s.size()); + } + if (auto s = std::string_view("class "); type_name.starts_with(s)) + { + type_name.remove_prefix(s.size()); + } + return type_name; +#endif + } + + template + constexpr std::string_view type_name = get_type_name(); + template > constexpr decltype(auto) get_field(T& t) noexcept { @@ -773,6 +824,7 @@ namespace field_reflection using detail::field_type; using detail::get_field; using detail::to_tuple; + using detail::type_name; template , field_referenceable U2 = std::remove_cvref_t> diff --git a/test/test.cpp b/test/test.cpp index e51597b..546c9fa 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -196,6 +196,13 @@ TEST(field_reflection, field_name) static_assert(field_name == "y1"); } +TEST(field_reflection, type_name) +{ + static_assert(type_name == "my_struct1"); + static_assert(type_name == "named::my_struct10"); + static_assert(type_name> == "std::pair"); +} + TEST(field_reflection, get_field) { { From 88f351d07b3b6d2ee3c45f4c1775ec59d53590f1 Mon Sep 17 00:00:00 2001 From: acd1034 <48613285+acd1034@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:47:47 +0900 Subject: [PATCH 8/9] =?UTF-8?q?=E2=9C=85=20Fix=20test=20for=20MSVC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test.cpp b/test/test.cpp index 546c9fa..8916e4e 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -200,7 +200,11 @@ TEST(field_reflection, type_name) { static_assert(type_name == "my_struct1"); static_assert(type_name == "named::my_struct10"); +#if defined(__GNUC__) || defined(__clang__) static_assert(type_name> == "std::pair"); +#else + static_assert(type_name> == "std::pair"); +#endif } TEST(field_reflection, get_field) From 3eeb345632e0257d5b5c25a5ca092b56e94046da Mon Sep 17 00:00:00 2001 From: acd1034 <48613285+acd1034@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:49:25 +0900 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=93=9D=20Add=20description=20for=20`t?= =?UTF-8?q?ype=5Fname`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/README.md b/README.md index e73f94a..92fe35f 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,88 @@ constexpr auto get_field(T&& t) noexcept; Extracts the `N`-th element from the `field_referenceable` type `T` and returns a reference to it. It behaves like `std::get` for `std::tuple` but returns a lvalue value instead of a rvalue reference. +### `type_name` + +```cpp +template +constexpr std::string_view type_name; +``` + +Get the name of the type `T`. + +
+Example + +```cpp +#include +#include +#include +#include // std::exchange +#include + +using Token = std::variant; + +struct Number { + int value; +}; + +struct Identifier { + std::string name; +}; + +template +inline constexpr bool alternative_of = false; + +template +inline constexpr bool alternative_of> = + (std::is_same_v || ...); + +template + requires alternative_of +struct std::formatter { + constexpr auto parse(auto& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + if (it != ctx.end() and *it != '}') { + throw std::format_error("invalid format"); + } + return it; + } + + auto format(const T& t, auto& ctx) const -> decltype(ctx.out()) { + auto out = ctx.out(); + out = std::format_to(out, "{} {{", field_reflection::type_name); + const char* dlm = ""; + field_reflection::for_each_field( + t, [&](std::string_view name, const auto& value) { + std::format_to( + out, "{}\n .{}={}", std::exchange(dlm, ","), name, value); + }); + out = std::format_to(out, "\n}}"); + return out; + } +}; + +#include + +int main() { + Number num{42}; + Identifier ident{"ident"}; + std::cout << std::format("{}", num) << std::endl; + std::cout << std::format("{}", ident) << std::endl; + // Expected Output + // =============== + // Number { + // .value=42 + // } + // Identifier { + // .name=ident + // } +} +``` + +🔗[Execution example in Compiler Explorer](https://godbolt.org/z/94fPc895o) +
+ ### `for_each_field`, `all_of_field`, `any_of_field` ```cpp