Line data Source code
1 : /**
2 : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_DATA_SPDATAENCODECBOR_H_
25 : #define STAPPLER_DATA_SPDATAENCODECBOR_H_
26 :
27 : #include "SPDataCbor.h"
28 : #include "SPDataValue.h"
29 : #include "SPFilesystem.h"
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::data::cbor {
32 :
33 : template <typename Interface>
34 : struct Encoder : public Interface::AllocBaseType {
35 : using InterfaceType = Interface;
36 : using ValueType = ValueTemplate<Interface>;
37 :
38 : enum Type {
39 : None,
40 : File,
41 : Buffered,
42 : Vector,
43 : Stream,
44 : };
45 :
46 : static typename Interface::BytesType encode(const typename ValueType::ArrayType &arr) {
47 : Encoder<Interface> enc(false);
48 : for (auto &it : arr) {
49 : it.encode(enc);
50 : }
51 : return enc.data();
52 : }
53 :
54 : static typename Interface::BytesType encode(const typename ValueType::DictionaryType &arr) {
55 : Encoder<Interface> enc(false);
56 : for (auto &it : arr) {
57 : it.encode(enc);
58 : }
59 : return enc.data();
60 : }
61 :
62 75 : Encoder(StringView filename) : type(File) {
63 75 : auto path = filesystem::native::posixToNative<Interface>(filename);
64 75 : file = new std::ofstream(path.data(), std::ios::binary);
65 75 : if (isOpen()) {
66 75 : cbor::_writeId(*this);
67 : }
68 75 : }
69 :
70 0 : Encoder(const Callback<void(BytesView)> *s) : type(Stream) {
71 0 : stream = s;
72 0 : if (isOpen()) {
73 0 : cbor::_writeId(*this);
74 : }
75 0 : }
76 :
77 16525 : Encoder(bool prefix = false, size_t reserve = 1_KiB) : type(Interface::usesMemoryPool()?Vector:Buffered) {
78 16525 : static thread_local typename ValueType::BytesType tl_buffer;
79 : if constexpr (Interface::usesMemoryPool()) {
80 28150 : buffer = new typename ValueType::BytesType();
81 : } else {
82 2450 : if (reserve <= 1_KiB) {
83 1750 : buffer = &tl_buffer;
84 1750 : buffer->clear();
85 1750 : reserve = 1_KiB;
86 : } else {
87 700 : type = Vector;
88 700 : buffer = new typename ValueType::BytesType();
89 : }
90 : }
91 16525 : buffer->reserve(reserve);
92 16525 : if (prefix && isOpen()) {
93 16525 : cbor::_writeId(*this);
94 : }
95 16525 : }
96 :
97 16600 : ~Encoder() {
98 16600 : switch (type) {
99 75 : case File: file->flush(); file->close(); delete file; break;
100 0 : case Stream: break;
101 15075 : case Vector: delete buffer; break;
102 1450 : default: break;
103 : }
104 16600 : }
105 :
106 19528483 : void emplace(uint8_t c) {
107 19528483 : switch (type) {
108 2558158 : case File: file->put(c); break;
109 0 : case Stream: (*stream) << c; break;
110 16970325 : case Buffered:
111 : case Vector:
112 16970325 : buffer->emplace_back(c);
113 16970325 : break;
114 0 : default: break;
115 : }
116 19528483 : }
117 :
118 16351533 : void emplace(const uint8_t *buf, size_t size) {
119 16351533 : if (type == Buffered) {
120 1723200 : switchBuffer(buffer->size() + size);
121 : }
122 :
123 : size_t tmpSize;
124 16351533 : switch (type) {
125 2542533 : case File: file->write((const std::ofstream::char_type *)buf, size); break;
126 0 : case Stream: (*stream) << BytesView(buf, size); break;
127 13809000 : case Buffered:
128 : case Vector:
129 13809000 : tmpSize = buffer->size();
130 13809000 : buffer->resize(tmpSize + size);
131 13809000 : memcpy(buffer->data() + tmpSize, buf, size);
132 13809000 : break;
133 0 : default: break;
134 : }
135 16351533 : }
136 :
137 1723200 : void switchBuffer(size_t newSize) {
138 1723200 : if (type == Buffered && newSize > 100_KiB) {
139 300 : type = Vector;
140 300 : auto newVec = new typename ValueType::BytesType();
141 300 : newVec->resize(buffer->size());
142 300 : memcpy(newVec->data(), buffer->data(), buffer->size());
143 300 : buffer = newVec;
144 : }
145 1723200 : }
146 :
147 31375 : bool isOpen() const {
148 31375 : switch (type) {
149 0 : case None: return false; break;
150 150 : case File: return file->is_open(); break;
151 31225 : default: return true; break;
152 : }
153 : return false;
154 : }
155 :
156 16525 : typename ValueType::BytesType data() {
157 16525 : if (type == Buffered) {
158 1450 : typename ValueType::BytesType ret;
159 1450 : ret.resize(buffer->size());
160 1450 : memcpy(ret.data(), buffer->data(), buffer->size());
161 1450 : return ret;
162 16525 : } else if (type == Vector) {
163 15075 : typename ValueType::BytesType ret(std::move(*buffer));
164 15075 : return ret;
165 15075 : }
166 0 : return typename ValueType::BytesType();
167 : }
168 :
169 : public: // CBOR format impl
170 3825 : inline void write(nullptr_t n) { _writeNull(*this, n); }
171 921250 : inline void write(bool value) { _writeBool(*this, value); }
172 533275 : inline void write(int64_t value) { _writeInt(*this, value); }
173 427418 : inline void write(double value) { _writeFloat(*this, value); }
174 13810929 : inline void write(const typename ValueType::StringType &str) { _writeString(*this, str); }
175 13100 : inline void write(const StringView &str) { _writeString(*this, str); }
176 426093 : inline void write(const typename ValueType::BytesType &data) { _writeBytes(*this, data); }
177 482775 : inline void onBeginArray(const typename ValueType::ArrayType &arr) { _writeArrayStart(*this, arr.size()); }
178 1375384 : inline void onBeginDict(const typename ValueType::DictionaryType &dict) { _writeMapStart(*this, dict.size()); }
179 :
180 : private:
181 : union {
182 : typename ValueType::BytesType *buffer;
183 : std::ofstream *file;
184 : const Callback<void(BytesView)> *stream;
185 : };
186 :
187 : Type type;
188 : };
189 :
190 :
191 : template <typename Interface>
192 : inline auto writeArray(const typename ValueTemplate<Interface>::ArrayType &arr) -> typename Interface::BytesType {
193 : return Encoder<Interface>::encode(arr);
194 : }
195 : template <typename Interface>
196 : inline auto writeObject(const typename ValueTemplate<Interface>::DictionaryType &dict) -> typename Interface::BytesType {
197 : return Encoder<Interface>::encode(dict);
198 : }
199 :
200 : template <typename Interface>
201 14700 : inline auto write(const ValueTemplate<Interface> &data, size_t reserve = 1_KiB) -> typename Interface::BytesType {
202 14700 : Encoder<Interface> enc(true, reserve);
203 14700 : if (enc.isOpen()) {
204 14700 : data.encode(enc);
205 14700 : return enc.data();
206 : }
207 0 : return typename Interface::BytesType();
208 14700 : }
209 :
210 : template <typename Interface>
211 0 : inline bool write(const Callback<void(BytesView)> &stream, const ValueTemplate<Interface> &data) {
212 0 : Encoder<Interface> enc(&stream);
213 0 : if (enc.isOpen()) {
214 0 : data.encode(enc);
215 0 : return true;
216 : }
217 0 : return false;
218 0 : }
219 :
220 : template <typename Interface>
221 75 : inline bool save(const ValueTemplate<Interface> &data, StringView file) {
222 75 : Encoder<Interface> enc(file);
223 75 : if (enc.isOpen()) {
224 75 : data.encode(enc);
225 75 : return true;
226 : }
227 0 : return false;
228 75 : }
229 :
230 : }
231 :
232 : #endif /* STAPPLER_DATA_SPDATAENCODECBOR_H_ */
|