pstore2
standard_types.hpp
Go to the documentation of this file.
1 //===- include/pstore/serialize/standard_types.hpp --------*- mode: C++ -*-===//
2 //* _ _ _ _ *
3 //* ___| |_ __ _ _ __ __| | __ _ _ __ __| | | |_ _ _ _ __ ___ ___ *
4 //* / __| __/ _` | '_ \ / _` |/ _` | '__/ _` | | __| | | | '_ \ / _ \/ __| *
5 //* \__ \ || (_| | | | | (_| | (_| | | | (_| | | |_| |_| | |_) | __/\__ \ *
6 //* |___/\__\__,_|_| |_|\__,_|\__,_|_| \__,_| \__|\__, | .__/ \___||___/ *
7 //* |___/|_| *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
18 
19 #ifndef PSTORE_SERIALIZE_STANDARD_TYPES_HPP
20 #define PSTORE_SERIALIZE_STANDARD_TYPES_HPP
21 
22 #include <atomic>
23 #include <map>
24 #include <set>
25 
28 
33 namespace pstore {
34  namespace serialize {
35 
36  struct string_helper {
51  template <typename Archive, typename StringType>
52  static auto write (Archive && archive, StringType const & str)
53  -> archive_result_type<Archive> {
54  auto const length = str.length ();
55 
56  // Encode the string length as a variable-length integer.
57  std::array<std::uint8_t, varint::max_output_length> encoded_length;
58  auto first = std::begin (encoded_length);
59  auto last = varint::encode (length, first);
60  auto length_bytes = std::distance (first, last);
61  PSTORE_ASSERT (length_bytes > 0 &&
62  static_cast<std::size_t> (length_bytes) <= encoded_length.size ());
63  if (length_bytes == 1) {
64  *(last++) = 0;
65  }
66  // Emit the string length.
67  auto const resl = serialize::write (std::forward<Archive> (archive),
68  gsl::make_span (&(*first), &(*last)));
69 
70  // Emit the string body.
71  serialize::write (std::forward<Archive> (archive), gsl::make_span (str));
72  return resl;
73  }
74 
75  template <typename Archive>
76  static std::size_t read_length (Archive && archive) {
77  std::array<std::uint8_t, varint::max_output_length> encoded_length{{0}};
78  // First read the two initial bytes. These contain the variable length value
79  // but might not be enough for the entire value.
80  static_assert (varint::max_output_length >= 2,
81  "maximum encoded varint length must be >= 2");
82  serialize::read_uninit (std::forward<Archive> (archive),
83  gsl::make_span (encoded_length.data (), 2));
84 
85  auto const varint_length = varint::decode_size (std::begin (encoded_length));
86  PSTORE_ASSERT (varint_length > 0);
87  // Was that initial read of 2 bytes enough? If not get the rest of the
88  // length value.
89  if (varint_length > 2) {
90  PSTORE_ASSERT (varint_length <= encoded_length.size ());
91  serialize::read_uninit (
92  std::forward<Archive> (archive),
93  gsl::make_span (encoded_length.data () + 2, varint_length - 2));
94  }
95 
96  return varint::decode (encoded_length.data (), varint_length);
97  }
98  };
99 
101  template <>
102  struct serializer<std::string> {
103  using value_type = std::string;
104 
106  template <typename Archive>
107  static auto write (Archive && archive, value_type const & str)
108  -> archive_result_type<Archive> {
109  return string_helper::write (std::forward<Archive> (archive), str);
110  }
111 
117  template <typename Archive>
118  static void read (Archive && archive, value_type & str) {
119  // Read the body of the string.
120  new (&str) value_type;
121 
122  // Deleter will ensure that the string is destroyed on exit if an exception is
123  // raised here.
124  auto dtor = [] (value_type * const p) {
125  using string = std::string;
126  p->~string ();
127  };
128  std::unique_ptr<value_type, decltype (dtor)> deleter (&str, dtor);
129 
130  auto const length = string_helper::read_length (std::forward<Archive> (archive));
131  str.resize (length);
132 
133 #ifdef PSTORE_HAVE_NON_CONST_STD_STRING_DATA
134  char * const data = str.data ();
135 #else
136  // TODO: this is technically undefined behaviour. Remove once we've got access to
137  // the C++17 library on our platforms.
138  auto * const data = const_cast<char *> (str.data ());
139 #endif
140  // Now read the body of the string.
141  serialize::read_uninit (
142  std::forward<Archive> (archive),
143  gsl::make_span (data, static_cast<std::ptrdiff_t> (length)));
144 
145  // Release ownership from the deleter so that the initialized object is returned to
146  // the caller.
147  deleter.release ();
148  }
149  };
150 
153  template <>
154  struct serializer<std::string const> {
155  using value_type = std::string;
156  template <typename Archive>
157  static auto write (Archive && archive, value_type const & str)
158  -> archive_result_type<Archive> {
159  return serializer::write (std::forward<Archive> (archive), str);
160  }
161  template <typename Archive>
162  static void read (Archive && archive, value_type & str) {
163  serialize::read_uninit (std::forward<Archive> (archive), str);
164  }
165  };
166 
170  template <typename Container>
172 
180 
181  template <typename Archive>
182  static auto write (Archive && archive, Container const & ty)
183  -> archive_result_type<Archive> {
184  // TODO: size_t is not a fixed-size type. Prefer uintXX_t.
185  auto result =
186  serialize::write (std::forward<Archive> (archive), std::size_t{ty.size ()});
187  for (typename Container::value_type const & m : ty) {
188  serialize::write (std::forward<Archive> (archive), m);
189  }
190  return result;
191  }
192 
193  using insert_callback = std::function<void (typename Container::value_type const &)>;
194 
205 
206  template <typename Archive>
207  static void read (Archive && archive, insert_callback inserter) {
208  Container result;
209  // TODO: size_t is not a fixed-size type. Prefer uintXX_t.
210  auto const num_members =
211  serialize::read<std::size_t> (std::forward<Archive> (archive));
212  auto num_read = std::size_t{0};
213  for (; num_read < num_members; ++num_read) {
214  inserter (serialize::read<typename Container::value_type> (
215  std::forward<Archive> (archive)));
216  }
217  }
218  };
219 
220 
222  template <typename T>
223  struct serializer<std::atomic<T>> {
224  using value_type = std::atomic<T>;
225 
232  template <typename Archive>
233  static auto write (Archive && archive, value_type const & value)
234  -> archive_result_type<Archive> {
235  return serialize::write (std::forward<Archive> (archive), value.load ());
236  }
237 
242  template <typename Archive>
243  static void read (Archive && archive, value_type & value) {
244  serialize::read_uninit<T> (std::forward<Archive> (archive), value);
245  }
246  };
247 
248 
250  template <typename T, typename U>
251  struct serializer<std::pair<T, U>> {
252  using value_type = std::pair<T, U>;
253 
261  template <typename Archive>
262  static auto write (Archive && archive, value_type const & value)
263  -> archive_result_type<Archive> {
264 
265  auto const result = serialize::write (std::forward<Archive> (archive), value.first);
266  serialize::write (std::forward<Archive> (archive), value.second);
267  return result;
268  }
269 
275  template <typename Archive>
276  static void read (Archive && archive, value_type & value) {
277  serialize::read_uninit (std::forward<Archive> (archive), value.first);
278  serialize::read_uninit (std::forward<Archive> (archive), value.second);
279  }
280  };
281  } // namespace serialize
282 } // namespace pstore
284 #endif // PSTORE_SERIALIZE_STANDARD_TYPES_HPP
Definition: standard_types.hpp:36
static void read(Archive &&archive, value_type &value)
Reads an instance of std::pair<> from an archive.
Definition: standard_types.hpp:276
static void read(Archive &&archive, value_type &value)
Reads an instance of std::atomic<> from an archive.
Definition: standard_types.hpp:243
The primary template for serialization of non standard layout types.
Definition: types.hpp:118
static auto write(Archive &&archive, value_type const &str) -> archive_result_type< Archive >
Writes an instance of std::string to an archive.
Definition: standard_types.hpp:107
static auto write(Archive &&archive, StringType const &str) -> archive_result_type< Archive >
Writes an instance of a string type (e.g.
Definition: standard_types.hpp:52
static auto write(Archive &&archive, Ty const &v) -> archive_result_type< Archive >
Writes an single value of type Ty to an archive.
Definition: types.hpp:133
A helper class which can be used to emit containers which have a size() method and which support the ...
Definition: standard_types.hpp:171
Definition: chunked_sequence.hpp:607
posix::deleter deleter
The cross-platform name for the deleter class.
Definition: file_posix.hpp:54
Provides serialization capabilities for trivial and user-defined types.
Ty read(Archive &&archive)
Read a single value from an archive.
Definition: types.hpp:412
Definition: nonpod2.cpp:40
static void read(Archive &&archive, value_type &str)
Reads an instance of std::string from an archiver.
Definition: standard_types.hpp:118
static auto write(Archive &&archive, value_type const &value) -> archive_result_type< Archive >
Writes an instance of std::pair<> to an archive.
Definition: standard_types.hpp:262
static auto write(Archive &&archive, Container const &ty) -> archive_result_type< Archive >
Writes the contents of a container to an archive.
Definition: standard_types.hpp:182
Implements a prefix-style variable-length integer.
static auto write(Archive &&archive, value_type const &value) -> archive_result_type< Archive >
Writes an instance of std::atomic<> to an archive.
Definition: standard_types.hpp:233
static void read(Archive &&archive, insert_callback inserter)
Reads the contents of a container from an archive.
Definition: standard_types.hpp:207