-
Notifications
You must be signed in to change notification settings - Fork 124
Expand file tree
/
Copy pathtype_support_wrapper.cpp
More file actions
149 lines (130 loc) · 5.85 KB
/
Copy pathtype_support_wrapper.cpp
File metadata and controls
149 lines (130 loc) · 5.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
* This is free and unencumbered software released into the public domain.
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
#include <cppcodec/base64_rfc4648.hpp>
#include <iostream>
// This example shows how to wrap a type (here: std::string) in another
// result type in order to modify the standard behavior for that type.
// Use this when you're in a position to wrap the result variable.
//
// This is the more straightforward of two ways for modifying cppcodec's
// behavior for a given type, the other one being able to modify the
// default behavior but also being more complex/intricate.
//
// The overall approach is straightforward: Define a result type with
// push_back(char) and size() methods, implement template specializations
// for init() and finish() for the result type, and call encode()/decode()
// with an object of this type as result parameter.
class string_append_wrapper
{
public:
string_append_wrapper(std::string& backing)
: m_backing(backing)
, m_offset(0)
, m_orig_size(0)
{
}
void init(size_t capacity)
{
m_orig_size = m_backing.size();
m_offset = m_orig_size;
m_backing.resize(m_orig_size + capacity);
}
void finish()
{
m_backing.resize(m_offset);
}
// Methods required for satisfying default result type requirements:
CPPCODEC_ALWAYS_INLINE void push_back(char c) { m_backing[m_offset++] = c; }
CPPCODEC_ALWAYS_INLINE size_t size() const { return m_offset - m_orig_size; }
// Note that the above implementation of push_back() is not the fastest,
// because operator[] for std::string (for C++11 and above) still includes
// a check for whether the size of the string fits into its allocation-less
// character array union.
//
// With C++17 and above, it's legitimate to get the character array as a
// mutable (non-const) char pointer, so this check can be skipped.
// This is implemented via template specialization in cppcodec's
// default behavior for std::string, but omitted here for simplicity.
// If you need that last bit of extra performance, see
// direct_data_access_result_state in cppcodec/data/access.hpp
// for an example of optimal C++17 string access.
private:
std::string& m_backing;
size_t m_offset;
size_t m_orig_size;
};
// init() and finish() must be declared in the cppcodec::data namespace.
namespace cppcodec {
namespace data {
template <> inline void init<string_append_wrapper>(
string_append_wrapper& result, empty_result_state&, size_t capacity)
{
// init() is called to prepare the output buffer. cppcodec will call it
// with the maximum output size, null termination not included.
//
// Any thrown exception will not be caught by cppcodec itself,
// the caller of the encode/decode function is responsible for handling it.
//
// empty_result_state can be ignored in this case because the wrapper type
// can carry all required state internally.
//
// In order to maximize performance, init() should generally try to
// allocate or guarantee the entire output buffer at once, so that
// subsequent calls to push_back() don't result in extra checks (slower)
// or even re-allocations.
result.init(capacity);
}
// Between init() and finish(), cppcodec will call result.push_back(char)
// repeatedly, once for each output character with no rewinding.
// While init() can ask for greater capacity than the final output length,
// cppcodec guarantees that push_back() will never be called too often.
//
// (If you know exactly how long your output is, you could theoretically
// overcommit on capacity while allocating only the exact expected length
// of the output buffer. This is of course dangerous, because you can
// hardly ever know for sure and everyone's often wrong, so don't try it
// unless you have a business-critical reason to reduce/avoid the allocation.)
template <> inline void finish<string_append_wrapper>(
string_append_wrapper& result, empty_result_state&)
{
// finish() is called after encoding/decoding is done.
// Its main purpose is to reduce the size of the result type
// from capacity to the actual (often slightly smaller) output length.
//
// After finish(), cppcodec will assert that result.size() does indeed
// equal the number of times that push_back() has been called.
result.finish();
}
} // namespace data
} // namespace cppcodec
int main() {
using base64 = cppcodec::base64_rfc4648;
std::string result = "Result: ";
string_append_wrapper appender(result);
base64::encode(appender, std::string("any carnal pleasure"));
std::cout << result << std::endl; // "Result: YW55IGNhcm5hbCBwbGVhc3VyZQ=="
return 0;
}