1 #pragma once
2 
3 #include "dsx-ns.h"
4 #ifdef dsx
5 #include <iterator>
6 #include <type_traits>
7 #include "dxxsconf.h"
8 #include "object.h"
9 #include "segment.h"
10 
11 #ifndef DXX_SEGITER_DEBUG_OBJECT_LINKAGE
12 #	ifdef NDEBUG
13 #		define DXX_SEGITER_DEBUG_OBJECT_LINKAGE	0
14 #	else
15 #		define DXX_SEGITER_DEBUG_OBJECT_LINKAGE	1
16 #	endif
17 #endif
18 
19 #if DXX_SEGITER_DEBUG_OBJECT_LINKAGE
20 #include <cassert>
21 #endif
22 
23 namespace detail
24 {
25 
26 template <typename>
27 struct unspecified_pointer_t;
28 
29 };
30 
31 namespace dsx {
32 
33 template <typename T>
34 class segment_object_range_t
35 {
36 	class iterator;
37 	const iterator b;
38 public:
segment_object_range_t(iterator && o)39 	segment_object_range_t(iterator &&o) :
40 		b(std::move(o))
41 	{
42 	}
begin()43 	const iterator &begin() const { return b; }
end()44 	static iterator end() { return T(object_none, static_cast<typename T::allow_none_construction *>(nullptr)); }
45 	template <typename OF, typename SF>
construct(const unique_segment & s,OF & of,SF & sf)46 		static segment_object_range_t construct(const unique_segment &s, OF &of, SF &sf)
47 		{
48 			if (s.objects == object_none)
49 				return end();
50 			auto &&opi = of(s.objects);
51 			const object_base &o = opi;
52 #if DXX_SEGITER_DEBUG_OBJECT_LINKAGE
53 			/* Assert that the first object in the segment claims to be
54 			 * in the segment that claims to have that object.
55 			 */
56 			assert(&*sf(o.segnum) == &s);
57 			/* Assert that the first object in the segment agrees that there
58 			 * are no objects before it in the segment.
59 			 */
60 			assert(o.prev == object_none);
61 #endif
62 			/* Check that the supplied SF can produce `const unique_segment &`.
63 			 * In !NDEBUG builds, this would be checked as a side effect of the
64 			 * assert conditions.  In NDEBUG builds, it would not be checked.
65 			 *
66 			 * Wrap the expression in a sizeof to prevent the compiler from
67 			 * emitting code to implement the test.
68 			 */
69 			static_cast<void>(sizeof(&*sf(o.segnum) == &s));
70 			return iterator(std::move(opi));
71 		}
72 };
73 
74 template <typename T>
75 class segment_object_range_t<T>::iterator :
76 	T
77 {
78 	using T::m_ptr;
79 	using T::m_idx;
80 public:
81 	using iterator_category = std::forward_iterator_tag;
82 	using value_type = T;
83 	using difference_type = std::ptrdiff_t;
84 	using pointer = void;
85 	using reference = T;
iterator(T && o)86 	iterator(T &&o) :
87 		T(std::move(o))
88 	{
89 	}
90 	T operator *() const { return *this; }
91 	iterator &operator++()
92 	{
93 		const auto oi = m_idx;
94 		const auto op = m_ptr;
95 		const auto ni = op->next;
96 		m_idx = ni;
97 		/* If ni == object_none, then the iterator is at end() and there should
98 		 * be no further reads of m_ptr.  Optimizing compilers will typically
99 		 * recognize that setting m_ptr=nullptr in this case is unnecessary and
100 		 * omit the store.  Omit the nullptr assignment so that less optimizing
101 		 * compilers do not generate a useless branch.
102 		 */
103 		m_ptr += static_cast<std::size_t>(ni) - static_cast<std::size_t>(oi);
104 		if (ni != object_none)
105 		{
106 			/* If ni == object_none, then `m_ptr` is now invalid and these
107 			 * tests would be undefined.
108 			 */
109 #if DXX_SEGITER_DEBUG_OBJECT_LINKAGE
110 			/* Assert that the next object in the segment agrees that
111 			 * the preceding object is the previous object.
112 			 */
113 			assert(oi == m_ptr->prev);
114 			/* Assert that the old object and new object are in the same
115 			 * segment.
116 			 */
117 			assert(op->segnum == m_ptr->segnum);
118 #endif
119 		}
120 		return *this;
121 	}
122 	bool operator==(const iterator &rhs) const
123 	{
124 		return m_idx == rhs.m_idx;
125 	}
126 	bool operator!=(const iterator &rhs) const
127 	{
128 		return !(*this == rhs);
129 	}
130 };
131 
132 template <typename OF, typename SF, typename R = segment_object_range_t<decltype(std::declval<OF &>()(object_first))>>
133 [[nodiscard]]
objects_in(const unique_segment & s,OF & of,SF & sf)134 static inline R objects_in(const unique_segment &s, OF &of, SF &sf)
135 {
136 	return R::construct(s, of, sf);
137 }
138 
139 }
140 #endif
141