Skip to content

Commit e6ffc34

Browse files
committed
DPL: improve DataSpecUtils::describe API in case of buffers
Just like snprintf, it makes sense to return the size of the formatted output.
1 parent 82782fd commit e6ffc34

File tree

3 files changed

+67
-22
lines changed

3 files changed

+67
-22
lines changed

Framework/Core/include/Framework/DataSpecUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,10 @@ struct DataSpecUtils {
152152
static bool validate(OutputSpec const& output);
153153

154154
/// Same as the other describe, but uses a buffer to reduce memory churn.
155-
static void describe(char* buffer, size_t size, InputSpec const& spec);
155+
static size_t describe(char* buffer, size_t size, InputSpec const& spec);
156156

157157
/// Same as the other describe, but uses a buffer to reduce memory churn.
158-
static void describe(char* buffer, size_t size, OutputSpec const& spec);
158+
static size_t describe(char* buffer, size_t size, OutputSpec const& spec);
159159

160160
/// If possible extract the ConcreteDataMatcher from an InputSpec. This
161161
/// can be done either if the InputSpec is defined in terms for a ConcreteDataMatcher

Framework/Core/src/DataSpecUtils.cxx

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -87,38 +87,30 @@ std::string DataSpecUtils::describe(OutputSpec const& spec)
8787
spec.matcher);
8888
}
8989

90-
void DataSpecUtils::describe(char* buffer, size_t size, InputSpec const& spec)
90+
size_t DataSpecUtils::describe(char* buffer, size_t size, InputSpec const& spec)
9191
{
9292
if (auto concrete = std::get_if<ConcreteDataMatcher>(&spec.matcher)) {
93-
char origin[5];
94-
origin[4] = 0;
95-
char description[17];
96-
description[16] = 0;
97-
snprintf(buffer, size, "%s/%s/%" PRIu32, (strncpy(origin, concrete->origin.str, 4), origin),
98-
(strncpy(description, concrete->description.str, 16), description), concrete->subSpec);
93+
auto out = fmt::format_to_n(buffer, size, "{:.4}/{:.16}/{}", concrete->origin.str, concrete->description.str, concrete->subSpec);
94+
return std::min(out.size, size);
9995
} else if (auto matcher = std::get_if<DataDescriptorMatcher>(&spec.matcher)) {
10096
std::ostringstream ss;
10197
ss << "<matcher query: " << *matcher << ">";
102-
strncpy(buffer, ss.str().c_str(), size - 1);
103-
} else {
104-
throw runtime_error("Unsupported InputSpec");
98+
auto out = fmt::format_to_n(buffer, size, "{}", ss.str());
99+
return std::min(out.size, size);
105100
}
101+
throw runtime_error("Unsupported InputSpec");
106102
}
107103

108-
void DataSpecUtils::describe(char* buffer, size_t size, OutputSpec const& spec)
104+
size_t DataSpecUtils::describe(char* buffer, size_t size, OutputSpec const& spec)
109105
{
110106
if (auto concrete = std::get_if<ConcreteDataMatcher>(&spec.matcher)) {
111-
char origin[5];
112-
origin[4] = 0;
113-
char description[17];
114-
description[16] = 0;
115-
snprintf(buffer, size, "%s/%s/%" PRIu32, (strncpy(origin, concrete->origin.str, 4), origin),
116-
(strncpy(description, concrete->description.str, 16), description), concrete->subSpec);
107+
auto out = fmt::format_to_n(buffer, size, "{:.4}/{:.16}/{}", concrete->origin.str, concrete->description.str, concrete->subSpec);
108+
return std::min(out.size, size);
117109
} else if (auto concrete = std::get_if<ConcreteDataTypeMatcher>(&spec.matcher)) {
118-
fmt::format_to(buffer, "<matcher query: {}/{}>", concrete->origin, concrete->description);
119-
} else {
120-
throw runtime_error("Unsupported OutputSpec");
110+
auto out = fmt::format_to_n(buffer, size, "<matcher query: {}/{}>", concrete->origin, concrete->description);
111+
return std::min(out.size, size);
121112
}
113+
throw runtime_error("Unsupported OutputSpec");
122114
}
123115

124116
std::string DataSpecUtils::label(InputSpec const& spec)

Framework/Core/test/unittest_DataSpecUtils.cxx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ TEST_CASE("ConcreteData")
4242
CHECK(std::string(concrete.description.as<std::string>()) == "FOOO");
4343
CHECK(concrete.subSpec == 1);
4444
CHECK(DataSpecUtils::describe(spec) == "TEST/FOOO/1");
45+
CHECK(DataSpecUtils::describe(spec) == "TEST/FOOO/1");
4546
CHECK(*DataSpecUtils::getOptionalSubSpec(spec) == 1);
4647

4748
ConcreteDataTypeMatcher dataType = DataSpecUtils::asConcreteDataTypeMatcher(spec);
@@ -59,6 +60,43 @@ TEST_CASE("ConcreteData")
5960
}
6061
}
6162

63+
TEST_CASE("DescribeUsingBuffer")
64+
{
65+
o2::framework::clean_all_runtime_errors();
66+
OutputSpec spec{
67+
"TEST",
68+
"FOOO",
69+
1,
70+
Lifetime::Timeframe};
71+
72+
InputSpec inputSpec{
73+
"binding",
74+
"TEST",
75+
"FOOO",
76+
1,
77+
Lifetime::Timeframe};
78+
79+
REQUIRE(DataSpecUtils::validate(inputSpec));
80+
81+
{
82+
char buffer[1024];
83+
84+
ConcreteDataMatcher concrete = DataSpecUtils::asConcreteDataMatcher(spec);
85+
CHECK(std::string(concrete.origin.as<std::string>()) == "TEST");
86+
CHECK(std::string(concrete.description.as<std::string>()) == "FOOO");
87+
CHECK(concrete.subSpec == 1);
88+
auto size = DataSpecUtils::describe(buffer, 1024, spec);
89+
CHECK(std::string_view(buffer, size) == "TEST/FOOO/1");
90+
size = DataSpecUtils::describe(buffer, 1024, spec);
91+
CHECK(std::string_view(buffer, size) == "TEST/FOOO/1");
92+
CHECK(*DataSpecUtils::getOptionalSubSpec(spec) == 1);
93+
94+
char buffer2[1024];
95+
size = DataSpecUtils::describe(buffer2, 5, spec);
96+
CHECK(std::string_view(buffer2, size) == "TEST/");
97+
}
98+
}
99+
62100
TEST_CASE("WithWildCards")
63101
{
64102
OutputSpec spec{
@@ -78,6 +116,21 @@ TEST_CASE("WithWildCards")
78116
CHECK(DataSpecUtils::getOptionalSubSpec(spec) == std::nullopt);
79117
}
80118

119+
TEST_CASE("WithWildCardsBuffer")
120+
{
121+
char buffer[1024];
122+
OutputSpec spec{
123+
{"TEST", "FOOO"},
124+
Lifetime::Timeframe};
125+
126+
auto size = DataSpecUtils::describe(buffer, 1024, spec);
127+
CHECK(std::string_view(buffer, size) == "<matcher query: TEST/FOOO>");
128+
129+
char buffer2[1024];
130+
size = DataSpecUtils::describe(buffer2, 5, spec);
131+
CHECK( std::string_view(buffer2, size) == "<matc");
132+
}
133+
81134
TEST_CASE("MatchingInputs")
82135
{
83136
OutputSpec fullySpecified{

0 commit comments

Comments
 (0)