Skip to content

Commit c3934a4

Browse files
authored
[API/SDK] Add ASCII helpers and remove regex from InstrumentMetaDataValidator (#4715)
1 parent bcacfec commit c3934a4

39 files changed

Lines changed: 555 additions & 314 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Increment the:
1515

1616
## [Unreleased]
1717

18+
* [API/SDK] Add ASCII helpers and remove regex from InstrumentMetaDataValidator
19+
[#4715](https://github.com/open-telemetry/opentelemetry-cpp/pull/4715)
20+
1821
* [SDK] Release provider mutexes before construction-failure diagnostics so
1922
custom log handlers can retrieve cached or noop tracers, loggers, and meters
2023
from the same provider without deadlocking.

‎api/include/opentelemetry/baggage/baggage.h‎

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33

44
#pragma once
55

6-
#include <cctype>
7-
6+
#include "opentelemetry/common/detail/ascii.h"
87
#include "opentelemetry/common/kv_properties.h"
98
#include "opentelemetry/common/macros.h"
109
#include "opentelemetry/nostd/shared_ptr.h"
@@ -215,16 +214,11 @@ class OPENTELEMETRY_EXPORT Baggage
215214
// Implementation inspired from : https://golang.org/src/net/url/url.go?s=7851:7884#L264
216215
static std::string UrlEncode(nostd::string_view str)
217216
{
218-
auto to_hex = [](char c) -> char {
219-
static const char *hex = "0123456789ABCDEF";
220-
return hex[c & 15];
221-
};
222-
223217
std::string ret;
224218

225219
for (auto c : str)
226220
{
227-
if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
221+
if (common::detail::IsAsciiAlnum(c) || c == '-' || c == '_' || c == '.' || c == '~')
228222
{
229223
ret.push_back(c);
230224
}
@@ -235,8 +229,8 @@ class OPENTELEMETRY_EXPORT Baggage
235229
else
236230
{
237231
ret.push_back('%');
238-
ret.push_back(to_hex(static_cast<char>(c >> 4)));
239-
ret.push_back(to_hex(static_cast<char>(c & 15)));
232+
ret.push_back(common::detail::UpperHexDigit(static_cast<unsigned char>(c) >> 4));
233+
ret.push_back(common::detail::UpperHexDigit(c));
240234
}
241235
}
242236

@@ -246,29 +240,21 @@ class OPENTELEMETRY_EXPORT Baggage
246240
// Uri decode key value pairs after extracting from header
247241
static std::string UrlDecode(nostd::string_view str, bool &err)
248242
{
249-
auto IsHex = [](char c) {
250-
return std::isdigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
251-
};
252-
253-
auto from_hex = [](char c) -> char {
254-
// c - '0' produces integer type which could trigger error/warning when casting to char,
255-
// but the cast is safe here.
256-
return static_cast<char>(std::isdigit(c) ? c - '0' : std::toupper(c) - 'A' + 10);
257-
};
258-
259243
std::string ret;
260244
ret.reserve(str.size());
261245

262246
for (size_t i = 0; i < str.size(); i++)
263247
{
264248
if (str[i] == '%')
265249
{
266-
if (i + 2 >= str.size() || !IsHex(str[i + 1]) || !IsHex(str[i + 2]))
250+
if (i + 2 >= str.size() || !common::detail::IsAsciiHexDigit(str[i + 1]) ||
251+
!common::detail::IsAsciiHexDigit(str[i + 2]))
267252
{
268253
err = true;
269254
return "";
270255
}
271-
ret.push_back(static_cast<char>(from_hex(str[i + 1]) << 4 | from_hex(str[i + 2])));
256+
ret.push_back(static_cast<char>(common::detail::HexDigitValue(str[i + 1]) << 4 |
257+
common::detail::HexDigitValue(str[i + 2])));
272258
i += 2;
273259
}
274260
else if (str[i] == '+')
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#pragma once
5+
6+
#include <cstdint>
7+
8+
#include "opentelemetry/version.h"
9+
10+
OPENTELEMETRY_BEGIN_NAMESPACE
11+
namespace common
12+
{
13+
namespace detail
14+
{
15+
16+
// Character classes for protocol and specification text, which define them over
17+
// ASCII. The <cctype> functions depend on the global locale, and passing them a
18+
// negative char is undefined behavior.
19+
20+
constexpr bool IsAsciiDigit(char c) noexcept
21+
{
22+
return c >= '0' && c <= '9';
23+
}
24+
25+
constexpr bool IsAsciiLower(char c) noexcept
26+
{
27+
return c >= 'a' && c <= 'z';
28+
}
29+
30+
constexpr bool IsAsciiUpper(char c) noexcept
31+
{
32+
return c >= 'A' && c <= 'Z';
33+
}
34+
35+
constexpr bool IsAsciiAlpha(char c) noexcept
36+
{
37+
return IsAsciiLower(c) || IsAsciiUpper(c);
38+
}
39+
40+
constexpr bool IsAsciiAlnum(char c) noexcept
41+
{
42+
return IsAsciiAlpha(c) || IsAsciiDigit(c);
43+
}
44+
45+
// Indexed by byte value: hexadecimal digits are decoded on the propagation hot
46+
// path, where a lookup is faster than range comparisons.
47+
constexpr int8_t kHexDigitValues[256] = {
48+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
49+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
50+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1,
51+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52+
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
55+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
56+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
57+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
58+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
59+
60+
// Returns the value of a hexadecimal digit of either case, or -1 if c is not one.
61+
constexpr int HexDigitValue(char c) noexcept
62+
{
63+
return kHexDigitValues[static_cast<unsigned char>(c)];
64+
}
65+
66+
constexpr bool IsAsciiHexDigit(char c) noexcept
67+
{
68+
return HexDigitValue(c) >= 0;
69+
}
70+
71+
// Returns the hexadecimal digit for the low four bits of value.
72+
constexpr char LowerHexDigit(int value) noexcept
73+
{
74+
return "0123456789abcdef"[value & 0xF];
75+
}
76+
77+
constexpr char UpperHexDigit(int value) noexcept
78+
{
79+
return "0123456789ABCDEF"[value & 0xF];
80+
}
81+
82+
// 0x00 to 0x1F and 0x7F: what std::iscntrl accepts in the "C" locale.
83+
constexpr bool IsAsciiControl(char c) noexcept
84+
{
85+
return static_cast<unsigned char>(c) < 0x20 || c == '\x7f';
86+
}
87+
88+
// Space, \t, \n, \v, \f and \r: what std::isspace accepts in the "C" locale.
89+
constexpr bool IsAsciiSpace(char c) noexcept
90+
{
91+
return c == ' ' || (c >= '\t' && c <= '\r');
92+
}
93+
94+
constexpr char ToAsciiLower(char c) noexcept
95+
{
96+
return IsAsciiUpper(c) ? static_cast<char>(c - 'A' + 'a') : c;
97+
}
98+
99+
constexpr char ToAsciiUpper(char c) noexcept
100+
{
101+
return IsAsciiLower(c) ? static_cast<char>(c - 'a' + 'A') : c;
102+
}
103+
104+
} // namespace detail
105+
} // namespace common
106+
OPENTELEMETRY_END_NAMESPACE

‎api/include/opentelemetry/common/string_util.h‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33

44
#pragma once
55

6-
#include <cctype>
7-
6+
#include "opentelemetry/common/detail/ascii.h"
87
#include "opentelemetry/common/macros.h"
98

109
#if OPENTELEMETRY_HAVE_EXCEPTIONS
@@ -29,11 +28,11 @@ class StringUtil
2928
{
3029
return nostd::string_view();
3130
}
32-
while (left <= right && std::isspace(str[left]))
31+
while (left <= right && detail::IsAsciiSpace(str[left]))
3332
{
3433
left++;
3534
}
36-
while (left <= right && std::isspace(str[right]))
35+
while (left <= right && detail::IsAsciiSpace(str[right]))
3736
{
3837
right--;
3938
}

‎api/include/opentelemetry/context/propagation/environment_carrier.h‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <memory>
99
#include <string>
1010

11+
#include "opentelemetry/common/detail/ascii.h"
1112
#include "opentelemetry/context/propagation/text_map_propagator.h"
1213
#include "opentelemetry/nostd/string_view.h"
1314
#include "opentelemetry/version.h"
@@ -135,17 +136,13 @@ class EnvironmentCarrier : public TextMapCarrier
135136
std::string result(key);
136137
for (auto &c : result)
137138
{
138-
unsigned char uc = static_cast<unsigned char>(c);
139-
if (uc >= 'a' && uc <= 'z')
140-
{
141-
c = static_cast<char>(uc - ('a' - 'A'));
142-
}
143-
else if (!((uc >= 'A' && uc <= 'Z') || (uc >= '0' && uc <= '9') || uc == '_'))
139+
c = common::detail::ToAsciiUpper(c);
140+
if (!common::detail::IsAsciiUpper(c) && !common::detail::IsAsciiDigit(c) && c != '_')
144141
{
145142
c = '_';
146143
}
147144
}
148-
if (result[0] >= '0' && result[0] <= '9')
145+
if (common::detail::IsAsciiDigit(result[0]))
149146
{
150147
result.insert(result.begin(), '_');
151148
}

‎api/include/opentelemetry/trace/propagation/detail/hex.h‎

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <cstdint>
88
#include <cstring>
99

10+
#include "opentelemetry/common/detail/ascii.h"
1011
#include "opentelemetry/nostd/string_view.h"
1112
#include "opentelemetry/version.h"
1213

@@ -20,28 +21,9 @@ namespace propagation
2021
namespace detail
2122
{
2223

23-
constexpr int8_t kHexDigits[256] = {
24-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26-
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1,
27-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28-
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35-
};
36-
37-
inline int8_t HexToInt(char c)
38-
{
39-
return kHexDigits[static_cast<uint8_t>(c)];
40-
}
41-
4224
inline bool IsValidHex(nostd::string_view s)
4325
{
44-
return std::all_of(s.begin(), s.end(), [](char c) { return HexToInt(c) != -1; });
26+
return std::all_of(s.begin(), s.end(), [](char c) { return common::detail::IsAsciiHexDigit(c); });
4527
}
4628

4729
/**
@@ -66,12 +48,13 @@ inline bool HexToBinary(nostd::string_view hex, uint8_t *buffer, size_t buffer_s
6648

6749
if (is_hex_size_odd)
6850
{
69-
buffer[buffer_pos++] = HexToInt(hex[i++]);
51+
buffer[buffer_pos++] = static_cast<uint8_t>(common::detail::HexDigitValue(hex[i++]));
7052
}
7153

7254
for (; i < last_hex_pos; i += 2)
7355
{
74-
buffer[buffer_pos++] = (HexToInt(hex[i]) << 4) | HexToInt(hex[i + 1]);
56+
buffer[buffer_pos++] = static_cast<uint8_t>((common::detail::HexDigitValue(hex[i]) << 4) |
57+
common::detail::HexDigitValue(hex[i + 1]));
7558
}
7659

7760
return true;

‎api/include/opentelemetry/trace/span_id.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cstdint>
77
#include <cstring>
88

9+
#include "opentelemetry/common/detail/ascii.h"
910
#include "opentelemetry/nostd/span.h"
1011
#include "opentelemetry/version.h"
1112

@@ -31,11 +32,10 @@ class SpanId final
3132
// Populates the buffer with the lowercase base16 representation of the ID.
3233
void ToLowerBase16(nostd::span<char, 2 * kSize> buffer) const noexcept
3334
{
34-
constexpr char kHex[] = "0123456789abcdef";
3535
for (size_t i = 0; i < kSize; ++i)
3636
{
37-
buffer[i * 2 + 0] = kHex[(rep_[i] >> 4) & 0xF];
38-
buffer[i * 2 + 1] = kHex[(rep_[i] >> 0) & 0xF];
37+
buffer[i * 2 + 0] = common::detail::LowerHexDigit(rep_[i] >> 4);
38+
buffer[i * 2 + 1] = common::detail::LowerHexDigit(rep_[i]);
3939
}
4040
}
4141

‎api/include/opentelemetry/trace/trace_flags.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <cstdint>
77

8+
#include "opentelemetry/common/detail/ascii.h"
89
#include "opentelemetry/nostd/span.h"
910
#include "opentelemetry/version.h"
1011

@@ -44,9 +45,8 @@ class TraceFlags final
4445
// Populates the buffer with the lowercase base16 representation of the flags.
4546
void ToLowerBase16(nostd::span<char, 2> buffer) const noexcept
4647
{
47-
constexpr char kHex[] = "0123456789ABCDEF";
48-
buffer[0] = kHex[(rep_ >> 4) & 0xF];
49-
buffer[1] = kHex[(rep_ >> 0) & 0xF];
48+
buffer[0] = common::detail::UpperHexDigit(rep_ >> 4);
49+
buffer[1] = common::detail::UpperHexDigit(rep_);
5050
}
5151

5252
uint8_t flags() const noexcept { return rep_; }

‎api/include/opentelemetry/trace/trace_id.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cstdint>
77
#include <cstring>
88

9+
#include "opentelemetry/common/detail/ascii.h"
910
#include "opentelemetry/nostd/span.h"
1011
#include "opentelemetry/version.h"
1112

@@ -34,11 +35,10 @@ class TraceId final
3435
// Populates the buffer with the lowercase base16 representation of the ID.
3536
void ToLowerBase16(nostd::span<char, 2 * kSize> buffer) const noexcept
3637
{
37-
constexpr char kHex[] = "0123456789abcdef";
3838
for (size_t i = 0; i < kSize; ++i)
3939
{
40-
buffer[i * 2 + 0] = kHex[(rep_[i] >> 4) & 0xF];
41-
buffer[i * 2 + 1] = kHex[(rep_[i] >> 0) & 0xF];
40+
buffer[i * 2 + 0] = common::detail::LowerHexDigit(rep_[i] >> 4);
41+
buffer[i * 2 + 1] = common::detail::LowerHexDigit(rep_[i]);
4242
}
4343
}
4444

‎api/include/opentelemetry/trace/trace_state.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33

44
#pragma once
55

6-
#include <cctype>
76
#include <cstddef>
87
#include <string>
98
#include <vector>
109

10+
#include "opentelemetry/common/detail/ascii.h"
1111
#include "opentelemetry/common/kv_properties.h"
1212
#include "opentelemetry/nostd/function_ref.h"
1313
#include "opentelemetry/nostd/shared_ptr.h"
@@ -298,7 +298,7 @@ class OPENTELEMETRY_EXPORT TraceState
298298

299299
static bool IsLowerCaseAlphaOrDigit(char c) noexcept
300300
{
301-
return std::isdigit(c) || std::islower(c);
301+
return common::detail::IsAsciiDigit(c) || common::detail::IsAsciiLower(c);
302302
}
303303

304304
private:

0 commit comments

Comments
 (0)