diff --git a/src/util/IntrusiveList.hxx b/src/util/IntrusiveList.hxx index 54cab6933..e5af95e16 100644 --- a/src/util/IntrusiveList.hxx +++ b/src/util/IntrusiveList.hxx @@ -15,6 +15,14 @@ struct IntrusiveListOptions { bool constant_time_size = false; + + /** + * Initialize the list head with nullptr (all zeroes) which + * adds some code for checking nullptr, but may reduce the + * data section for statically allocated lists. It's a + * trade-off. + */ + bool zero_initialized = false; }; struct IntrusiveListNode { @@ -143,7 +151,9 @@ template counter; @@ -240,6 +250,10 @@ public: } constexpr bool empty() const noexcept { + if constexpr (options.zero_initialized) + if (head.next == nullptr) + return true; + return head.next == &head; } @@ -383,6 +397,10 @@ public: }; constexpr iterator begin() noexcept { + if constexpr (options.zero_initialized) + if (head.next == nullptr) + return end(); + return {head.next}; } @@ -454,6 +472,10 @@ public: }; constexpr const_iterator begin() const noexcept { + if constexpr (options.zero_initialized) + if (head.next == nullptr) + return end(); + return {head.next}; } @@ -498,6 +520,10 @@ public: GetHookMode() < IntrusiveHookMode::AUTO_UNLINK, "Can't use auto-unlink hooks with constant_time_size"); + if constexpr (options.zero_initialized) + if (head.next == nullptr) + head = {&head, &head}; + auto &existing_node = *p.cursor; auto &new_node = ToNode(t); @@ -535,6 +561,10 @@ public: if (_begin == _end) return; + if constexpr (options.zero_initialized) + if (head.next == nullptr) + head = {&head, &head}; + auto &next_node = *position.cursor; auto &prev_node = *std::prev(position).cursor;