pstore2
address.hpp
Go to the documentation of this file.
1 //===- include/pstore/core/address.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 //===----------------------------------------------------------------------===//
17 
18 // --> increasing addresses
19 //
20 // |<- j ->|<- j ->|
21 // |H| s(0) | s(1) | s(2) | s(3) | s(4) |T|
22 // |-------+-------+-------+-------+------+
23 // | region | region |
24 // | 0 | 1 |
25 
26 
27 // existing segments <---|---> new segments
28 // |<- j ->|<- j ->|
29 // |H| s(0) | s(1) | s(2) | s(3) | s(4) | s(n-1) | s(n) |T|
30 // |-------+-------+-------+-------+------+--------+---------+
31 // | region | region |region | region |
32 // | 0 | 1 | 2 | 3 |
33 
34 
35 // |<- j ->|<- j ->|
36 // | s(0) | s(1) | s(2) | s(3) | s(4) | s(n-1) | s(n) |
37 // |-----------------------+--------------+---------------+
38 // | region | region |
39 // | 0 | 1 |
40 // |-----------------------+--------------+---------------+
41 // | m | m | m | m |
42 // | 0 | 1 | 2 | 3 |
43 //
44 
45 // H is the file header
46 // j is 2^offset_number_bits
47 // s is a segment number
48 // m is an entry in the mapping table
49 
50 
51 
52 // Regions are used to limit the amount of contiguous address space that we request from the OS.
53 
54 // When I open the file, I divide the space into regions. On Windows, each region corresponds to
55 // a "file mapping". is memory mapped and then the underlying segment pointers are pushed onto
56 // the segment address table. Any remaining segments are then mapped and added to the table.
57 // (There isn't a one-to-one correspondence between regions or segments and "file mappings" (on
58 // Windows). file is modified we decide if a new segment needs to be created.
59 
60 #ifndef PSTORE_CORE_ADDRESS_HPP
61 #define PSTORE_CORE_ADDRESS_HPP
62 
63 #include <cstddef>
64 #include <cstdint>
65 #include <cstdlib>
66 #include <functional>
67 #include <limits>
68 #include <ostream>
69 #include <type_traits>
70 
72 
73 namespace pstore {
74 
75  //* _ _ *
76  //* __ _ __| | __| |_ __ ___ ___ ___ *
77  //* / _` |/ _` |/ _` | '__/ _ \/ __/ __| *
78  //* | (_| | (_| | (_| | | | __/\__ \__ \ *
79  //* \__,_|\__,_|\__,_|_| \___||___/___/ *
80  //* *
81  struct address {
83  static constexpr unsigned offset_number_bits = 22U;
85  static constexpr unsigned segment_number_bits = 16U;
86  static constexpr unsigned total_bits = offset_number_bits + segment_number_bits;
87 
88  using offset_type = std::uint_least32_t;
89  using segment_type = std::uint_least16_t;
90  using value_type = std::uint64_t;
91 
93  static constexpr offset_type const max_offset =
94  (UINT64_C (1) << offset_number_bits) - UINT64_C (1);
96  static constexpr segment_type const max_segment = (1U << segment_number_bits) - 1U;
98  static constexpr value_type const segment_size = value_type{max_offset} + UINT64_C (1);
99 
100  constexpr address () noexcept = default;
101  explicit constexpr address (value_type const absolute) noexcept
102  : a_{absolute} {}
103  constexpr address (segment_type const segment, offset_type const offset) noexcept
104  : a_{as_absolute (segment, offset)} {}
105 
106  static constexpr address null () noexcept { return address{0}; }
108  static constexpr address max () noexcept {
109  return address{(value_type{max_segment} << offset_number_bits) |
110  value_type{max_offset}};
111  }
112 
113  constexpr value_type absolute () const noexcept { return a_; }
114 
115  address operator++ () noexcept { return (*this) += 1U; }
116  address operator++ (int) noexcept {
117  auto const old = *this;
118  ++(*this);
119  return old;
120  }
121  address operator-- () noexcept { return (*this) -= 1U; }
122  address operator-- (int) noexcept {
123  auto const old = *this;
124  --(*this);
125  return old;
126  }
127 
128  address operator+= (value_type const distance) noexcept {
129  PSTORE_ASSERT (a_ <= std::numeric_limits<value_type>::max () - distance);
130  a_ += distance;
131  return *this;
132  }
133 
134  address operator-= (value_type const distance) noexcept {
135  PSTORE_ASSERT (a_ >= distance);
136  a_ -= distance;
137  return *this;
138  }
139 
140  address operator|= (value_type const mask) noexcept {
141  a_ |= mask;
142  return *this;
143  }
144 
145  address operator&= (value_type const mask) noexcept {
146  a_ &= mask;
147  return *this;
148  }
149 
150  constexpr segment_type segment () const noexcept {
151  return static_cast<segment_type> ((a_ >> offset_number_bits) & value_type{max_segment});
152  }
153 
154  constexpr offset_type offset () const noexcept {
155  return static_cast<offset_type> (a_ & max_offset);
156  }
157 
158  private:
159  value_type a_ = 0;
160 
161  static constexpr value_type as_absolute (segment_type const segment,
162  offset_type const offset) noexcept {
163  PSTORE_ASSERT (value_type{segment} <= max_segment + UINT64_C (1));
164  PSTORE_ASSERT (value_type{offset} <= max_offset + UINT64_C (1));
165  return (value_type{segment} << offset_number_bits) | value_type{offset};
166  }
167  };
168 
169  static_assert (alignof (address) == 8, "address should be 8 byte aligned");
170  static_assert (sizeof (address) == 8, "address should be 8 bytes wide");
171  static_assert (std::is_standard_layout<address>::value, "address is not standard layout");
172 
173  // comparison
174 
175  constexpr bool operator== (address const & lhs, address const & rhs) noexcept {
176  return lhs.absolute () == rhs.absolute ();
177  }
178  constexpr bool operator!= (address const & lhs, address const & rhs) noexcept {
179  return !operator== (lhs, rhs);
180  }
181 
182 
183  // ordering
184 
185  constexpr bool operator> (address const & lhs, address const & rhs) noexcept {
186  return lhs.absolute () > rhs.absolute ();
187  }
188  constexpr bool operator>= (address const & lhs, address const & rhs) noexcept {
189  return lhs.absolute () >= rhs.absolute ();
190  }
191  constexpr bool operator< (address const & lhs, address const & rhs) noexcept {
192  return lhs.absolute () < rhs.absolute ();
193  }
194  constexpr bool operator<= (address const & lhs, address const & rhs) noexcept {
195  return lhs.absolute () <= rhs.absolute ();
196  }
197 
198 
199  // arithmetic
200 
201  inline address operator- (address const lhs, address::value_type const rhs) noexcept {
202  PSTORE_ASSERT (lhs.absolute () >= rhs);
203  return address{lhs.absolute () - rhs};
204  }
205  inline address operator- (address const lhs, address const rhs) noexcept {
206  PSTORE_ASSERT (lhs.absolute () >= rhs.absolute ());
207  return address{lhs.absolute () - rhs.absolute ()};
208  }
209 
210  constexpr address operator+ (address const lhs, address::value_type const rhs) noexcept {
211  return address{lhs.absolute () + rhs};
212  }
213  constexpr address operator+ (address const lhs, address const rhs) noexcept {
214  return address{lhs.absolute () + rhs.absolute ()};
215  }
216 
217 
218  // bitwise
219 
220  constexpr address operator| (address const lhs, address::value_type const rhs) noexcept {
221  return address{lhs.absolute () | rhs};
222  }
223 
224  std::ostream & operator<< (std::ostream & os, address const & addr);
225 } // end namespace pstore
226 
227 
228 namespace pstore {
229 
230  template <typename T>
232  public:
233  static constexpr unsigned total_bits = address::total_bits;
234 
235  using type = T;
236 
237  constexpr typed_address () = default;
238  explicit constexpr typed_address (address const a) noexcept
239  : a_ (a) {}
240  typed_address (typed_address const & addr) noexcept = default;
241  typed_address (typed_address && addr) noexcept = default;
242  ~typed_address () noexcept = default;
243 
244  template <typename Other>
245  static constexpr typed_address cast (typed_address<Other> other) noexcept {
246  return typed_address{other.to_address ()};
247  }
248 
249  static constexpr typed_address null () noexcept { return typed_address{address::null ()}; }
250  static constexpr typed_address make (address a) noexcept { return typed_address{a}; }
251  static constexpr typed_address make (address::value_type const absolute) noexcept {
252  return typed_address{address{absolute}};
253  }
254 
255  typed_address & operator= (typed_address const & rhs) noexcept = default;
256  typed_address & operator= (typed_address && rhs) noexcept = default;
257 
258  constexpr bool operator== (typed_address const & rhs) const noexcept {
259  return a_ == rhs.a_;
260  }
261  constexpr bool operator!= (typed_address const & rhs) const noexcept {
262  return !operator== (rhs);
263  }
264 
265  typed_address operator++ () noexcept { return (*this) += 1U; }
266  typed_address operator++ (int) noexcept {
267  auto const old = *this;
268  ++(*this);
269  return old;
270  }
271  typed_address operator-- () noexcept { return (*this) -= 1U; }
272  typed_address operator-- (int) noexcept {
273  auto const old = *this;
274  --(*this);
275  return old;
276  }
277 
278  typed_address operator+= (std::uint64_t const distance) noexcept {
279  a_ += distance * sizeof (T);
280  return *this;
281  }
282  typed_address operator-= (std::uint64_t const distance) noexcept {
283  a_ -= distance * sizeof (T);
284  return *this;
285  }
286 
287  constexpr address to_address () const noexcept { return a_; }
288  constexpr address::value_type absolute () const noexcept { return a_.absolute (); }
289 
290  private:
291  address a_;
292  };
293 
294  // ordering
295 
296  template <typename T>
297  constexpr bool operator> (typed_address<T> lhs, typed_address<T> rhs) noexcept {
298  return lhs.to_address () > rhs.to_address ();
299  }
300  template <typename T>
301  constexpr bool operator>= (typed_address<T> lhs, typed_address<T> rhs) noexcept {
302  return lhs.to_address () >= rhs.to_address ();
303  }
304  template <typename T>
305  constexpr bool operator< (typed_address<T> lhs, typed_address<T> rhs) noexcept {
306  return lhs.to_address () < rhs.to_address ();
307  }
308  template <typename T>
309  constexpr bool operator<= (typed_address<T> lhs, typed_address<T> rhs) noexcept {
310  return lhs.to_address () <= rhs.to_address ();
311  }
312 
313  // arithmetic
314 
315  template <typename T>
316  inline typed_address<T> operator- (typed_address<T> const lhs,
317  std::uint64_t const rhs) noexcept {
318  auto const delta = rhs * sizeof (T);
319  PSTORE_ASSERT (lhs.absolute () >= delta);
320  return typed_address<T> (lhs.to_address () - delta);
321  }
322 
323  template <typename T>
324  inline typed_address<T> operator+ (typed_address<T> const lhs,
325  std::uint64_t const rhs) noexcept {
326  return typed_address<T>{address{lhs.absolute () + rhs * sizeof (T)}};
327  }
328 
329  template <typename T>
330  std::ostream & operator<< (std::ostream & os, typed_address<T> const & addr) {
331  return os << addr.to_address ();
332  }
333 
334 } // end namespace pstore
335 
336 
337 namespace std {
338  //* _ _ _ _ _ *
339  //* _ __ _ _ _ __ ___ ___ _ __(_) ___ | (_)_ __ ___ (_) |_ ___ *
340  //* | '_ \| | | | '_ ` _ \ / _ \ '__| |/ __| | | | '_ ` _ \| | __/ __| *
341  //* | | | | |_| | | | | | | __/ | | | (__ | | | | | | | | | |_\__ \ *
342  //* |_| |_|\__,_|_| |_| |_|\___|_| |_|\___| |_|_|_| |_| |_|_|\__|___/ *
343  //* *
344 
345  // (Strictly speaking, we should be providing const and volatile versions of this specialization
346  // as well.)
347  template <>
348  class numeric_limits<pstore::address> {
349  using base = std::numeric_limits<pstore::address::value_type>;
350  using type = pstore::address;
351 
352  public:
353  static constexpr const bool is_specialized = base::is_specialized;
354  static constexpr type min () noexcept { return pstore::address::null (); }
355  static constexpr type max () noexcept { return pstore::address::max (); }
356  static constexpr type lowest () noexcept { return pstore::address{base::lowest ()}; }
357 
358  static constexpr const int digits = base::digits;
359  static constexpr const int digits10 = base::digits10;
360  static constexpr const int max_digits10 = base::max_digits10;
361  static constexpr const bool is_signed = base::is_signed;
362  static constexpr const bool is_integer = base::is_integer;
363  static constexpr const bool is_exact = base::is_exact;
364  static constexpr const int radix = base::radix;
365  static constexpr type epsilon () noexcept { return pstore::address{base::epsilon ()}; }
366  static constexpr type round_error () noexcept {
367  return pstore::address{base::round_error ()};
368  }
369 
370  static constexpr const int min_exponent = base::min_exponent;
371  static constexpr const int min_exponent10 = base::min_exponent10;
372  static constexpr const int max_exponent = base::max_exponent;
373  static constexpr const int max_exponent10 = base::max_exponent10;
374 
375  static constexpr const bool has_infinity = base::has_infinity;
376  static constexpr const bool has_quiet_NaN = base::has_quiet_NaN; // NOLINT
377  static constexpr const bool has_signaling_NaN = base::has_signaling_NaN; // NOLINT
378  static constexpr const float_denorm_style has_denorm = base::has_denorm;
379  static constexpr const bool has_denorm_loss = base::has_denorm_loss;
380  static constexpr type infinity () noexcept { return pstore::address{base::infinity ()}; }
381  // NOLINTNEXTLINE(readability-identifier-naming)
382  static constexpr type quiet_NaN () noexcept {
383  // NOLINTNEXTLINE(readability-identifier-naming)
384  return pstore::address{base::quiet_NaN ()};
385  }
386  // NOLINTNEXTLINE(readability-identifier-naming)
387  static constexpr type signaling_NaN () noexcept {
388  // NOLINTNEXTLINE(readability-identifier-naming)
389  return pstore::address{base::signaling_NaN ()};
390  }
391  static constexpr type denorm_min () noexcept {
392  return pstore::address{base::denorm_min ()};
393  }
394 
395  static constexpr const bool is_iec559 = base::is_iec559;
396  static constexpr const bool is_bounded = base::is_bounded;
397  static constexpr const bool is_modulo = base::is_modulo;
398 
399  static constexpr const bool traps = base::traps;
400  static constexpr const bool tinyness_before = base::tinyness_before;
401  static constexpr const float_round_style round_style = base::round_style;
402  };
403 
404  //* _ _ *
405  //* | |__ __ _ ___ | |__ *
406  //* | '_ \ / _` |/ __|| '_ \ *
407  //* | | | || (_| |\__ \| | | | *
408  //* |_| |_| \__,_||___/|_| |_| *
409  //* *
410  template <>
411  struct hash<pstore::address> {
413  using result_type = std::size_t;
414 
415  result_type operator() (argument_type const s) const {
416  auto const abs = s.absolute ();
417  return std::hash<std::remove_const<decltype (abs)>::type>{}(abs);
418  }
419  };
420 
421  template <typename T>
422  struct hash<pstore::typed_address<T>> {
424  using result_type = std::size_t;
425 
426  result_type operator() (argument_type const s) const {
427  auto const addr = s.to_address ();
428  return std::hash<typename std::remove_const<decltype (addr)>::type>{}(addr);
429  }
430  };
431 
432 } // end namespace std
433 
434 
435 namespace pstore {
436 
440  template <typename T>
441  struct extent {
442  constexpr extent () noexcept;
445  constexpr extent (typed_address<T> const a, std::uint64_t const s) noexcept
446  : addr{a}
447  , size{s} {}
448  extent (extent const & rhs) noexcept = default;
449  extent (extent && rhs) noexcept = default;
450  ~extent () noexcept = default;
451 
452  extent & operator= (extent const &) noexcept = default;
453  extent & operator= (extent &&) noexcept = default;
454 
461  std::uint64_t size = UINT64_C (0);
462  };
463 
464  template <typename T>
465  static constexpr extent<T> make_extent (typed_address<T> a, std::uint64_t s) noexcept {
466  return {a, s};
467  }
468 
469  template <typename T>
470  constexpr extent<T>::extent () noexcept {
471  PSTORE_STATIC_ASSERT (offsetof (extent, addr) == 0);
472  PSTORE_STATIC_ASSERT (offsetof (extent, size) == 8);
473  PSTORE_STATIC_ASSERT (sizeof (extent) == 16);
474  }
475 
476  // comparison
477  template <typename T>
478  constexpr bool operator== (extent<T> const & lhs, extent<T> const & rhs) noexcept {
479  return lhs.addr == rhs.addr && lhs.size == rhs.size;
480  }
481  template <typename T>
482  constexpr bool operator!= (extent<T> const & lhs, extent<T> const & rhs) noexcept {
483  return !(lhs == rhs);
484  }
485 
486  // ordering
487  template <typename T>
488  constexpr bool operator< (extent<T> const & lhs, extent<T> const & rhs) noexcept {
489  return lhs.addr < rhs.addr || (lhs.addr == rhs.addr && lhs.size < rhs.size);
490  }
491  template <typename T>
492  constexpr bool operator>= (extent<T> const & lhs, extent<T> const & rhs) noexcept {
493  return !(lhs < rhs);
494  }
495  template <typename T>
496  constexpr bool operator> (extent<T> const & lhs, extent<T> const & rhs) noexcept {
497  return rhs < lhs;
498  }
499  template <typename T>
500  constexpr bool operator<= (extent<T> const & lhs, extent<T> const & rhs) noexcept {
501  return !(lhs > rhs);
502  }
503 
504  // output
505  template <typename T>
506  inline std::ostream & operator<< (std::ostream & os, extent<T> const & r) {
507  return os << "{addr:" << r.addr << ",size:" << r.size << "}";
508  }
509 
510 } // end namespace pstore
511 
512 #endif // PSTORE_CORE_ADDRESS_HPP
typed_address< T > addr
The address of the data associated with this extent.
Definition: address.hpp:456
An extent is a contiguous area of storage reserved for a data BLOB, represented as a range...
Definition: address.hpp:441
static constexpr offset_type const max_offset
The largest legal offset value.
Definition: address.hpp:93
Definition: address.hpp:81
static constexpr segment_type const max_segment
The largest legal segment value.
Definition: address.hpp:96
Definition: chunked_sequence.hpp:607
Definition: address.hpp:231
static constexpr unsigned segment_number_bits
A segment number is 0-2^16.
Definition: address.hpp:85
constexpr extent(typed_address< T > const a, std::uint64_t const s) noexcept
Definition: address.hpp:445
static constexpr unsigned offset_number_bits
An offset is 0-2^22 (4 megabytes)
Definition: address.hpp:83
Definition: nonpod2.cpp:40
static constexpr address max() noexcept
The largest legal absolute address.
Definition: address.hpp:108
An implementation of the standard assert() macro with the exception that it will, on failure...
static constexpr value_type const segment_size
The number of bytes in a segment.
Definition: address.hpp:98