Skip to content

Commit a73ec5c

Browse files
committed
Addition of string_view support
1 parent b07326c commit a73ec5c

File tree

11 files changed

+564
-346
lines changed

11 files changed

+564
-346
lines changed

docs/traits.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ struct my_favorite_json_library_traits {
5454
static boolean_type as_boolean(const value_type &val);
5555

5656
// serialization and parsing
57-
static bool parse(value_type &val, string_type str);
57+
template <class string_t> // could be the json string_type, or std::string_view for instance
58+
static bool parse(value_type &val, const string_t& str);
5859
static string_type serialize(const value_type &val); // with no extra whitespace, padding or indentation
5960
};
6061
```

include/jwt-cpp/base.h

+47-52
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
#include <array>
66
#include <stdexcept>
77
#include <string>
8-
#include <vector>
8+
9+
#include "string_types.h"
910

1011
#ifdef __has_cpp_attribute
1112
#if __has_cpp_attribute(fallthrough)
@@ -37,10 +38,7 @@ namespace jwt {
3738
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}};
3839
return data;
3940
}
40-
static const std::string& fill() {
41-
static std::string fill{"="};
42-
return fill;
43-
}
41+
static std::array<string_constant, 1> fill() { return std::array<string_constant, 1>{"="}; }
4442
};
4543
/**
4644
* \brief valid list of character when working with [Base64URL](https://tools.ietf.org/html/rfc4648#section-5)
@@ -60,10 +58,7 @@ namespace jwt {
6058
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
6159
return data;
6260
}
63-
static const std::string& fill() {
64-
static std::string fill{"%3d"};
65-
return fill;
66-
}
61+
static std::array<string_constant, 1> fill() { return std::array<string_constant, 1>{"%3d"}; }
6762
};
6863
namespace helper {
6964
/**
@@ -81,15 +76,15 @@ namespace jwt {
8176
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}};
8277
return data;
8378
}
84-
static const std::initializer_list<std::string>& fill() {
85-
static std::initializer_list<std::string> fill{"%3D", "%3d"};
86-
return fill;
87-
}
79+
static std::array<string_constant, 2> fill() { return std::array<string_constant, 2>{"%3D", "%3d"}; }
8880
};
8981
} // namespace helper
9082

9183
inline uint32_t index(const std::array<char, 64>& alphabet, char symbol) {
92-
auto itr = std::find_if(alphabet.cbegin(), alphabet.cend(), [symbol](char c) { return c == symbol; });
84+
if (symbol >= 'A' && symbol <= 'Z') { return static_cast<uint32_t>(symbol - 'A'); }
85+
if (symbol >= 'a' && symbol <= 'z') { return static_cast<uint32_t>(26 + symbol - 'a'); }
86+
if (symbol >= '0' && symbol <= '9') { return static_cast<uint32_t>(52 + symbol - '0'); }
87+
auto itr = std::find(std::next(alphabet.cbegin(), 62U), alphabet.cend(), symbol);
9388
if (itr == alphabet.cend()) { throw std::runtime_error("Invalid input: not within alphabet"); }
9489

9590
return std::distance(alphabet.cbegin(), itr);
@@ -116,30 +111,31 @@ namespace jwt {
116111
}
117112
};
118113

119-
inline padding count_padding(const std::string& base, const std::vector<std::string>& fills) {
120-
for (const auto& fill : fills) {
121-
if (base.size() < fill.size()) continue;
114+
template<class StrInputIt>
115+
padding count_padding(string_view base, StrInputIt fillStart, StrInputIt fillEnd) {
116+
for (StrInputIt fillIt = fillStart; fillIt != fillEnd; ++fillIt) {
117+
int fillLen = static_cast<int>(fillIt->size());
118+
int deltaLen = static_cast<int>(base.size()) - fillLen;
122119
// Does the end of the input exactly match the fill pattern?
123-
if (base.substr(base.size() - fill.size()) == fill) {
124-
return padding{1, fill.length()} +
125-
count_padding(base.substr(0, base.size() - fill.size()), fills);
120+
if (deltaLen >= 0 && base.substr(deltaLen) == *fillIt) {
121+
return padding{1, static_cast<size_t>(fillLen)} +
122+
count_padding(base.substr(0, deltaLen), fillStart, fillEnd);
126123
}
127124
}
128125

129126
return {};
130127
}
131128

132-
inline std::string encode(const std::string& bin, const std::array<char, 64>& alphabet,
133-
const std::string& fill) {
129+
inline std::string encode(string_view bin, const std::array<char, 64>& alphabet, string_view fill) {
134130
size_t size = bin.size();
135131
std::string res;
136132

137133
// clear incomplete bytes
138134
size_t fast_size = size - size % 3;
139-
for (size_t i = 0; i < fast_size;) {
140-
uint32_t octet_a = static_cast<unsigned char>(bin[i++]);
141-
uint32_t octet_b = static_cast<unsigned char>(bin[i++]);
142-
uint32_t octet_c = static_cast<unsigned char>(bin[i++]);
135+
for (size_t i = 0; i < fast_size; i += 3) {
136+
uint32_t octet_a = static_cast<unsigned char>(bin[i]);
137+
uint32_t octet_b = static_cast<unsigned char>(bin[i + 1]);
138+
uint32_t octet_c = static_cast<unsigned char>(bin[i + 2]);
143139

144140
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
145141

@@ -178,9 +174,10 @@ namespace jwt {
178174
return res;
179175
}
180176

181-
inline std::string decode(const std::string& base, const std::array<char, 64>& alphabet,
182-
const std::vector<std::string>& fill) {
183-
const auto pad = count_padding(base, fill);
177+
template<class StrInputIt>
178+
inline std::string decode(string_view base, const std::array<char, 64>& alphabet, StrInputIt fillStart,
179+
StrInputIt fillEnd) {
180+
const auto pad = count_padding(base, fillStart, fillEnd);
184181
if (pad.count > 2) throw std::runtime_error("Invalid input: too much fill");
185182

186183
const size_t size = base.size() - pad.length;
@@ -224,44 +221,42 @@ namespace jwt {
224221
return res;
225222
}
226223

227-
inline std::string decode(const std::string& base, const std::array<char, 64>& alphabet,
228-
const std::string& fill) {
229-
return decode(base, alphabet, std::vector<std::string>{fill});
230-
}
231-
232-
inline std::string pad(const std::string& base, const std::string& fill) {
233-
std::string padding;
234-
switch (base.size() % 4) {
235-
case 1: padding += fill; JWT_FALLTHROUGH;
236-
case 2: padding += fill; JWT_FALLTHROUGH;
237-
case 3: padding += fill; JWT_FALLTHROUGH;
224+
inline std::string pad(string_view base, string_view fill) {
225+
std::string res(base);
226+
switch (res.size() % 4) {
227+
case 1: res += fill; JWT_FALLTHROUGH;
228+
case 2: res += fill; JWT_FALLTHROUGH;
229+
case 3: res += fill; JWT_FALLTHROUGH;
238230
default: break;
239231
}
240-
241-
return base + padding;
232+
return res;
242233
}
243234

244-
inline std::string trim(const std::string& base, const std::string& fill) {
235+
inline std::string trim(string_view base, string_view fill) {
245236
auto pos = base.find(fill);
246-
return base.substr(0, pos);
237+
return static_cast<std::string>(base.substr(0, pos));
247238
}
248239
} // namespace details
249240

250241
template<typename T>
251-
std::string encode(const std::string& bin) {
252-
return details::encode(bin, T::data(), T::fill());
242+
std::string encode(string_view bin) {
243+
static const auto fills = T::fill();
244+
return details::encode(bin, T::data(), fills.front());
253245
}
254246
template<typename T>
255-
std::string decode(const std::string& base) {
256-
return details::decode(base, T::data(), T::fill());
247+
std::string decode(string_view base) {
248+
static const auto fills = T::fill();
249+
return details::decode(base, T::data(), fills.begin(), fills.end());
257250
}
258251
template<typename T>
259-
std::string pad(const std::string& base) {
260-
return details::pad(base, T::fill());
252+
std::string pad(string_view base) {
253+
static const auto fills = T::fill();
254+
return details::pad(base, fills.front());
261255
}
262256
template<typename T>
263-
std::string trim(const std::string& base) {
264-
return details::trim(base, T::fill());
257+
std::string trim(string_view base) {
258+
static const auto fills = T::fill();
259+
return details::trim(base, fills.front());
265260
}
266261
} // namespace base
267262
} // namespace jwt

0 commit comments

Comments
 (0)