1 | // [Blend2D] |
2 | // 2D Vector Graphics Powered by a JIT Compiler. |
3 | // |
4 | // [License] |
5 | // Zlib - See LICENSE.md file in the package. |
6 | |
7 | #ifndef BLEND2D_BLZONELIST_P_H |
8 | #define BLEND2D_BLZONELIST_P_H |
9 | |
10 | #include "./blapi-internal_p.h" |
11 | |
12 | //! \cond INTERNAL |
13 | //! \addtogroup blend2d_internal |
14 | //! \{ |
15 | |
16 | // ============================================================================ |
17 | // [BLZoneListNode] |
18 | // ============================================================================ |
19 | |
20 | //! Zone-allocated double-linked list node. |
21 | template<typename NodeT> |
22 | class BLZoneListNode { |
23 | public: |
24 | BL_NONCOPYABLE(BLZoneListNode) |
25 | |
26 | union { |
27 | NodeT* _listNodes[2]; |
28 | struct { |
29 | NodeT* _listPrev; |
30 | NodeT* _listNext; |
31 | }; |
32 | }; |
33 | |
34 | BL_INLINE BLZoneListNode() noexcept |
35 | : _listNodes { nullptr, nullptr } {} |
36 | |
37 | BL_INLINE BLZoneListNode(BLZoneListNode&& other) noexcept |
38 | : _listNodes { other._listNodes[0], other._listNodes[1] } {} |
39 | |
40 | BL_INLINE bool hasPrev() const noexcept { return _listPrev != nullptr; } |
41 | BL_INLINE bool hasNext() const noexcept { return _listNext != nullptr; } |
42 | |
43 | BL_INLINE NodeT* prev() const noexcept { return _listPrev; } |
44 | BL_INLINE NodeT* next() const noexcept { return _listNext; } |
45 | }; |
46 | |
47 | // ============================================================================ |
48 | // [BLZoneList<T>] |
49 | // ============================================================================ |
50 | |
51 | //! Zone-allocated double-linked list container. |
52 | template <typename NodeT> |
53 | class BLZoneList { |
54 | public: |
55 | BL_NONCOPYABLE(BLZoneList) |
56 | |
57 | NodeT* _nodes[2]; |
58 | |
59 | BL_INLINE BLZoneList() noexcept |
60 | : _nodes { nullptr, nullptr } {} |
61 | |
62 | BL_INLINE BLZoneList(BLZoneList&& other) noexcept |
63 | : _nodes { other._nodes[0], other._nodes[1] } {} |
64 | |
65 | BL_INLINE void swap(BLZoneList& other) noexcept { |
66 | std::swap(_nodes[0], other._nodes[0]); |
67 | std::swap(_nodes[1], other._nodes[1]); |
68 | } |
69 | |
70 | BL_INLINE void reset() noexcept { |
71 | _nodes[0] = nullptr; |
72 | _nodes[1] = nullptr; |
73 | } |
74 | |
75 | BL_INLINE bool empty() const noexcept { return _nodes[0] == nullptr; } |
76 | BL_INLINE NodeT* first() const noexcept { return _nodes[0]; } |
77 | BL_INLINE NodeT* last() const noexcept { return _nodes[1]; } |
78 | |
79 | // Can be used to both prepend and append. |
80 | BL_INLINE void _addNode(NodeT* node, size_t dir) noexcept { |
81 | NodeT* prev = _nodes[dir]; |
82 | |
83 | node->_listNodes[!dir] = prev; |
84 | _nodes[dir] = node; |
85 | if (prev) |
86 | prev->_listNodes[dir] = node; |
87 | else |
88 | _nodes[!dir] = node; |
89 | } |
90 | |
91 | // Can be used to both prepend and append. |
92 | BL_INLINE void _insertNode(NodeT* ref, NodeT* node, size_t dir) noexcept { |
93 | BL_ASSERT(ref != nullptr); |
94 | |
95 | NodeT* prev = ref; |
96 | NodeT* next = ref->_listNodes[dir]; |
97 | |
98 | prev->_listNodes[dir] = node; |
99 | if (next) |
100 | next->_listNodes[!dir] = node; |
101 | else |
102 | _nodes[dir] = node; |
103 | |
104 | node->_listNodes[!dir] = prev; |
105 | node->_listNodes[ dir] = next; |
106 | } |
107 | |
108 | BL_INLINE void append(NodeT* node) noexcept { _addNode(node, 1); } |
109 | BL_INLINE void prepend(NodeT* node) noexcept { _addNode(node, 0); } |
110 | |
111 | BL_INLINE void insertAfter(NodeT* ref, NodeT* node) noexcept { _insertNode(ref, node, 1); } |
112 | BL_INLINE void insertBefore(NodeT* ref, NodeT* node) noexcept { _insertNode(ref, node, 0); } |
113 | |
114 | BL_INLINE NodeT* unlink(NodeT* node) noexcept { |
115 | NodeT* prev = node->prev(); |
116 | NodeT* next = node->next(); |
117 | |
118 | if (prev) { prev->_listNext = next; node->_listPrev = nullptr; } else { _nodes[0] = next; } |
119 | if (next) { next->_listPrev = prev; node->_listNext = nullptr; } else { _nodes[1] = prev; } |
120 | |
121 | node->_listPrev = nullptr; |
122 | node->_listNext = nullptr; |
123 | |
124 | return node; |
125 | } |
126 | |
127 | BL_INLINE NodeT* popFirst() noexcept { |
128 | NodeT* node = _nodes[0]; |
129 | BL_ASSERT(node != nullptr); |
130 | |
131 | NodeT* next = node->next(); |
132 | _nodes[0] = next; |
133 | |
134 | if (next) { |
135 | next->_listPrev = nullptr; |
136 | node->_listNext = nullptr; |
137 | } |
138 | else { |
139 | _nodes[1] = nullptr; |
140 | } |
141 | |
142 | return node; |
143 | } |
144 | |
145 | BL_INLINE NodeT* pop() noexcept { |
146 | NodeT* node = _nodes[1]; |
147 | BL_ASSERT(node != nullptr); |
148 | |
149 | NodeT* prev = node->prev(); |
150 | _nodes[1] = prev; |
151 | |
152 | if (prev) { |
153 | prev->_listNext = nullptr; |
154 | node->_listPrev = nullptr; |
155 | } |
156 | else { |
157 | _nodes[0] = nullptr; |
158 | } |
159 | |
160 | return node; |
161 | } |
162 | }; |
163 | |
164 | //! \} |
165 | //! \endcond |
166 | |
167 | #endif // BLEND2D_BLZONELIST_P_H |
168 | |