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 <cstring>
24#include <iostream>
25#include <memory>
26#include <string>
27#include <exception>
28
29#include "memory_operations.hpp"
30
31namespace datasketches {
32
34template<typename T, typename Enable = void> struct serde {
41 void serialize(std::ostream& os, const T* items, unsigned num) const;
42
49 void deserialize(std::istream& is, T* items, unsigned num) const;
50
58 size_t serialize(void* ptr, size_t capacity, const T* items, unsigned num) const;
59
67 size_t deserialize(const void* ptr, size_t capacity, T* items, unsigned num) const;
68
74 size_t size_of_item(const T& item) const;
75};
76
80template<typename T>
81struct serde<T, typename std::enable_if<std::is_arithmetic<T>::value>::type> {
83 void serialize(std::ostream& os, const T* items, unsigned num) const {
84 bool failure = false;
85 try {
86 os.write(reinterpret_cast<const char*>(items), sizeof(T) * num);
87 } catch (std::ostream::failure&) {
88 failure = true;
89 }
90 if (failure || !os.good()) {
91 throw std::runtime_error("error writing to std::ostream with " + std::to_string(num) + " items");
92 }
93 }
94
95 void deserialize(std::istream& is, T* items, unsigned num) const {
96 bool failure = false;
97 try {
98 is.read((char*)items, sizeof(T) * num);
99 } catch (std::istream::failure&) {
100 failure = true;
101 }
102 if (failure || !is.good()) {
103 throw std::runtime_error("error reading from std::istream with " + std::to_string(num) + " items");
104 }
105 }
106
108 size_t serialize(void* ptr, size_t capacity, const T* items, unsigned num) const {
109 const size_t bytes_written = sizeof(T) * num;
110 check_memory_size(bytes_written, capacity);
111 memcpy(ptr, items, bytes_written);
112 return bytes_written;
113 }
114
116 size_t deserialize(const void* ptr, size_t capacity, T* items, unsigned num) const {
117 const size_t bytes_read = sizeof(T) * num;
118 check_memory_size(bytes_read, capacity);
119 memcpy(items, ptr, bytes_read);
120 return bytes_read;
121 }
122
124 size_t size_of_item(const T& item) const {
125 unused(item);
126 return sizeof(T);
127 }
128};
129
135template<>
136struct serde<std::string> {
138 void serialize(std::ostream& os, const std::string* items, unsigned num) const {
139 unsigned i = 0;
140 bool failure = false;
141 try {
142 for (; i < num && os.good(); i++) {
143 uint32_t length = static_cast<uint32_t>(items[i].size());
144 os.write((char*)&length, sizeof(length));
145 os.write(items[i].c_str(), length);
146 }
147 } catch (std::ostream::failure&) {
148 failure = true;
149 }
150 if (failure || !os.good()) {
151 throw std::runtime_error("error writing to std::ostream at item " + std::to_string(i));
152 }
153 }
154
156 void deserialize(std::istream& is, std::string* items, unsigned num) const {
157 unsigned i = 0;
158 bool failure = false;
159 try {
160 for (; i < num; i++) {
161 uint32_t length;
162 is.read((char*)&length, sizeof(length));
163 if (!is.good()) { break; }
164 std::string str;
165 str.reserve(length);
166 for (uint32_t j = 0; j < length; j++) {
167 str.push_back(static_cast<char>(is.get()));
168 }
169 if (!is.good()) { break; }
170 new (&items[i]) std::string(std::move(str));
171 }
172 } catch (std::istream::failure&) {
173 failure = true;
174 }
175 if (failure || !is.good()) {
176 // clean up what we've already allocated
177 for (unsigned j = 0; j < i; ++j) {
178 items[j].~basic_string();
179 }
180 throw std::runtime_error("error reading from std::istream at item " + std::to_string(i));
181 }
182 }
183
185 size_t serialize(void* ptr, size_t capacity, const std::string* items, unsigned num) const {
186 size_t bytes_written = 0;
187 for (unsigned i = 0; i < num; ++i) {
188 const uint32_t length = static_cast<uint32_t>(items[i].size());
189 const size_t new_bytes = length + sizeof(length);
190 check_memory_size(bytes_written + new_bytes, capacity);
191 memcpy(ptr, &length, sizeof(length));
192 ptr = static_cast<char*>(ptr) + sizeof(uint32_t);
193 memcpy(ptr, items[i].c_str(), length);
194 ptr = static_cast<char*>(ptr) + length;
195 bytes_written += new_bytes;
196 }
197 return bytes_written;
198 }
199
201 size_t deserialize(const void* ptr, size_t capacity, std::string* items, unsigned num) const {
202 size_t bytes_read = 0;
203 unsigned i = 0;
204 bool failure = false;
205 for (; i < num && !failure; ++i) {
206 uint32_t length;
207 if (bytes_read + sizeof(length) > capacity) {
208 bytes_read += sizeof(length); // we'll use this to report the error
209 failure = true;
210 break;
211 }
212 memcpy(&length, ptr, sizeof(length));
213 ptr = static_cast<const char*>(ptr) + sizeof(uint32_t);
214 bytes_read += sizeof(length);
215
216 if (bytes_read + length > capacity) {
217 bytes_read += length; // we'll use this to report the error
218 failure = true;
219 break;
220 }
221 new (&items[i]) std::string(static_cast<const char*>(ptr), length);
222 ptr = static_cast<const char*>(ptr) + length;
223 bytes_read += length;
224 }
225
226 if (failure) {
227 // clean up what we've already allocated
228 for (unsigned j = 0; j < i; ++j)
229 items[j].~basic_string();
230 // using this for a consistent error message
231 check_memory_size(bytes_read, capacity);
232 }
233
234 return bytes_read;
235 }
236
238 size_t size_of_item(const std::string& item) const {
239 return sizeof(uint32_t) + item.size();
240 }
241};
242
243} /* namespace datasketches */
244
245# 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:124
size_t deserialize(const void *ptr, size_t capacity, T *items, unsigned num) const
Raw bytes deserialization.
Definition serde.hpp:116
void serialize(std::ostream &os, const T *items, unsigned num) const
Stream serialization.
Definition serde.hpp:83
size_t serialize(void *ptr, size_t capacity, const T *items, unsigned num) const
Raw bytes serialization.
Definition serde.hpp:108
void serialize(std::ostream &os, const std::string *items, unsigned num) const
Stream serialization.
Definition serde.hpp:138
size_t serialize(void *ptr, size_t capacity, const std::string *items, unsigned num) const
Raw bytes serialization.
Definition serde.hpp:185
size_t size_of_item(const std::string &item) const
Size of the given item.
Definition serde.hpp:238
size_t deserialize(const void *ptr, size_t capacity, std::string *items, unsigned num) const
Raw bytes deserialization.
Definition serde.hpp:201
void deserialize(std::istream &is, std::string *items, unsigned num) const
Stream deserialization.
Definition serde.hpp:156
Interface for serializing and deserializing items.
Definition serde.hpp:34
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.