1/* -*- mode: c++; indent-tabs-mode: nil -*- */
5 Qore Programming Language
7 Copyright (C) 2003 - 2024 Qore Technologies, s.r.o.
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the "Software"),
11 to deal in the Software without restriction, including without limitation
12 the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 and/or sell copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
27 Note that the Qore library is released under a choice of three open-source
28 licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
32#ifndef _QORE_SAFE_DSLIST
34#define _QORE_SAFE_DSLIST
42//! defines a node in a safe_dslist
43template<typename T> hashdecl _qore_list_node {
44 typedef _qore_list_node self_t;
48 DLLLOCAL _qore_list_node(T d, self_t* n) {
52 DLLLOCAL _qore_list_node(T d) {
58//! defines an iterator for a safe_dslist
59template<typename T> hashdecl _qore_list_iterator {
60 typedef _qore_list_node<T> node_t;
61 typedef _qore_list_iterator<T> self_t;
66 DLLLOCAL _qore_list_iterator(node_t* n) {
69 DLLLOCAL _qore_list_iterator() {
72 DLLLOCAL self_t operator++(int) {
77 DLLLOCAL self_t operator++() {
81 DLLLOCAL T operator*() {
84 DLLLOCAL bool operator!=(const self_t& n) {
85 return n.node != node;
87 DLLLOCAL bool operator==(const self_t& n) {
88 return n.node == node;
92//! defines a const iterator for a safe_dslist
93template<typename T> hashdecl _qore_list_const_iterator {
94 typedef _qore_list_node<T> node_t;
95 typedef _qore_list_const_iterator<T> self_t;
100 DLLLOCAL _qore_list_const_iterator(_qore_list_iterator<T> i) {
103 DLLLOCAL _qore_list_const_iterator(const node_t* n) {
106 DLLLOCAL _qore_list_const_iterator() {
109 DLLLOCAL self_t operator++(int) {
114 DLLLOCAL self_t operator++() {
118 DLLLOCAL T operator*() const {
121 DLLLOCAL bool operator!=(const self_t& n) {
122 return n.node != node;
124 DLLLOCAL bool operator==(const self_t& n) {
125 return n.node == node;
129//! templated class for a double-ended singly-linked list that can be safely read from multiple threads without locking as long as writes are locked
131 Reading in multiple threads is safe as long as writes (appends at the end or beginning) are locked.
132 Implements a singly-linked list with constant-time inserts at the beginning and end that
133 can be read in a multi-threaded context without locking. Writes must be performed in a lock; however
134 this class does not provide any locking; locking must be provided and performed externally to the
135 class. Provides an STL-like interface.
137template<typename T> class safe_dslist {
139 typedef _qore_list_iterator<T> iterator;
140 typedef _qore_list_const_iterator<T> const_iterator;
141 typedef _qore_list_node<T> node_t;
142 typedef safe_dslist<T> self_t;
145 DLLLOCAL void clear_intern() {
155 node_t* head = nullptr,
159 DLLLOCAL safe_dslist() {
162 DLLLOCAL ~safe_dslist() {
167 DLLLOCAL void clear() {
169 head = tail = nullptr;
172 //! returns an iterator pointing to the first element of the list
173 DLLLOCAL iterator begin() {
177 //! returns an iterator pointing one element from the end of the list
178 DLLLOCAL iterator end() {
182 //! returns an iterator pointing to the first element of the list
183 DLLLOCAL const_iterator begin() const {
187 //! returns an iterator pointing one element from the end of the list
188 DLLLOCAL const_iterator end() const {
192 //! returns an iterator pointing to the last element in the list
193 DLLLOCAL iterator last() {
197 //! returns an iterator pointing to the last element in the list
198 DLLLOCAL const_iterator last() const {
202 //! returns an iterator either pointing to the element given if present in the list or pointing to one element from the end of the list if not
203 DLLLOCAL iterator find(T data) {
213 //! returns an iterator either pointing to the element given if present in the list or pointing to one element from the end of the list if not
214 DLLLOCAL const_iterator find(T data) const {
224 //! adds an element to the beginning of the list (constant time)
225 DLLLOCAL void push_front(T data) {
226 node_t* n = new node_t(data, head);
232 //! adds an element to the end of the list (constant time)
233 DLLLOCAL void push_back(T data) {
234 node_t* n = new node_t(data);
242 //! removes an element from the beginning of the list
243 DLLLOCAL void pop_front() {
253 //! concatenates all elements of this list to the end of the list passed
254 DLLLOCAL void populate(self_t& other) {
255 iterator i = begin();
262 //! concatenates all elements of this list to the end of the list passed
263 DLLLOCAL void populate(self_t* other) {
264 iterator i = begin();
266 other->push_back(*i);
271 //! returns true if the list is empty
272 DLLLOCAL bool empty() const {
276 //! returns true if the list contains only one element (constant time)
277 DLLLOCAL bool singular() const {
278 return head && head == tail;
281 //! returns true if the list contains more than one element (constant time)
282 DLLLOCAL bool plural() const {
286 //! deletes the list element after the iterator argument and all other elements to the end of the list
287 /** O(n) where n=length of list after the element given
288 @note does not erase the element given by the iterator argument
290 DLLLOCAL void erase_to_end(iterator i) {
296 node_t* w = i.node->next;
297 i.node->next = nullptr;
307 //! deletes the list element given by the iterator argument
308 /** only constant time for the first element in the list, otherwise is O(n), linear with the length of the list
310 DLLLOCAL void erase(iterator i) {
311 if (i.node == head) {
317 // find previous entry
319 while (n->next != i.node) {
322 n->next = i.node->next;
323 if (i.node == tail) {
330 DLLLOCAL size_t size() const {