Skip to content

Commit ce64e1f

Browse files
committed
Allow retrieving of integral format parameters by value
1 parent 1c4b6a4 commit ce64e1f

File tree

2 files changed

+85
-5
lines changed

2 files changed

+85
-5
lines changed

fly/types/string/detail/string_formatter_types.hpp

+49-4
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ class BasicFormatString
519519
template <typename StringType, typename... ParameterTypes>
520520
class BasicFormatParameters
521521
{
522+
using FormatParameters = std::tuple<std::type_identity_t<ParameterTypes>...>;
522523
using FormatSpecifier = BasicFormatSpecifier<typename StringType::value_type>;
523524

524525
public:
@@ -534,17 +535,38 @@ class BasicFormatParameters
534535
* position. If the provided position is found, invokes the provided callback with the
535536
* replacement field and a reference to the found format parameter.
536537
*
538+
* @tparam Callback Type of the callback to invoke.
539+
*
537540
* @param specifier The replacement field corresponding to the parameter to search for.
538541
* @param callback The callback to invoke if the parameter is found.
539542
*/
540543
template <typename Callback, size_t N = 0>
541544
void visit(FormatSpecifier &&specifier, Callback callback) const;
542545

546+
/**
547+
* Visitor to provide runtime access to the stored parameter at the provided index. If the index
548+
* is found, and is convertible to the desired type, returns a copy of the found format
549+
* parameter.
550+
*
551+
* This is only allowed for integral format parameters. Attempting to copy other format types is
552+
* forbidden.
553+
*
554+
* @tparam T Desired type of the format parameter.
555+
*
556+
* @param index The index of the parameter to search for.
557+
*
558+
* @return If successful, a copy of the format parameter. Otherwise, an uninitialized value.
559+
*/
560+
template <typename T, size_t N = 0>
561+
std::optional<T> get(std::size_t index) const;
562+
543563
private:
544564
BasicFormatParameters(const BasicFormatParameters &) = delete;
545565
BasicFormatParameters &operator=(const BasicFormatParameters &) = delete;
546566

547-
const std::tuple<ParameterTypes...> m_parameters;
567+
const FormatParameters m_parameters;
568+
569+
static constexpr const std::size_t s_parameter_count = sizeof...(ParameterTypes);
548570
};
549571

550572
//==================================================================================================
@@ -1167,9 +1189,7 @@ void BasicFormatParameters<StringType, ParameterTypes...>::visit(
11671189
FormatSpecifier &&specifier,
11681190
Callback callback) const
11691191
{
1170-
static constexpr const std::size_t s_tuple_size = std::tuple_size_v<decltype(m_parameters)>;
1171-
1172-
if constexpr (N < s_tuple_size)
1192+
if constexpr (N < s_parameter_count)
11731193
{
11741194
if (N == specifier.m_position)
11751195
{
@@ -1181,4 +1201,29 @@ void BasicFormatParameters<StringType, ParameterTypes...>::visit(
11811201
}
11821202
}
11831203

1204+
//==================================================================================================
1205+
template <typename StringType, typename... ParameterTypes>
1206+
template <typename T, size_t N>
1207+
std::optional<T> BasicFormatParameters<StringType, ParameterTypes...>::get(std::size_t index) const
1208+
{
1209+
if constexpr (N < s_parameter_count)
1210+
{
1211+
if (N == index)
1212+
{
1213+
using P = std::remove_cvref_t<std::tuple_element_t<N, FormatParameters>>;
1214+
1215+
if constexpr (std::is_integral_v<P> && std::is_convertible_v<P, T>)
1216+
{
1217+
return static_cast<T>(std::get<N>(m_parameters));
1218+
}
1219+
}
1220+
1221+
return get<T, N + 1>(index);
1222+
}
1223+
else
1224+
{
1225+
return std::nullopt;
1226+
}
1227+
}
1228+
11841229
} // namespace fly::detail

test/types/string/string_formatter_types.cpp

+36-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55

66
#include "fly/types/string/detail/string_formatter_types.hpp"
77

8+
#include "fly/types/numeric/literals.hpp"
89
#include "fly/types/string/string_literal.hpp"
910

1011
#include "catch2/catch.hpp"
1112

1213
#include <ostream>
1314
#include <string>
1415

16+
using namespace fly::literals::numeric_literals;
17+
1518
namespace {
1619

1720
#define FMT(format) FLY_ARR(char_type, format)
@@ -1138,7 +1141,39 @@ CATCH_TEMPLATE_TEST_CASE(
11381141
CATCH_CHECK(visit_count == 1);
11391142
}
11401143

1141-
CATCH_SECTION("Stored parameters are never copied or moved")
1144+
CATCH_SECTION("Parameters can be copied if of a compatible type")
1145+
{
1146+
fly::detail::BasicFormatParameters<StringType, int> parameters(1);
1147+
1148+
auto value1 = parameters.template get<int>(0);
1149+
CATCH_REQUIRE(value1);
1150+
CATCH_CHECK(value1 == 1);
1151+
1152+
auto value2 = parameters.template get<std::size_t>(0);
1153+
CATCH_REQUIRE(value2);
1154+
CATCH_CHECK(value2 == 1_zu);
1155+
1156+
auto value3 = parameters.template get<std::size_t>(1);
1157+
CATCH_CHECK_FALSE(value3);
1158+
}
1159+
1160+
CATCH_SECTION("Parameters cannot be copied if of a non-integral type")
1161+
{
1162+
fly::detail::BasicFormatParameters<StringType, std::string> parameters("ab");
1163+
1164+
auto value = parameters.template get<std::string>(0);
1165+
CATCH_CHECK_FALSE(value);
1166+
}
1167+
1168+
CATCH_SECTION("Parameters cannot be copied if of an incompatible type")
1169+
{
1170+
fly::detail::BasicFormatParameters<StringType, int> parameters(1);
1171+
1172+
auto value = parameters.template get<std::string>(0);
1173+
CATCH_CHECK_FALSE(value);
1174+
}
1175+
1176+
CATCH_SECTION("Stored parameters are not copied or moved")
11421177
{
11431178
ConstructorCounter c1;
11441179
const ConstructorCounter c2;

0 commit comments

Comments
 (0)