datasketches-cpp
Loading...
Searching...
No Matches
serde.hpp
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#ifndef DATASKETCHES_SERDE_HPP_
21#define DATASKETCHES_SERDE_HPP_
22
23#include <cstdint>
24#include <cstring>
25#include <iostream>
26#include <memory>
27#include <string>
28#include <exception>
29
30#include "memory_operations.hpp"
31
32namespace datasketches {
33
35template<typename T, typename Enable = void> struct serde {
42 void serialize(std::ostream& os, const T* items, unsigned num) const;
43
50 void deserialize(std::istream& is, T* items, unsigned num) const;
51
59 size_t serialize(void* ptr, size_t capacity, const T* items, unsigned num) const;
60
68 size_t deserialize(const void* ptr, size_t capacity, T* items, unsigned num) const;
69
75 size_t size_of_item(const T& item) const;
76};
77
81template<typename T>
82struct serde<T, typename std::enable_if<std::is_arithmetic<T>::value>::type> {
84 void serialize(std::ostream& os, const T* items, unsigned num) const {
85 bool failure = false;
86 try {
87 os.write(reinterpret_cast<const char*>(items), sizeof(T) * num);
88 } catch (std::ostream::failure&) {
89 failure = true;
90 }
91 if (failure || !os.good()) {
92 throw std::runtime_error("error writing to std::ostream with " + std::to_string(num) + " items");
93 }
94 }
95
96 void deserialize(std::istream& is, T* items, unsigned num) const {
97 bool failure = false;
98 try {
99 is.read((char*)items, sizeof(T) * num);
100 } catch (std::istream::failure&) {
101 failure = true;
102 }
103 if (failure || !is.good()) {
104 throw std::runtime_error("error reading from std::istream with " + std::to_string(num) + " items");
105 }
106 }
107
109 size_t serialize(void* ptr, size_t capacity, const T* items, unsigned num) const {
110 const size_t bytes_written = sizeof(T) * num;
111 check_memory_size(bytes_written, capacity);
112 memcpy(ptr, items, bytes_written);
113 return bytes_written;
114 }
115
117 size_t deserialize(const void* ptr, size_t capacity, T* items, unsigned num) const {
118 const size_t bytes_read = sizeof(T) * num;
119 check_memory_size(bytes_read, capacity);
120 memcpy(items, ptr, bytes_read);
121 return bytes_read;
122 }
123
125 size_t size_of_item(const T& item) const {
126 unused(item);
127 return sizeof(T);
128 }
129};
130
141template<>
142struct serde<std::string> {
144 void serialize(std::ostream& os, const std::string* items, unsigned num) const {
145 unsigned i = 0;
146 bool failure = false;
147 try {
148 for (; i < num && os.good(); i++) {
149 uint32_t length = static_cast<uint32_t>(items[i].size());
150 os.write((char*)&length, sizeof(length));
151 os.write(items[i].c_str(), length);
152 }
153 } catch (std::ostream::failure&) {
154 failure = true;
155 }
156 if (failure || !os.good()) {
157 throw std::runtime_error("error writing to std::ostream at item " + std::to_string(i));
158 }
159 }
160
162 void deserialize(std::istream& is, std::string* items, unsigned num) const {
163 unsigned i = 0;
164 bool failure = false;
165 try {
166 for (; i < num; i++) {
167 uint32_t length;
168 is.read((char*)&length, sizeof(length));
169 if (!is.good()) { break; }
170 std::string str;
171 str.reserve(length);
172 for (uint32_t j = 0; j < length; j++) {
173 str.push_back(static_cast<char>(is.get()));
174 }
175 if (!is.good()) { break; }
176 new (&items[i]) std::string(std::move(str));
177 }
178 } catch (std::istream::failure&) {
179 failure = true;
180 }
181 if (failure || !is.good()) {
182 // clean up what we've already allocated
183 for (unsigned j = 0; j < i; ++j) {
184 items[j].~basic_string();
185 }
186 throw std::runtime_error("error reading from std::istream at item " + std::to_string(i));
187 }
188 }
189
191 size_t serialize(void* ptr, size_t capacity, const std::string* items, unsigned num) const {
192 size_t bytes_written = 0;
193 for (unsigned i = 0; i < num; ++i) {
194 const uint32_t length = static_cast<uint32_t>(items[i].size());
195 const size_t new_bytes = length + sizeof(length);
196 check_memory_size(bytes_written + new_bytes, capacity);
197 memcpy(ptr, &length, sizeof(length));
198 ptr = static_cast<char*>(ptr) + sizeof(uint32_t);
199 memcpy(ptr, items[i].c_str(), length);
200 ptr = static_cast<char*>(ptr) + length;
201 bytes_written += new_bytes;
202 }
203 return bytes_written;
204 }
205
207 size_t deserialize(const void* ptr, size_t capacity, std::string* items, unsigned num) const {
208 size_t bytes_read = 0;
209 unsigned i = 0;
210 bool failure = false;
211 for (; i < num && !failure; ++i) {
212 uint32_t length;
213 if (bytes_read + sizeof(length) > capacity) {
214 bytes_read += sizeof(length); // we'll use this to report the error
215 failure = true;
216 break;
217 }
218 memcpy(&length, ptr, sizeof(length));
219 ptr = static_cast<const char*>(ptr) + sizeof(uint32_t);
220 bytes_read += sizeof(length);
221
222 if (bytes_read + length > capacity) {
223 bytes_read += length; // we'll use this to report the error
224 failure = true;
225 break;
226 }
227 new (&items[i]) std::string(static_cast<const char*>(ptr), length);
228 ptr = static_cast<const char*>(ptr) + length;
229 bytes_read += length;
230 }
231
232 if (failure) {
233 // clean up what we've already allocated
234 for (unsigned j = 0; j < i; ++j)
235 items[j].~basic_string();
236 // using this for a consistent error message
237 check_memory_size(bytes_read, capacity);
238 }
239
240 return bytes_read;
241 }
242
244 size_t size_of_item(const std::string& item) const {
245 return sizeof(uint32_t) + item.size();
246 }
247};
248
249} /* namespace datasketches */
250
251# endif
DataSketches namespace.
Definition binomial_bounds.hpp:38
size_t size_of_item(const T &item) const
Size of the given item.
Definition serde.hpp:125
size_t deserialize(const void *ptr, size_t capacity, T *items, unsigned num) const
Raw bytes deserialization.
Definition serde.hpp:117
void serialize(std::ostream &os, const T *items, unsigned num) const
Stream serialization.
Definition serde.hpp:84
size_t serialize(void *ptr, size_t capacity, const T *items, unsigned num) const
Raw bytes serialization.
Definition serde.hpp:109
void serialize(std::ostream &os, const std::string *items, unsigned num) const
Stream serialization.
Definition serde.hpp:144
size_t serialize(void *ptr, size_t capacity, const std::string *items, unsigned num) const
Raw bytes serialization.
Definition serde.hpp:191
size_t size_of_item(const std::string &item) const
Size of the given item.
Definition serde.hpp:244
size_t deserialize(const void *ptr, size_t capacity, std::string *items, unsigned num) const
Raw bytes deserialization.
Definition serde.hpp:207
void deserialize(std::istream &is, std::string *items, unsigned num) const
Stream deserialization.
Definition serde.hpp:162
Interface for serializing and deserializing items.
Definition serde.hpp:35
size_t size_of_item(const T &item) const
Size of the given item.
size_t deserialize(const void *ptr, size_t capacity, T *items, unsigned num) const
Raw bytes deserialization.
void deserialize(std::istream &is, T *items, unsigned num) const
Stream deserialization.
void serialize(std::ostream &os, const T *items, unsigned num) const
Stream serialization.
size_t serialize(void *ptr, size_t capacity, const T *items, unsigned num) const
Raw bytes serialization.