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.
21template<typename NodeT>
22class BLZoneListNode {
23public:
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.
52template <typename NodeT>
53class BLZoneList {
54public:
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