mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-19 04:22:13 +00:00
Parser might be explicitly tagged as backward
This commit is contained in:
committed by
Antony Polukhin
parent
48b9be5070
commit
2876b2e793
@@ -122,13 +122,13 @@
|
||||
#ifndef BOOST_PFR_CORE_NAME_PARSING
|
||||
# if defined(_MSC_VER)
|
||||
// sizeof("auto __cdecl boost::pfr::detail::name_of_field_impl<") - 1, sizeof(">(void) noexcept") - 1
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (52, 16, "->")
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (52, 16, backward("->"))
|
||||
# elif defined(__clang__)
|
||||
// sizeof("auto boost::pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (64, 2, ".")
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (64, 2, backward("."))
|
||||
# elif defined(__GNUC__)
|
||||
// sizeof("consteval auto boost::pfr::detail::name_of_field_impl() [with MsvcWorkaround = ") - 1, sizeof(")]") - 1
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (79, 2, "::")
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (79, 2, backward("::"))
|
||||
# else
|
||||
// Deafult parser for other platforms... Just skip nothing!
|
||||
# define BOOST_PFR_CORE_NAME_PARSING (0, 0, "")
|
||||
|
||||
@@ -29,31 +29,64 @@ struct core_name_skip {
|
||||
std::size_t size_at_begin;
|
||||
std::size_t size_at_end;
|
||||
bool more_at_runtime;
|
||||
std::string_view until_runtime_last;
|
||||
bool is_backward;
|
||||
std::string_view until_runtime;
|
||||
|
||||
consteval std::string_view fail() const noexcept {
|
||||
return "";
|
||||
}
|
||||
|
||||
consteval std::string_view apply(std::string_view sv) const noexcept {
|
||||
sv.remove_prefix((std::min)(size_at_begin, sv.size()));
|
||||
sv.remove_suffix((std::min)(size_at_end, sv.size()));
|
||||
if (!more_at_runtime) {
|
||||
if (!until_runtime.empty())
|
||||
return fail(); ///< useless skip condition
|
||||
return sv;
|
||||
}
|
||||
else {
|
||||
// so, we're asked to skip more
|
||||
if (until_runtime.empty())
|
||||
return fail(); ///< condition to skip more wasn't specified
|
||||
const auto found = is_backward ? sv.rfind(until_runtime)
|
||||
: sv.find(until_runtime);
|
||||
;
|
||||
const auto cut_until = found + until_runtime.size();
|
||||
const auto safe_cut_until = (std::min)(cut_until, sv.size());
|
||||
return sv.substr(safe_cut_until);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct backward {
|
||||
explicit consteval backward(std::string_view value) noexcept
|
||||
: value(value)
|
||||
{}
|
||||
|
||||
std::string_view value;
|
||||
};
|
||||
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
bool more_at_runtime,
|
||||
std::string_view until_runtime_last) noexcept
|
||||
std::string_view until_runtime) noexcept
|
||||
{
|
||||
return core_name_skip{size_at_begin, size_at_end, more_at_runtime, until_runtime_last};
|
||||
return core_name_skip{size_at_begin, size_at_end, more_at_runtime, false, until_runtime};
|
||||
}
|
||||
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
std::string_view until_runtime_last) noexcept
|
||||
bool more_at_runtime,
|
||||
backward until_runtime) noexcept
|
||||
{
|
||||
return core_name_skip{size_at_begin, size_at_end, true, until_runtime_last};
|
||||
return core_name_skip{size_at_begin, size_at_end, more_at_runtime, true, until_runtime.value};
|
||||
}
|
||||
|
||||
consteval std::string_view apply_core_name_skip(std::string_view sv,
|
||||
core_name_skip s) noexcept {
|
||||
sv.remove_prefix((std::min)(s.size_at_begin, sv.size()));
|
||||
sv.remove_suffix((std::min)(s.size_at_end, sv.size()));
|
||||
return s.more_at_runtime ? sv.substr((std::min)(sv.rfind(s.until_runtime_last) + s.until_runtime_last.size(), sv.size()))
|
||||
: sv;
|
||||
;
|
||||
consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
|
||||
std::size_t size_at_end,
|
||||
auto until_runtime) noexcept
|
||||
{
|
||||
return detail::make_core_name_skip(size_at_begin, size_at_end, true, until_runtime);
|
||||
}
|
||||
|
||||
template <bool Condition>
|
||||
@@ -85,7 +118,14 @@ consteval auto name_of_field_impl() noexcept {
|
||||
return detail::make_stdarray<char>(0);
|
||||
} else {
|
||||
constexpr auto skip = detail::make_core_name_skip BOOST_PFR_CORE_NAME_PARSING;
|
||||
constexpr auto fn = detail::apply_core_name_skip(sv, skip);
|
||||
static_assert(
|
||||
skip.more_at_runtime || skip.until_runtime.empty(),
|
||||
"====================> Boost.PFR: Parser configured in a wrong way. "
|
||||
"It wasn't requested to skip more, but such skip condition was specified in vain. "
|
||||
"Please read your definition of BOOST_PFR_CORE_NAME_PARSING macro patiently "
|
||||
"and fix it."
|
||||
);
|
||||
constexpr auto fn = skip.apply(sv);
|
||||
auto res = std::array<char, fn.size()+1>{};
|
||||
detail::assert_compile_time_legths<!fn.empty()>();
|
||||
std::ranges::copy(fn, res.begin());
|
||||
|
||||
@@ -62,6 +62,8 @@ test-suite pfr_name_tests
|
||||
[ run fields_names_constexpr.cpp : : : : ]
|
||||
[ run fields_names_nonascii.cpp : : : <toolset>msvc:<cxxflags>"/utf-8" : ]
|
||||
[ run fields_names_big.cpp : : : <toolset>msvc:<cxxflags>"/bigobj" : ]
|
||||
[ run fields_names_correctly_configured_compiler.cpp : : : : ]
|
||||
[ run fields_names_internal_parser.cpp : : : : ]
|
||||
[ run print_name.cpp : : : <test-info>always_show_run_output ]
|
||||
;
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#define BOOST_PFR_FUNCTION_SIGNATURE "dummy"
|
||||
#define BOOST_PFR_CORE_NAME_PARSING (3,2,false,"")
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::get_name<0, A>(); // Must be a compile time error
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#define BOOST_PFR_FUNCTION_SIGNATURE " *[field] "
|
||||
#define BOOST_PFR_CORE_NAME_PARSING (3,2,false,"")
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct A { int field; };
|
||||
|
||||
int main() {
|
||||
BOOST_TEST_EQ( ((boost::pfr::get_name<0,A>())), "field");
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
58
test/core_name/fields_names_internal_parser.cpp
Normal file
58
test/core_name/fields_names_internal_parser.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
// Initial implementation by Bela Schaum, https://github.com/schaumb
|
||||
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
|
||||
//
|
||||
|
||||
#include <boost/pfr/core_name.hpp>
|
||||
#include <string_view>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
namespace testing
|
||||
{
|
||||
|
||||
constexpr std::string_view fake_func_name = " ******************** [fake_text1->fake_text2->fake_text3] **********";
|
||||
|
||||
void test_general()
|
||||
{
|
||||
namespace detail = boost::pfr::detail;
|
||||
using detail::backward;
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, false, "").apply(fake_func_name), "fake_text1->fake_text2->fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, backward("->")).apply(fake_func_name), "fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, "->").apply(fake_func_name), "fake_text2->fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, true, backward("->")).apply(fake_func_name), "fake_text3");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(23, 12, true, "->").apply(fake_func_name), "fake_text2->fake_text3");
|
||||
}
|
||||
|
||||
void test_undefided_parser()
|
||||
{
|
||||
namespace detail = boost::pfr::detail;
|
||||
using detail::backward;
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, backward("")).apply(fake_func_name), "");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, "").apply(fake_func_name), "");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, true, backward("")).apply(fake_func_name), "");
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, true, "").apply(fake_func_name), "");
|
||||
}
|
||||
|
||||
void test_identity_parser()
|
||||
{
|
||||
namespace detail = boost::pfr::detail;
|
||||
using detail::backward;
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, false, backward("")).apply(fake_func_name), fake_func_name);
|
||||
BOOST_TEST_EQ(detail::make_core_name_skip(0, 0, false, "").apply(fake_func_name), fake_func_name);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
testing::test_general();
|
||||
testing::test_undefided_parser();
|
||||
testing::test_identity_parser();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user