pstore2
indirect_string.hpp
1 //===- include/pstore/core/indirect_string.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 //===----------------------------------------------------------------------===//
16 
17 #ifndef PSTORE_CORE_INDIRECT_STRING_HPP
18 #define PSTORE_CORE_INDIRECT_STRING_HPP
19 
20 #include <memory>
21 
23 
24 namespace pstore {
25 
26  //* _ _ _ _ _ _ *
27  //* (_)_ _ __| (_)_ _ ___ __| |_ __| |_ _ _(_)_ _ __ _ *
28  //* | | ' \/ _` | | '_/ -_) _| _| (_-< _| '_| | ' \/ _` | *
29  //* |_|_||_\__,_|_|_| \___\__|\__| /__/\__|_| |_|_||_\__, | *
30  //* |___/ *
31 
45  friend struct serialize::serializer<indirect_string>;
46 
47  public:
48  constexpr indirect_string (database const & db, address const addr) noexcept
49  : db_{db}
50  , is_pointer_{false}
51  , address_{addr.absolute ()} {}
52  constexpr indirect_string (database const & db,
53  gsl::not_null<raw_sstring_view const *> const str) noexcept
54  : db_{db}
55  , is_pointer_{true}
56  , str_{str} {
57  PSTORE_ASSERT ((reinterpret_cast<std::uintptr_t> (str.get ()) & in_heap_mask) == 0);
58  }
59 
60  bool operator== (indirect_string const & rhs) const;
61  bool operator!= (indirect_string const & rhs) const { return !operator== (rhs); }
62  bool operator< (indirect_string const & rhs) const;
63 
64  raw_sstring_view as_string_view (gsl::not_null<shared_sstring_view *> owner) const;
65 
66  std::size_t length () const;
67 
72  if (!is_in_store ()) {
73  raise (error_code::bad_address);
74  }
75  return this->as_string_view (owner);
76  }
77 
78  std::string to_string () const {
79  shared_sstring_view owner;
80  return this->as_string_view (&owner).to_string ();
81  }
82 
84  constexpr bool is_in_store () const noexcept {
85  return !is_pointer_ && !(address_ & in_heap_mask);
86  }
87 
89  constexpr address in_store_address () const noexcept {
90  PSTORE_ASSERT (this->is_in_store ());
91  return address{address_};
92  }
93 
103  raw_sstring_view const & str,
104  typed_address<address> address_to_patch);
105 
107  static indirect_string read (database const & db, typed_address<indirect_string> addr);
108 
109  private:
110  static constexpr std::uint64_t in_heap_mask = 0x01;
111  bool equal_contents (indirect_string const & rhs) const;
112 
113  database const & db_;
114  // TODO: replace with std::variant<>...?
118  bool is_pointer_;
119  union {
120  address::value_type address_;
122  };
123  };
124 
125  template <typename OStream>
126  OStream & operator<< (OStream & os, indirect_string const & ind_str) {
127  shared_sstring_view owner;
128  return os << ind_str.as_string_view (&owner);
129  }
130 
131 
132  namespace serialize {
133 
138  template <>
140  using value_type = indirect_string;
141 
148  static auto write (archive::database_writer && archive, value_type const & value)
149  -> archive_result_type<archive::database_writer> {
150  return write_string_address (archive, value);
151  }
152 
159  static auto write (archive::database_writer & archive, value_type const & value)
160  -> archive_result_type<archive::database_writer> {
161  return write_string_address (archive, value);
162  }
163 
164 
171  static void read (archive::database_reader & archive, value_type & value);
172 
179  static void read (archive::database_reader && archive, value_type & value);
180 
181  private:
182  template <typename DBArchive>
183  static auto write_string_address (DBArchive && archive, value_type const & value)
184  -> archive_result_type<DBArchive>;
185 
186  template <typename DBArchive>
187  static void read_string_address (DBArchive && archive, value_type & value);
188  };
189 
190  // write_string_address
191  // ~~~~~~~~~~~~~~~~~~~~
192  template <typename DBArchive>
193  auto serializer<indirect_string>::write_string_address (DBArchive && archive,
194  value_type const & value)
195  -> archive_result_type<DBArchive> {
196 
197  // The body of an indirect string must be written separately by the caller.
198  PSTORE_ASSERT (value.is_pointer_);
199  constexpr auto mask = indirect_string::in_heap_mask;
200  PSTORE_ASSERT (!(reinterpret_cast<std::uintptr_t> (value.str_) & mask));
201 
202  return archive.put (address{reinterpret_cast<std::uintptr_t> (value.str_) | mask});
203  }
204 
205  } // end namespace serialize
206 } // end namespace pstore
207 
208 namespace std {
209 
210  template <>
211  struct hash<::pstore::indirect_string> {
212  size_t operator() (::pstore::indirect_string const & str) const {
214  return std::hash<pstore::raw_sstring_view>{}(str.as_string_view (&owner));
215  }
216  };
217 
218 } // namespace std
219 
220 namespace pstore {
221 
222  //* _ _ _ _ _ _ _ _ *
223  //* (_)_ _ __| (_)_ _ ___ __| |_ __| |_ _ _(_)_ _ __ _ __ _ __| |__| |___ _ _ *
224  //* | | ' \/ _` | | '_/ -_) _| _| (_-< _| '_| | ' \/ _` | / _` / _` / _` / -_) '_| *
225  //* |_|_||_\__,_|_|_| \___\__|\__| /__/\__|_| |_|_||_\__, | \__,_\__,_\__,_\___|_| *
226  //* |___/ *
227 
236  public:
237  indirect_string_adder () = default;
241  explicit indirect_string_adder (std::size_t expected_size);
242 
243  template <typename Index>
244  std::pair<typename Index::iterator, bool> add (transaction_base & transaction,
245  std::shared_ptr<Index> const & index,
247 
248  void flush (transaction_base & transaction);
249 
250  private:
251  std::vector<std::pair<raw_sstring_view const *, typed_address<address>>> views_;
252  };
253 
254  // add
255  // ~~~
256  template <typename Index>
257  std::pair<typename Index::iterator, bool>
258  indirect_string_adder::add (transaction_base & transaction,
259  std::shared_ptr<Index> const & index,
261 
262  // Inserting into the index immediately writes the indirect_string instance to the store if
263  // the string isn't already in the set.
264  auto res = index->insert (transaction, pstore::indirect_string{transaction.db (), str});
265  if (res.second) {
266  // Now the in-store addresses are pointing at the sstring_view instances on the heap.
267  // If the string was written, we remember where it went.
268  typename Index::iterator const & pos = res.first;
269  views_.emplace_back (str, typed_address<address>::make (pos.get_address ()));
270  }
271  return res;
272  }
273 
274  //* _ _ __ _ _ *
275  //* | |_ ___| |_ __ ___ _ _ / _|_ _ _ _ __| |_(_)___ _ _ *
276  //* | ' \/ -_) | '_ \/ -_) '_| | _| || | ' \/ _| _| / _ \ ' \ *
277  //* |_||_\___|_| .__/\___|_| |_| \_,_|_||_\__|\__|_\___/_||_| *
278  //* |_| *
279 
284  raw_sstring_view get_sstring_view (database const & db,
287 
292  raw_sstring_view get_sstring_view (database const & db, address addr,
294 
300  raw_sstring_view get_sstring_view (database const & db, address addr, std::size_t length,
302 
303 } // end namespace pstore
304 
305 #endif // PSTORE_CORE_INDIRECT_STRING_HPP
address::value_type address_
The in-store/in-heap string address.
Definition: indirect_string.hpp:120
The primary template for serialization of non standard layout types.
Definition: types.hpp:118
An archive-reader which reads data from a database.
Definition: db_archive.hpp:102
constexpr bool is_in_store() const noexcept
Definition: indirect_string.hpp:84
Definition: address.hpp:81
constexpr address in_store_address() const noexcept
Definition: indirect_string.hpp:89
The string address can come in three forms:
Definition: indirect_string.hpp:44
Definition: chunked_sequence.hpp:607
raw_sstring_view const * str_
The address of the in-heap string.
Definition: indirect_string.hpp:121
Definition: transaction.hpp:191
Definition: address.hpp:231
Definition: gsl.hpp:589
static indirect_string read(database const &db, typed_address< indirect_string > addr)
Reads an indirect string from the store.
Definition: indirect_string.cpp:151
static auto write(archive::database_writer &archive, value_type const &value) -> archive_result_type< archive::database_writer >
Writes an instance of indirect_string to an archiver.
Definition: indirect_string.hpp:159
indirect_string_adder is a helper class which handles the details of adding strings to the "indirect"...
Definition: indirect_string.hpp:235
static address write_body_and_patch_address(transaction_base &transaction, raw_sstring_view const &str, typed_address< address > address_to_patch)
Write the body of a string and updates the indirect pointer so that it points to that body...
Definition: indirect_string.cpp:95
Definition: nonpod2.cpp:40
Definition: database.hpp:40
Definition: db_archive.hpp:78
Definition: sstring_view.hpp:113
raw_sstring_view as_db_string_view(gsl::not_null< shared_sstring_view *> const owner) const
When it is known that the string body is a store address use this function to carry out additional ch...
Definition: indirect_string.hpp:71
Defines serializer<> specializations for strings.
The database transaction class.
Definition: transaction.hpp:43
static auto write(archive::database_writer &&archive, value_type const &value) -> archive_result_type< archive::database_writer >
Writes an instance of indirect_string to an archiver.
Definition: indirect_string.hpp:148