pstore2
gsl.hpp
1 //===- include/pstore/support/gsl.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 #ifndef PSTORE_SUPPORT_GSL_HPP
17 #define PSTORE_SUPPORT_GSL_HPP
18 
19 #include <array>
20 #include <iterator>
21 #include <limits>
22 #include <memory>
23 #include <stdexcept>
24 #include <string>
25 #include <type_traits>
26 #include <utility>
27 #include <vector>
28 
30 
31 namespace pstore {
32  namespace gsl {
33  //
34  // czstring and wzstring
35  //
36  // These are "tag" typedef's for C-style strings (i.e. null-terminated character arrays)
37  // that allow static analysis to help find bugs.
38  //
39  // There are no additional features/semantics that we can find a way to add inside the
40  // type system for these types that will not either incur significant runtime costs or
41  // (sometimes needlessly) break existing programs when introduced.
42  //
43 
44  template <typename CharT>
45  using basic_zstring = CharT *;
46 
47  using zstring = basic_zstring<char>;
48  using wzstring = basic_zstring<wchar_t>;
49  using czstring = basic_zstring<char const>;
50  using cwzstring = basic_zstring<wchar_t const>;
51 
52 
53 
54  // [views.constants], constants
55  constexpr const std::ptrdiff_t dynamic_extent = -1;
56 
57  template <typename ElementType, std::ptrdiff_t Extent = dynamic_extent>
58  class span;
59 
60  // implementation details
61  namespace details {
62  template <typename Span, bool IsConst>
63  class span_iterator {
64  using element_type = typename Span::element_type;
65 
66  public:
67  using iterator_category = std::random_access_iterator_tag;
68  using value_type = typename std::remove_const<element_type>::type;
69  using difference_type = typename Span::index_type;
70 
71  using reference =
72  typename std::conditional<IsConst, element_type const, element_type>::type &;
73  using pointer = typename std::add_pointer<reference>::type;
74 
75  friend class span_iterator<Span, true>;
76 
77  constexpr span_iterator () noexcept = default;
78  constexpr span_iterator (Span const * span,
79  typename Span::index_type index) noexcept
80  : span_ (span)
81  , index_ (index) {
82  PSTORE_ASSERT (span == nullptr || (index_ >= 0 && index <= span_->length ()));
83  }
84  // Note that we allow non-const iterators to be assigned and constructed from
85  // const iterators, but not the other way round. We want to allow implicit
86  // conversions between span types.
87  // NOLINTNEXTLINE(hicpp-explicit-conversions)
88  constexpr span_iterator (span_iterator<Span, false> const & other) noexcept
89  : span_iterator (other.span_, other.index_) {}
90 
91  template <bool OtherIsConst = IsConst,
92  typename = typename std::enable_if<OtherIsConst>::type>
93  // NOLINTNEXTLINE(hicpp-explicit-conversions)
94  constexpr span_iterator (span_iterator<Span, true> const & other) noexcept
95  : span_iterator (other.span_, other.index_) {}
96 
97  span_iterator & operator= (span_iterator<Span, false> const & rhs) noexcept {
98  span_ = rhs.span_;
99  index_ = rhs.index_;
100  return *this;
101  }
102  template <bool OtherIsConst = IsConst,
103  typename = typename std::enable_if<OtherIsConst>::type>
104  span_iterator & operator= (span_iterator<Span, true> const & rhs) noexcept {
105  span_ = rhs.span_;
106  index_ = rhs.index_;
107  return *this;
108  }
109 
110  reference operator* () const {
111  PSTORE_ASSERT (span_);
112  return (*span_)[index_];
113  }
114 
115  pointer operator-> () const {
116  PSTORE_ASSERT (span_);
117  return &((*span_)[index_]);
118  }
119 
120  span_iterator & operator++ () noexcept {
121  PSTORE_ASSERT (span_ && index_ >= 0 && index_ < span_->length ());
122  ++index_;
123  return *this;
124  }
125 
126  span_iterator operator++ (int) noexcept {
127  auto ret = *this;
128  ++(*this);
129  return ret;
130  }
131 
132  span_iterator & operator-- () noexcept {
133  PSTORE_ASSERT (span_ && index_ > 0 && index_ <= span_->length ());
134  --index_;
135  return *this;
136  }
137 
138  span_iterator operator-- (int) const noexcept {
139  auto ret = *this;
140  --(*this);
141  return ret;
142  }
143 
144  span_iterator operator+ (difference_type n) const noexcept {
145  auto ret = *this;
146  return ret += n;
147  }
148 
149  span_iterator & operator+= (difference_type n) {
150  PSTORE_ASSERT (span_ && (index_ + n) >= 0 && (index_ + n) <= span_->length ());
151  index_ += n;
152  return *this;
153  }
154 
155  span_iterator & operator-= (difference_type n) noexcept { return *this += -n; }
156 
157  span_iterator operator- (difference_type n) const noexcept {
158  auto ret = *this;
159  return ret -= n;
160  }
161  difference_type operator- (span_iterator const & rhs) const {
162  PSTORE_ASSERT (span_ == rhs.span_);
163  return index_ - rhs.index_;
164  }
165 
166  constexpr reference operator[] (difference_type n) const noexcept {
167  return *(*this + n);
168  }
169 
170  constexpr friend bool operator== (span_iterator const & lhs,
171  span_iterator const & rhs) noexcept {
172  return lhs.span_ == rhs.span_ && lhs.index_ == rhs.index_;
173  }
174 
175  constexpr friend bool operator!= (span_iterator const & lhs,
176  span_iterator const & rhs) noexcept {
177  return !(lhs == rhs);
178  }
179 
180  friend bool operator< (span_iterator const & lhs, span_iterator const & rhs) {
181  PSTORE_ASSERT (lhs.span_ == rhs.span_);
182  return lhs.index_ < rhs.index_;
183  }
184 
185  friend bool operator<= (span_iterator const & lhs,
186  span_iterator const & rhs) noexcept {
187  return !(rhs < lhs);
188  }
189 
190  friend bool operator> (span_iterator const & lhs,
191  span_iterator const & rhs) noexcept {
192  return rhs < lhs;
193  }
194 
195  friend bool operator>= (span_iterator const & lhs,
196  span_iterator const & rhs) noexcept {
197  return !(rhs > lhs);
198  }
199 
200  void swap (span_iterator & rhs) noexcept {
201  std::swap (index_, rhs.index_);
202  std::swap (span_, rhs.span_);
203  }
204 
205  private:
206  Span const * span_ = nullptr;
207  std::ptrdiff_t index_ = 0;
208  };
209 
210  template <typename Span, bool IsConst>
212  operator+ (typename span_iterator<Span, IsConst>::difference_type n,
213  span_iterator<Span, IsConst> const & rhs) noexcept {
214  return rhs + n;
215  }
216 
217  template <typename Span, bool IsConst>
219  operator- (typename span_iterator<Span, IsConst>::difference_type n,
220  span_iterator<Span, IsConst> const & rhs) noexcept {
221  return rhs - n;
222  }
223 
224  template <std::ptrdiff_t Extent>
225  class extent_type {
226  public:
227  using index_type = std::ptrdiff_t;
228 
229  static_assert (Extent >= 0, "A fixed-size span must be >= 0 in size.");
230 
231  constexpr extent_type () noexcept = default;
232 
233  template <index_type Other>
234  constexpr explicit extent_type (extent_type<Other> ext) {
235  static_assert (
236  Other == Extent || Other == dynamic_extent,
237  "Mismatch between fixed-size extent and size of initializing data.");
238  (void) ext;
239  PSTORE_ASSERT (ext.size () == Extent);
240  }
241 
242  constexpr explicit extent_type (index_type const size) noexcept {
243  (void) size;
244  PSTORE_ASSERT (size == Extent);
245  }
246 
247  constexpr index_type size () const noexcept { return Extent; }
248  };
249 
250  template <>
251  class extent_type<dynamic_extent> {
252  public:
253  using index_type = std::ptrdiff_t;
254 
255  template <index_type Other>
256  constexpr explicit extent_type (extent_type<Other> const ext) noexcept
257  : size_ (ext.size ()) {}
258  constexpr explicit extent_type (index_type const size) noexcept
259  : size_ (size) {
260  PSTORE_ASSERT (size >= 0);
261  }
262  constexpr index_type size () const noexcept { return size_; }
263 
264  private:
265  index_type size_;
266  };
267  } // namespace details
268 
269 
270  // [span], class template span
271  template <typename ElementType, std::ptrdiff_t Extent>
272  class span {
273  public:
274  // constants and types
275  using element_type = ElementType;
276  using index_type = std::ptrdiff_t;
277  using pointer = element_type *;
278  using reference = element_type &;
279 
280  using iterator = details::span_iterator<span<ElementType, Extent>, false>;
281  using const_iterator = details::span_iterator<span<ElementType, Extent>, true>;
282  using reverse_iterator = std::reverse_iterator<iterator>;
283  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
284 
285  constexpr static index_type const extent = Extent;
286 
287  // [span.cons], span constructors, copy, assignment, and destructor
288  constexpr span () noexcept
289  : storage_ (nullptr, details::extent_type<0> ()) {}
290  constexpr explicit span (std::nullptr_t const) noexcept
291  : span () {}
292  constexpr span (pointer ptr, index_type count)
293  : storage_ (ptr, count) {}
294 
295  constexpr span (pointer first, pointer last)
296  : storage_ (first, std::distance (first, last)) {}
297 
298 
299  template <size_t N>
300  constexpr explicit span (element_type (&arr)[N]) noexcept
301  : storage_ (&arr[0], details::extent_type<N> ()) {}
302 
303  template <size_t N, class ArrayElementType = element_type>
304  constexpr explicit span (std::array<ArrayElementType, N> & arr) noexcept
305  : storage_ (&arr[0], details::extent_type<N> ()) {}
306 
307  template <size_t N, class ArrayElementType = element_type>
308  constexpr explicit span (std::array<ArrayElementType, N> const & arr) noexcept
309  : storage_ (&arr[0], details::extent_type<N> ()) {}
310 
311 
312  template <typename MemberType>
313  constexpr explicit span (std::vector<MemberType> & cont)
314  : span (cont.data (), static_cast<index_type> (cont.size ())) {}
315 
316  template <typename MemberType>
317  constexpr explicit span (std::vector<MemberType> const & cont)
318  : span (cont.data (), static_cast<index_type> (cont.size ())) {}
319 
320 
321  template <typename ArrayElementType = std::add_pointer<element_type>>
322  constexpr span (std::unique_ptr<ArrayElementType> const & ptr, index_type count)
323  : storage_ (ptr.get (), count) {}
324  constexpr explicit span (std::unique_ptr<element_type> const & ptr)
325  : storage_ (ptr.get (), ptr.get () ? 1 : 0) {}
326  constexpr explicit span (std::shared_ptr<element_type> const & ptr)
327  : storage_ (ptr.get (), ptr.get () ? 1 : 0) {}
328 
329 
330  template <typename OtherElementType, std::ptrdiff_t OtherExtent>
331  // NOLINTNEXTLINE(hicpp-explicit-conversions)
332  constexpr span (span<OtherElementType, OtherExtent> const & other)
333  : storage_ (other.data (), details::extent_type<OtherExtent> (other.size ())) {}
334 
335 
336  constexpr span (span const & other) noexcept = default;
337  constexpr span (span && other) noexcept = default;
338 
339  ~span () noexcept = default;
340  span & operator= (span const & other) noexcept = default;
341  span & operator= (span && other) noexcept = default;
342 
343  // [span.sub], span subviews
344  template <std::ptrdiff_t Count>
345  span<element_type, Count> first () const {
346  PSTORE_ASSERT (Count >= 0 && Count <= size ());
347  return {data (), Count};
348  }
349 
350  span<element_type, dynamic_extent> first (index_type count) const {
351  PSTORE_ASSERT (count >= 0 && count <= size ());
352  return {data (), count};
353  }
354 
355  template <std::ptrdiff_t Count>
356  span<element_type, Count> last () const {
357  PSTORE_ASSERT (Count >= 0 && Count <= size ());
358  return {data () + (size () - Count), Count};
359  }
360 
361  span<element_type, dynamic_extent> last (index_type count) const {
362  PSTORE_ASSERT (count >= 0 && count <= size ());
363  return {data () + (size () - count), count};
364  }
365 
366  template <std::ptrdiff_t Offset, std::ptrdiff_t Count = dynamic_extent>
367  span<element_type, Count> subspan () const {
368  PSTORE_ASSERT (
369  (Offset == 0 || (Offset > 0 && Offset <= size ())) &&
370  (Count == dynamic_extent || (Count >= 0 && Offset + Count <= size ())));
371  return {data () + Offset, Count == dynamic_extent ? size () - Offset : Count};
372  }
373 
375  subspan (index_type const offset, index_type const count = dynamic_extent) const
376  noexcept {
377  PSTORE_ASSERT (
378  (offset == 0 || (offset > 0 && offset <= size ())) &&
379  (count == dynamic_extent || (count >= 0 && offset + count <= size ())));
380  return {data () + offset, count == dynamic_extent ? size () - offset : count};
381  }
382 
383  // [span.obs], span observers
384  constexpr index_type length () const noexcept { return size (); }
385  constexpr index_type size () const noexcept { return storage_.size (); }
386  constexpr index_type length_bytes () const noexcept { return size_bytes (); }
387  constexpr index_type size_bytes () const noexcept {
388  return size () * static_cast<index_type> (sizeof (element_type));
389  }
390  constexpr bool empty () const noexcept { return size () == 0; }
391 
392  // [span.elem], span element access
393  reference operator[] (index_type const idx) const {
394  PSTORE_ASSERT (idx >= 0 && idx < storage_.size ());
395  return data ()[idx];
396  }
397 
398  constexpr reference at (index_type const idx) const { return this->operator[] (idx); }
399  constexpr reference operator() (index_type const idx) const {
400  return this->operator[] (idx);
401  }
402  constexpr pointer data () const noexcept { return storage_.data (); }
403 
404  // [span.iter], span iterator support
405  iterator begin () const noexcept { return {this, 0}; }
406  iterator end () const noexcept { return {this, length ()}; }
407 
408  const_iterator cbegin () const noexcept { return {this, 0}; }
409  const_iterator cend () const noexcept { return {this, length ()}; }
410 
411  reverse_iterator rbegin () const noexcept { return reverse_iterator{end ()}; }
412  reverse_iterator rend () const noexcept { return reverse_iterator{begin ()}; }
413 
414  const_reverse_iterator crbegin () const noexcept {
415  return const_reverse_iterator{cend ()};
416  }
417  const_reverse_iterator crend () const noexcept {
418  return const_reverse_iterator{cbegin ()};
419  }
420 
421  private:
422  // this implementation detail class lets us take advantage of the
423  // empty base class optimization to pay for only storage of a single
424  // pointer in the case of fixed-size spans
425  template <typename ExtentType>
426  class storage_type : public ExtentType {
427  public:
428  template <typename OtherExtentType>
429  constexpr storage_type (pointer data, OtherExtentType ext)
430  : ExtentType (ext)
431  , data_ (data) {}
432 
433  constexpr pointer data () const noexcept { return data_; }
434 
435  private:
436  pointer data_;
437  };
438 
439  storage_type<details::extent_type<Extent>> storage_;
440  };
441 
442  template <typename ElementType, std::ptrdiff_t Extent>
443  constexpr
444  typename span<ElementType, Extent>::index_type const span<ElementType, Extent>::extent;
445 
446 
447  // [span.comparison], span comparison operators
448  template <typename ElementType, std::ptrdiff_t FirstExtent, std::ptrdiff_t SecondExtent>
449  constexpr bool operator== (span<ElementType, FirstExtent> const & lhs,
450  span<ElementType, SecondExtent> const & rhs) {
451 
452  return lhs.size () == rhs.size () &&
453  std::equal (lhs.begin (), lhs.end (), rhs.begin ());
454  }
455 
456  template <typename ElementType, std::ptrdiff_t Extent>
457  constexpr bool operator!= (span<ElementType, Extent> const & lhs,
458  span<ElementType, Extent> const & rhs) {
459  return !(lhs == rhs);
460  }
461 
462  template <typename ElementType, std::ptrdiff_t Extent>
463  constexpr bool operator< (span<ElementType, Extent> const & lhs,
464  span<ElementType, Extent> const & rhs) {
465  return std::lexicographical_compare (lhs.begin (), lhs.end (), rhs.begin (),
466  rhs.end ());
467  }
468 
469  template <typename ElementType, std::ptrdiff_t Extent>
470  constexpr bool operator<= (span<ElementType, Extent> const & lhs,
471  span<ElementType, Extent> const & rhs) {
472  return !(lhs > rhs);
473  }
474 
475  template <typename ElementType, std::ptrdiff_t Extent>
476  constexpr bool operator> (span<ElementType, Extent> const & lhs,
477  span<ElementType, Extent> const & rhs) {
478  return rhs < lhs;
479  }
480 
481  template <typename ElementType, std::ptrdiff_t Extent>
482  constexpr bool operator>= (span<ElementType, Extent> const & lhs,
483  span<ElementType, Extent> const & rhs) {
484  return !(lhs < rhs);
485  }
486 
487 
488  namespace details {
489  // if we only supported compilers with good constexpr support then
490  // this pair of classes could collapse down to a constexpr function
491 
492  // we should use a narrow_cast<> to go to size_t, but older compilers may not see it as
493  // constexpr and so will fail compilation of the template
494  template <typename ElementType, std::ptrdiff_t Extent>
496  : std::integral_constant<std::ptrdiff_t,
497  static_cast<std::ptrdiff_t> (
498  sizeof (ElementType) *
499  static_cast<std::size_t> (Extent))> {};
500 
501  template <typename ElementType>
502  struct calculate_byte_size<ElementType, dynamic_extent>
503  : std::integral_constant<std::ptrdiff_t, dynamic_extent> {};
504  } // namespace details
505 
506  // [span.objectrep], views of object representation
507  template <typename ElementType, std::ptrdiff_t Extent>
509  as_bytes (span<ElementType, Extent> s) noexcept {
510  return {reinterpret_cast<std::uint8_t const *> (s.data ()), s.size_bytes ()};
511  }
512 
513  template <typename ElementType, std::ptrdiff_t Extent,
514  class = typename std::enable_if<!std::is_const<ElementType>::value>::type>
516  as_writeable_bytes (span<ElementType, Extent> s) noexcept {
517  return {reinterpret_cast<std::uint8_t *> (s.data ()), s.size_bytes ()};
518  }
519 
520 
521  //
522  // make_span() - Utility functions for creating spans
523  //
524  template <typename ElementType>
525  span<ElementType> make_span (ElementType * ptr,
526  typename span<ElementType>::index_type count) {
527  return span<ElementType> (ptr, count);
528  }
529 
530  template <typename ElementType>
531  span<ElementType> make_span (ElementType * first, ElementType * last) {
532  return span<ElementType> (first, last);
533  }
534 
535  template <typename ElementType, std::size_t N>
536  span<ElementType, N> make_span (ElementType (&arr)[N]) {
537  return span<ElementType, N>{arr};
538  }
539 
540 
541  template <typename ValueType, std::size_t N>
542  span<ValueType, N> make_span (std::array<ValueType, N> & cont) {
543  return span<ValueType, N>{cont};
544  }
545  template <typename ValueType, std::size_t N>
546  span<ValueType const, N> make_span (std::array<ValueType, N> const & cont) {
547  return span<ValueType const, N>{cont};
548  }
549 
550 
551 
552  template <typename Container>
553  span<typename Container::value_type> make_span (Container & c) {
554  return {c.data (), static_cast<std::ptrdiff_t> (c.size ())};
555  }
556  template <typename Container>
557  span<typename Container::value_type const> make_span (Container const & c) {
558  return {c.data (), static_cast<std::ptrdiff_t> (c.size ())};
559  }
560 
561 
562 
563  template <typename SmartPtr>
564  span<typename SmartPtr::element_type> make_span (SmartPtr & cont, std::ptrdiff_t count) {
565  return {cont, count};
566  }
567 
568  template <typename SmartPtr>
569  span<typename SmartPtr::element_type> make_span (SmartPtr & cont) {
571  }
572 
573 
574  //
575  // not_null
576  //
577  // Restricts a pointer or smart pointer to only hold non-null values.
578  //
579  // Has zero size overhead over T.
580  //
581  // If T is a pointer (i.e. T == U*) then
582  // - allow construction from U* or U&
583  // - disallow construction from nullptr_t
584  // - disallow default construction
585  // - ensure construction from U* fails with nullptr
586  // - allow implicit conversion to U*
587  //
588  template <typename T>
589  class not_null {
590  static_assert (std::is_assignable<T &, std::nullptr_t>::value,
591  "T cannot be assigned nullptr.");
592 
593  public:
594  // NOLINTNEXTLINE(hicpp-explicit-conversions)
595  constexpr not_null (T const t) noexcept
596  : ptr_{t} {
597  ensure_invariant ();
598  }
599 
600  // prevents compilation when someone attempts to assign a nullptr
601  not_null (std::nullptr_t) noexcept = delete;
602  not_null (int) noexcept = delete;
603  not_null (not_null const &) noexcept = default;
604  not_null (not_null &&) noexcept = default;
605 
606  ~not_null () noexcept = default;
607 
608  not_null & operator= (not_null const &) noexcept = default;
609  not_null & operator= (not_null &&) noexcept = default;
610  not_null & operator= (T const & t) noexcept {
611  ptr_ = t;
612  ensure_invariant ();
613  return *this;
614  }
615 
616  // prevents compilation when someone attempts to assign a nullptr
617  not_null<T> & operator= (std::nullptr_t) = delete;
618  not_null<T> & operator= (int) = delete;
619 
620  constexpr T get () const noexcept { return ptr_; }
621 
622  // NOLINTNEXTLINE(hicpp-explicit-conversions)
623  constexpr operator T () const noexcept { return get (); }
624  constexpr T operator-> () const noexcept { return get (); }
625 
626  bool operator== (T const & rhs) const noexcept { return ptr_ == rhs; }
627  bool operator!= (T const & rhs) const noexcept { return !(*this == rhs); }
628 
629  // unwanted operators...pointers only point to single objects!
630  // TODO ensure all arithmetic ops on this type are unavailable
631  not_null<T> & operator++ () = delete;
632  not_null<T> & operator-- () = delete;
633  not_null<T> operator++ (int) = delete;
634  not_null<T> operator-- (int) = delete;
635  not_null<T> & operator+ (size_t) = delete;
636  not_null<T> & operator+= (size_t) = delete;
637  not_null<T> & operator- (size_t) = delete;
638  not_null<T> & operator-= (size_t) = delete;
639 
640  private:
641  T ptr_;
642 
643  // We assume that the compiler can hoist/prove away most of the checks inlined from this
644  // function. If not, we could make them optional via conditional compilation.
645  constexpr void ensure_invariant () const noexcept { PSTORE_ASSERT (ptr_ != nullptr); }
646  };
647 
648 
649  //
650  // at() - Bounds-checked way of accessing static arrays, std::array, std::vector
651  //
652  template <typename T, size_t N>
653  constexpr T & at (T (&arr)[N], std::ptrdiff_t const index) {
654  PSTORE_ASSERT (index >= 0 && index < static_cast<std::ptrdiff_t> (N));
655  return arr[static_cast<size_t> (index)];
656  }
657 
658  template <typename T, size_t N>
659  constexpr T & at (std::array<T, N> & arr, std::ptrdiff_t const index) {
660  PSTORE_ASSERT (index >= 0 && index < static_cast<std::ptrdiff_t> (N));
661  return arr[static_cast<size_t> (index)];
662  }
663 
664  template <typename Cont>
665  constexpr typename Cont::value_type & at (Cont & cont, std::ptrdiff_t const index) {
666  PSTORE_ASSERT (index >= 0 && index < static_cast<std::ptrdiff_t> (cont.size ()));
667  return cont[static_cast<typename Cont::size_type> (index)];
668  }
669 
670  template <typename T>
671  constexpr T const & at (std::initializer_list<T> cont, std::ptrdiff_t const index) {
672  PSTORE_ASSERT (index >= 0 && index < static_cast<std::ptrdiff_t> (cont.size ()));
673  return *(cont.begin () + index);
674  }
675 
676  } // namespace gsl
677 } // end namespace pstore
678 
679 #endif // PSTORE_SUPPORT_GSL_HPP
Definition: gsl.hpp:58
An extent is a contiguous area of storage reserved for a data BLOB, represented as a range...
Definition: address.hpp:441
transaction< transaction_lock > begin(database &db, transaction_lock &lock)
Creates a new transaction. Every operation performed on a transaction instance can be potentially und...
Definition: transaction.hpp:311
Definition: gsl.hpp:225
Definition: gsl.hpp:589
Definition: print.cpp:18
Definition: nonpod2.cpp:40
An implementation of the standard assert() macro with the exception that it will, on failure...