mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-29 09:56:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			563 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			563 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*****************************************************************************
 | |
| 
 | |
| Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
 | |
| Copyright (c) 2019, 2022, MariaDB Corporation.
 | |
| 
 | |
| This program is free software; you can redistribute it and/or modify it under
 | |
| the terms of the GNU General Public License as published by the Free Software
 | |
| Foundation; version 2 of the License.
 | |
| 
 | |
| This program is distributed in the hope that it will be useful, but WITHOUT
 | |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | |
| FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License along with
 | |
| this program; if not, write to the Free Software Foundation, Inc.,
 | |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
 | |
| 
 | |
| *****************************************************************************/
 | |
| 
 | |
| /******************************************************************//**
 | |
| @file include/ut0lst.h
 | |
| List utilities
 | |
| 
 | |
| Created 9/10/1995 Heikki Tuuri
 | |
| Rewritten by Sunny Bains Dec 2011.
 | |
| ***********************************************************************/
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| /* Do not include univ.i because univ.i includes this. */
 | |
| 
 | |
| #include "ut0dbg.h"
 | |
| 
 | |
| /* This module implements the two-way linear list. Note that a single
 | |
| list node may belong to two or more lists, but is only on one list
 | |
| at a time. */
 | |
| 
 | |
| /*******************************************************************//**
 | |
| The two way list node.
 | |
| @param TYPE the list node type name */
 | |
| template <typename Type>
 | |
| struct ut_list_node {
 | |
| 	Type*		prev;			/*!< pointer to the previous
 | |
| 						node, NULL if start of list */
 | |
| 	Type*		next;			/*!< pointer to next node,
 | |
| 						NULL if end of list */
 | |
| 
 | |
| 	void reverse()
 | |
| 	{
 | |
| 		Type*	tmp = prev;
 | |
| 		prev = next;
 | |
| 		next = tmp;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| /** Macro used for legacy reasons */
 | |
| #define UT_LIST_NODE_T(t)		ut_list_node<t>
 | |
| 
 | |
| /*******************************************************************//**
 | |
| The two-way list base node. The base node contains pointers to both ends
 | |
| of the list and a count of nodes in the list (excluding the base node
 | |
| from the count). We also store a pointer to the member field so that it
 | |
| doesn't have to be specified when doing list operations.
 | |
| @param Type the type of the list element
 | |
| @param NodePtr field member pointer that points to the list node */
 | |
| template <typename Type, typename NodePtr>
 | |
| struct ut_list_base {
 | |
| 	typedef Type elem_type;
 | |
| 	typedef NodePtr node_ptr;
 | |
| 	typedef ut_list_node<Type> node_type;
 | |
| 
 | |
| 	ulint		count;			/*!< count of nodes in list */
 | |
| 	elem_type*	start;			/*!< pointer to list start,
 | |
| 						NULL if empty */
 | |
| 	elem_type*	end;			/*!< pointer to list end,
 | |
| 						NULL if empty */
 | |
| 	node_ptr	node;			/*!< Pointer to member field
 | |
| 						that is used as a link node */
 | |
| #ifdef UNIV_DEBUG
 | |
| 	ulint		init;			/*!< UT_LIST_INITIALISED if
 | |
| 						the list was initialised with
 | |
| 						UT_LIST_INIT() */
 | |
| #endif /* UNIV_DEBUG */
 | |
| 
 | |
| 	void reverse()
 | |
| 	{
 | |
| 		Type*	tmp = start;
 | |
| 		start = end;
 | |
| 		end = tmp;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| #define UT_LIST_BASE_NODE_T(t)	ut_list_base<t, ut_list_node<t> t::*>
 | |
| 
 | |
| #ifdef UNIV_DEBUG
 | |
| # define UT_LIST_INITIALISED		0xCAFE
 | |
| # define UT_LIST_INITIALISE(b)		(b).init = UT_LIST_INITIALISED
 | |
| # define UT_LIST_IS_INITIALISED(b)	ut_a(((b).init == UT_LIST_INITIALISED))
 | |
| #else
 | |
| # define UT_LIST_INITIALISE(b)
 | |
| # define UT_LIST_IS_INITIALISED(b)
 | |
| #endif /* UNIV_DEBUG */
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Note: This is really the list constructor. We should be able to use
 | |
| placement new here.
 | |
| Initializes the base node of a two-way list.
 | |
| @param b the list base node
 | |
| @param pmf point to member field that will be used as the link node */
 | |
| #define UT_LIST_INIT(b, pmf)						\
 | |
| {									\
 | |
| 	(b).count = 0;							\
 | |
| 	(b).start = 0;							\
 | |
| 	(b).end   = 0;							\
 | |
| 	(b).node  = pmf;						\
 | |
| 	UT_LIST_INITIALISE(b);						\
 | |
| }
 | |
| 
 | |
| /** Functor for accessing the embedded node within a list element. This is
 | |
| required because some lists can have the node emebedded inside a nested
 | |
| struct/union. See lock0priv.h (table locks) for an example. It provides a
 | |
| specialised functor to grant access to the list node. */
 | |
| template <typename Type>
 | |
| struct GenericGetNode {
 | |
| 
 | |
| 	typedef ut_list_node<Type> node_type;
 | |
| 
 | |
| 	GenericGetNode(node_type Type::* node) : m_node(node) {}
 | |
| 
 | |
| 	node_type& operator() (Type& elem)
 | |
| 	{
 | |
| 		return(elem.*m_node);
 | |
| 	}
 | |
| 
 | |
| 	node_type	Type::*m_node;
 | |
| };
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Adds the node as the first element in a two-way linked list.
 | |
| @param list the base node (not a pointer to it)
 | |
| @param elem the element to add */
 | |
| template <typename List>
 | |
| void
 | |
| ut_list_prepend(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem)
 | |
| {
 | |
| 	typename List::node_type&	elem_node = elem->*list.node;
 | |
| 
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	elem_node.prev = 0;
 | |
| 	elem_node.next = list.start;
 | |
| 
 | |
| 	if (list.start != 0) {
 | |
| 		typename List::node_type&	base_node =
 | |
| 			list.start->*list.node;
 | |
| 
 | |
| 		ut_ad(list.start != elem);
 | |
| 
 | |
| 		base_node.prev = elem;
 | |
| 	}
 | |
| 
 | |
| 	list.start = elem;
 | |
| 
 | |
| 	if (list.end == 0) {
 | |
| 		list.end = elem;
 | |
| 	}
 | |
| 
 | |
| 	++list.count;
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Adds the node as the first element in a two-way linked list.
 | |
| @param LIST the base node (not a pointer to it)
 | |
| @param ELEM the element to add */
 | |
| #define UT_LIST_ADD_FIRST(LIST, ELEM)	ut_list_prepend(LIST, ELEM)
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Adds the node as the last element in a two-way linked list.
 | |
| @param list list
 | |
| @param elem the element to add
 | |
| @param get_node to get the list node for that element */
 | |
| template <typename List, typename Functor>
 | |
| void
 | |
| ut_list_append(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem,
 | |
| 	Functor				get_node)
 | |
| {
 | |
| 	typename List::node_type&	node = get_node(*elem);
 | |
| 
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	node.next = 0;
 | |
| 	node.prev = list.end;
 | |
| 
 | |
| 	if (list.end != 0) {
 | |
| 		typename List::node_type&	base_node = get_node(*list.end);
 | |
| 
 | |
| 		ut_ad(list.end != elem);
 | |
| 
 | |
| 		base_node.next = elem;
 | |
| 	}
 | |
| 
 | |
| 	list.end = elem;
 | |
| 
 | |
| 	if (list.start == 0) {
 | |
| 		list.start = elem;
 | |
| 	}
 | |
| 
 | |
| 	++list.count;
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Adds the node as the last element in a two-way linked list.
 | |
| @param list list
 | |
| @param elem the element to add */
 | |
| template <typename List>
 | |
| void
 | |
| ut_list_append(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem)
 | |
| {
 | |
| 	ut_list_append(
 | |
| 		list, elem,
 | |
| 		GenericGetNode<typename List::elem_type>(list.node));
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Adds the node as the last element in a two-way linked list.
 | |
| @param LIST list base node (not a pointer to it)
 | |
| @param ELEM the element to add */
 | |
| #define UT_LIST_ADD_LAST(LIST, ELEM)	ut_list_append(LIST, ELEM)
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Inserts a ELEM2 after ELEM1 in a list.
 | |
| @param list the base node
 | |
| @param elem1 node after which ELEM2 is inserted
 | |
| @param elem2 node being inserted after ELEM1 */
 | |
| template <typename List>
 | |
| void
 | |
| ut_list_insert(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem1,
 | |
| 	typename List::elem_type*	elem2)
 | |
| {
 | |
| 	ut_ad(elem1 != elem2);
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	typename List::node_type&	elem1_node = elem1->*list.node;
 | |
| 	typename List::node_type&	elem2_node = elem2->*list.node;
 | |
| 
 | |
| 	elem2_node.prev = elem1;
 | |
| 	elem2_node.next = elem1_node.next;
 | |
| 
 | |
| 	if (elem1_node.next != NULL) {
 | |
| 		typename List::node_type&	next_node =
 | |
| 			elem1_node.next->*list.node;
 | |
| 
 | |
| 		next_node.prev = elem2;
 | |
| 	}
 | |
| 
 | |
| 	elem1_node.next = elem2;
 | |
| 
 | |
| 	if (list.end == elem1) {
 | |
| 		list.end = elem2;
 | |
| 	}
 | |
| 
 | |
| 	++list.count;
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Inserts a ELEM2 after ELEM1 in a list.
 | |
| @param LIST list base node (not a pointer to it)
 | |
| @param ELEM1 node after which ELEM2 is inserted
 | |
| @param ELEM2 node being inserted after ELEM1 */
 | |
| #define UT_LIST_INSERT_AFTER(LIST, ELEM1, ELEM2)			\
 | |
| 	ut_list_insert(LIST, ELEM1, ELEM2)
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Inserts a ELEM2 after ELEM1 in a list.
 | |
| @param list the base node
 | |
| @param elem1 node after which ELEM2 is inserted
 | |
| @param elem2 node being inserted after ELEM1
 | |
| @param get_node to get the list node for that element */
 | |
| 
 | |
| template <typename List, typename Functor>
 | |
| void
 | |
| ut_list_insert(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem1,
 | |
|         typename List::elem_type*	elem2,
 | |
| 	Functor				get_node)
 | |
| {
 | |
| 	ut_ad(elem1 != elem2);
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	typename List::node_type&	elem1_node = get_node(*elem1);
 | |
| 	typename List::node_type&	elem2_node = get_node(*elem2);
 | |
| 
 | |
| 	elem2_node.prev = elem1;
 | |
| 	elem2_node.next = elem1_node.next;
 | |
| 
 | |
| 	if (elem1_node.next != NULL) {
 | |
| 		typename List::node_type&	next_node =
 | |
| 			get_node(*elem1_node.next);
 | |
| 
 | |
| 		next_node.prev = elem2;
 | |
| 	}
 | |
| 
 | |
| 	elem1_node.next = elem2;
 | |
| 
 | |
| 	if (list.end == elem1) {
 | |
| 		list.end = elem2;
 | |
| 	}
 | |
| 
 | |
| 	++list.count;
 | |
| 
 | |
| }
 | |
| /*******************************************************************//**
 | |
| Removes a node from a two-way linked list.
 | |
| @param list the base node (not a pointer to it)
 | |
| @param node member node within list element that is to be removed
 | |
| @param get_node functor to get the list node from elem */
 | |
| template <typename List, typename Functor>
 | |
| void
 | |
| ut_list_remove(
 | |
| 	List&				list,
 | |
| 	typename List::node_type&	node,
 | |
| 	Functor				get_node)
 | |
| {
 | |
| 	ut_a(list.count > 0);
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	if (node.next != NULL) {
 | |
| 		typename List::node_type&	next_node =
 | |
| 			get_node(*node.next);
 | |
| 
 | |
| 		next_node.prev = node.prev;
 | |
| 	} else {
 | |
| 		list.end = node.prev;
 | |
| 	}
 | |
| 
 | |
| 	if (node.prev != NULL) {
 | |
| 		typename List::node_type&	prev_node =
 | |
| 			get_node(*node.prev);
 | |
| 
 | |
| 		prev_node.next = node.next;
 | |
| 	} else {
 | |
| 		list.start = node.next;
 | |
| 	}
 | |
| 
 | |
| 	node.next = 0;
 | |
| 	node.prev = 0;
 | |
| 
 | |
| 	--list.count;
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Removes a node from a two-way linked list.
 | |
| @param list the base node (not a pointer to it)
 | |
| @param elem element to be removed from the list
 | |
| @param get_node functor to get the list node from elem */
 | |
| template <typename List, typename Functor>
 | |
| void
 | |
| ut_list_remove(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem,
 | |
| 	Functor				get_node)
 | |
| {
 | |
| 	ut_list_remove(list, get_node(*elem), get_node);
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Removes a node from a two-way linked list.
 | |
| @param list the base node (not a pointer to it)
 | |
| @param elem element to be removed from the list */
 | |
| template <typename List>
 | |
| void
 | |
| ut_list_remove(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem)
 | |
| {
 | |
| 	ut_list_remove(
 | |
| 		list, elem->*list.node,
 | |
| 		GenericGetNode<typename List::elem_type>(list.node));
 | |
| }
 | |
| 
 | |
| /*******************************************************************//**
 | |
| Removes a node from a two-way linked list.
 | |
| @param LIST the base node (not a pointer to it)
 | |
| @param ELEM node to be removed from the list */
 | |
| #define UT_LIST_REMOVE(LIST, ELEM)	ut_list_remove(LIST, ELEM)
 | |
| 
 | |
| /********************************************************************//**
 | |
| Gets the next node in a two-way list.
 | |
| @param NAME list name
 | |
| @param N pointer to a node
 | |
| @return the successor of N in NAME, or NULL */
 | |
| #define UT_LIST_GET_NEXT(NAME, N)	(((N)->NAME).next)
 | |
| 
 | |
| /********************************************************************//**
 | |
| Gets the previous node in a two-way list.
 | |
| @param NAME list name
 | |
| @param N pointer to a node
 | |
| @return the predecessor of N in NAME, or NULL */
 | |
| #define UT_LIST_GET_PREV(NAME, N)	(((N)->NAME).prev)
 | |
| 
 | |
| /********************************************************************//**
 | |
| Alternative macro to get the number of nodes in a two-way list, i.e.,
 | |
| its length.
 | |
| @param BASE the base node (not a pointer to it).
 | |
| @return the number of nodes in the list */
 | |
| #define UT_LIST_GET_LEN(BASE)		(BASE).count
 | |
| 
 | |
| /********************************************************************//**
 | |
| Gets the first node in a two-way list.
 | |
| @param BASE the base node (not a pointer to it)
 | |
| @return first node, or NULL if the list is empty */
 | |
| #define UT_LIST_GET_FIRST(BASE)		(BASE).start
 | |
| 
 | |
| /********************************************************************//**
 | |
| Gets the last node in a two-way list.
 | |
| @param BASE the base node (not a pointer to it)
 | |
| @return last node, or NULL if the list is empty */
 | |
| #define UT_LIST_GET_LAST(BASE)		(BASE).end
 | |
| 
 | |
| struct NullValidate { void operator()(const void*) const {} };
 | |
| 
 | |
| /** Iterate over all the elements and call the functor for each element.
 | |
| @param[in]	list	base node (not a pointer to it)
 | |
| @param[in,out]	functor	Functor that is called for each element in the list */
 | |
| template <typename List, class Functor>
 | |
| inline void ut_list_map(const List& list, Functor& functor)
 | |
| {
 | |
| 	ulint count = 0;
 | |
| 
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	for (typename List::elem_type* elem = list.start; elem;
 | |
| 	     elem = (elem->*list.node).next, ++count) {
 | |
| 
 | |
| 		functor(elem);
 | |
| 	}
 | |
| 
 | |
| 	ut_a(count == list.count);
 | |
| }
 | |
| 
 | |
| /** Iterate over all the elements and call the functor for each element.
 | |
| @param[in]	list	base node (not a pointer to it)
 | |
| @param[in]	functor	Functor that is called for each element in the list */
 | |
| template <typename List, class Functor>
 | |
| inline void ut_list_map(const List& list, const Functor& functor)
 | |
| {
 | |
| 	ulint count = 0;
 | |
| 
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	for (typename List::elem_type* elem = list.start; elem;
 | |
| 	     elem = (elem->*list.node).next, ++count) {
 | |
| 
 | |
| 		functor(elem);
 | |
| 	}
 | |
| 
 | |
| 	ut_a(count == list.count);
 | |
| }
 | |
| 
 | |
| /** Check the consistency of a doubly linked list.
 | |
| @param[in] list		base node (not a pointer to it)
 | |
| @param[in,out] functor	Functor that is called for each element in the list */
 | |
| template <typename List, class Functor>
 | |
| void ut_list_validate(const List& list, Functor& functor)
 | |
| {
 | |
| 	ut_list_map(list, functor);
 | |
| #ifdef UNIV_DEBUG
 | |
| 	/* Validate the list backwards. */
 | |
| 	ulint count = list.count;
 | |
| 
 | |
| 	for (typename List::elem_type* elem = list.end;
 | |
| 	     elem != 0;
 | |
| 	     elem = (elem->*list.node).prev) {
 | |
| 		--count;
 | |
| 	}
 | |
| 	ut_ad(!count);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /** Check the consistency of a doubly linked list.
 | |
| @param[in] list		base node (not a pointer to it)
 | |
| @param[in] functor	Functor that is called for each element in the list */
 | |
| template <typename List, class Functor>
 | |
| inline void ut_list_validate(const List& list, const Functor& functor)
 | |
| {
 | |
| 	ut_list_map(list, functor);
 | |
| #ifdef UNIV_DEBUG
 | |
| 	/* Validate the list backwards. */
 | |
| 	ulint count = list.count;
 | |
| 
 | |
| 	for (typename List::elem_type* elem = list.end;
 | |
| 	     elem != 0;
 | |
| 	     elem = (elem->*list.node).prev) {
 | |
| 		--count;
 | |
| 	}
 | |
| 
 | |
| 	ut_ad(!count);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| template <typename List>
 | |
| inline void ut_list_validate(const List& list)
 | |
| {
 | |
|   ut_d(ut_list_validate(list, NullValidate()));
 | |
| }
 | |
| 
 | |
| #ifdef UNIV_DEBUG
 | |
| template <typename List>
 | |
| inline void ut_list_reverse(List& list)
 | |
| {
 | |
| 	UT_LIST_IS_INITIALISED(list);
 | |
| 
 | |
| 	for (typename List::elem_type* elem = list.start;
 | |
| 	     elem != 0;
 | |
| 	     elem = (elem->*list.node).prev) {
 | |
| 		(elem->*list.node).reverse();
 | |
| 	}
 | |
| 
 | |
| 	list.reverse();
 | |
| }
 | |
| 
 | |
| /** Check if the given element exists in the list.
 | |
| @param[in,out]	list	the list object
 | |
| @param[in]	elem	the element of the list which will be checked */
 | |
| template <typename List>
 | |
| inline bool ut_list_exists(const List& list, typename List::elem_type* elem)
 | |
| {
 | |
| 	for (typename List::elem_type* e1 = UT_LIST_GET_FIRST(list); e1;
 | |
| 	     e1 = (e1->*list.node).next) {
 | |
| 		if (elem == e1) {
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /** Move the given element to the beginning of the list.
 | |
| @param[in,out]	list	the list object
 | |
| @param[in]	elem	the element of the list which will be moved
 | |
| 			to the beginning of the list. */
 | |
| template <typename List>
 | |
| void
 | |
| ut_list_move_to_front(
 | |
| 	List&				list,
 | |
| 	typename List::elem_type*	elem)
 | |
| {
 | |
| 	ut_ad(ut_list_exists(list, elem));
 | |
| 
 | |
| 	if (UT_LIST_GET_FIRST(list) != elem) {
 | |
| 		ut_list_remove(list, elem);
 | |
| 		ut_list_prepend(list, elem);
 | |
| 	}
 | |
| }
 | 
