2021-04-10 14:59:24 +00:00
/*
2021-04-22 20:40:43 +00:00
* Copyright ( c ) 2021 , Idan Horowitz < idan . horowitz @ serenityos . org >
2021-04-10 14:59:24 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-04-10 14:59:24 +00:00
*/
# pragma once
2021-09-07 22:57:49 +00:00
# include <AK/IntrusiveDetails.h>
2021-04-10 14:59:24 +00:00
# include <AK/RedBlackTree.h>
2021-09-09 10:57:19 +00:00
namespace AK : : Detail {
2021-04-10 14:59:24 +00:00
2021-09-07 22:57:49 +00:00
template < Integral K , typename V , typename Container = RawPtr < V > >
2021-04-10 14:59:24 +00:00
class IntrusiveRedBlackTreeNode ;
2021-09-09 10:57:19 +00:00
struct ExtractIntrusiveRedBlackTreeTypes {
template < typename K , typename V , typename Container , typename T >
static K key ( IntrusiveRedBlackTreeNode < K , V , Container > T : : * x ) ;
template < typename K , typename V , typename Container , typename T >
static V value ( IntrusiveRedBlackTreeNode < K , V , Container > T : : * x ) ;
template < typename K , typename V , typename Container , typename T >
static Container container ( IntrusiveRedBlackTreeNode < K , V , Container > T : : * x ) ;
} ;
2021-09-07 22:57:49 +00:00
template < Integral K , typename V , typename Container = RawPtr < V > >
2021-09-09 10:57:19 +00:00
using SubstitutedIntrusiveRedBlackTreeNode = IntrusiveRedBlackTreeNode < K , V , typename Detail : : SubstituteIntrusiveContainerType < V , Container > : : Type > ;
2021-04-10 14:59:24 +00:00
2021-09-09 10:57:19 +00:00
template < Integral K , typename V , typename Container , SubstitutedIntrusiveRedBlackTreeNode < K , V , Container > V : : * member >
2021-09-07 22:57:49 +00:00
class IntrusiveRedBlackTree : public BaseRedBlackTree < K > {
2021-07-17 09:25:28 +00:00
2021-04-10 14:59:24 +00:00
public :
IntrusiveRedBlackTree ( ) = default ;
2021-04-23 08:10:23 +00:00
virtual ~ IntrusiveRedBlackTree ( ) override
2021-04-10 14:59:24 +00:00
{
clear ( ) ;
}
using BaseTree = BaseRedBlackTree < K > ;
2021-09-09 10:57:19 +00:00
using TreeNode = SubstitutedIntrusiveRedBlackTreeNode < K , V , Container > ;
2021-04-10 14:59:24 +00:00
2021-09-07 22:57:49 +00:00
Container find ( K key )
2021-04-10 14:59:24 +00:00
{
auto * node = static_cast < TreeNode * > ( BaseTree : : find ( this - > m_root , key ) ) ;
if ( ! node )
return nullptr ;
return node_to_value ( * node ) ;
}
2021-09-07 22:57:49 +00:00
Container find_largest_not_above ( K key )
2021-04-10 14:59:24 +00:00
{
auto * node = static_cast < TreeNode * > ( BaseTree : : find_largest_not_above ( this - > m_root , key ) ) ;
if ( ! node )
return nullptr ;
return node_to_value ( * node ) ;
}
2021-09-08 00:07:34 +00:00
void insert ( K key , V & value )
2021-04-10 14:59:24 +00:00
{
auto & node = value . * member ;
2021-09-07 22:57:49 +00:00
VERIFY ( ! node . m_in_tree ) ;
2021-09-08 00:20:30 +00:00
static_cast < typename BaseTree : : Node & > ( node ) . key = key ;
2021-04-10 14:59:24 +00:00
BaseTree : : insert ( & node ) ;
2021-09-07 22:57:49 +00:00
if constexpr ( ! TreeNode : : IsRaw )
node . m_self . reference = & value ; // Note: Self-reference ensures that the object will keep a ref to itself when the Container is a smart pointer.
2021-04-10 14:59:24 +00:00
node . m_in_tree = true ;
}
template < typename ElementType >
class BaseIterator {
public :
BaseIterator ( ) = default ;
bool operator ! = ( const BaseIterator & other ) const { return m_node ! = other . m_node ; }
BaseIterator & operator + + ( )
{
if ( ! m_node )
return * this ;
m_prev = m_node ;
// the complexity is O(logn) for each successor call, but the total complexity for all elements comes out to O(n), meaning the amortized cost for a single call is O(1)
m_node = static_cast < TreeNode * > ( BaseTree : : successor ( m_node ) ) ;
return * this ;
}
BaseIterator & operator - - ( )
{
if ( ! m_prev )
return * this ;
m_node = m_prev ;
m_prev = static_cast < TreeNode * > ( BaseTree : : predecessor ( m_prev ) ) ;
return * this ;
}
ElementType & operator * ( )
{
VERIFY ( m_node ) ;
return * node_to_value ( * m_node ) ;
}
2021-09-07 22:57:49 +00:00
auto operator - > ( )
2021-04-10 14:59:24 +00:00
{
VERIFY ( m_node ) ;
return node_to_value ( * m_node ) ;
}
[ [ nodiscard ] ] bool is_end ( ) const { return ! m_node ; }
[ [ nodiscard ] ] bool is_begin ( ) const { return ! m_prev ; }
2021-07-17 09:26:04 +00:00
[ [ nodiscard ] ] auto key ( ) const { return m_node - > key ; }
2021-04-10 14:59:24 +00:00
private :
friend class IntrusiveRedBlackTree ;
explicit BaseIterator ( TreeNode * node , TreeNode * prev = nullptr )
: m_node ( node )
, m_prev ( prev )
{
}
TreeNode * m_node { nullptr } ;
TreeNode * m_prev { nullptr } ;
} ;
using Iterator = BaseIterator < V > ;
Iterator begin ( ) { return Iterator ( static_cast < TreeNode * > ( this - > m_minimum ) ) ; }
Iterator end ( ) { return { } ; }
Iterator begin_from ( K key ) { return Iterator ( static_cast < TreeNode * > ( BaseTree : : find ( this - > m_root , key ) ) ) ; }
using ConstIterator = BaseIterator < const V > ;
ConstIterator begin ( ) const { return ConstIterator ( static_cast < TreeNode * > ( this - > m_minimum ) ) ; }
ConstIterator end ( ) const { return { } ; }
ConstIterator begin_from ( K key ) const { return ConstIterator ( static_cast < TreeNode * > ( BaseTree : : find ( this - > m_rootF , key ) ) ) ; }
bool remove ( K key )
{
auto * node = static_cast < TreeNode * > ( BaseTree : : find ( this - > m_root , key ) ) ;
if ( ! node )
return false ;
BaseTree : : remove ( node ) ;
node - > right_child = nullptr ;
node - > left_child = nullptr ;
node - > m_in_tree = false ;
2021-09-07 22:57:49 +00:00
if constexpr ( ! TreeNode : : IsRaw )
node - > m_self . reference = nullptr ;
2021-04-10 14:59:24 +00:00
return true ;
}
void clear ( )
{
clear_nodes ( static_cast < TreeNode * > ( this - > m_root ) ) ;
this - > m_root = nullptr ;
this - > m_minimum = nullptr ;
this - > m_size = 0 ;
}
private :
static void clear_nodes ( TreeNode * node )
{
if ( ! node )
return ;
clear_nodes ( static_cast < TreeNode * > ( node - > right_child ) ) ;
node - > right_child = nullptr ;
clear_nodes ( static_cast < TreeNode * > ( node - > left_child ) ) ;
node - > left_child = nullptr ;
node - > m_in_tree = false ;
2021-09-07 22:57:49 +00:00
if constexpr ( ! TreeNode : : IsRaw )
node - > m_self . reference = nullptr ;
2021-04-10 14:59:24 +00:00
}
static V * node_to_value ( TreeNode & node )
{
2021-08-12 19:01:02 +00:00
return bit_cast < V * > ( bit_cast < u8 * > ( & node ) - bit_cast < u8 * > ( member ) ) ;
2021-04-10 14:59:24 +00:00
}
} ;
2021-09-07 22:57:49 +00:00
template < Integral K , typename V , typename Container >
2021-04-10 14:59:24 +00:00
class IntrusiveRedBlackTreeNode : public BaseRedBlackTree < K > : : Node {
public :
~ IntrusiveRedBlackTreeNode ( )
{
VERIFY ( ! is_in_tree ( ) ) ;
}
2021-07-17 09:26:04 +00:00
[ [ nodiscard ] ] bool is_in_tree ( ) const
2021-04-10 14:59:24 +00:00
{
return m_in_tree ;
}
2021-09-08 00:20:30 +00:00
[ [ nodiscard ] ] K key ( ) const
{
return BaseRedBlackTree < K > : : Node : : key ;
}
2021-09-07 22:57:49 +00:00
static constexpr bool IsRaw = IsPointer < Container > ;
# ifndef __clang__
2021-04-10 14:59:24 +00:00
private :
2021-09-09 10:57:19 +00:00
template < Integral TK , typename TV , typename TContainer , SubstitutedIntrusiveRedBlackTreeNode < TK , TV , TContainer > TV : : * member >
friend class : : AK : : Detail : : IntrusiveRedBlackTree ;
2021-09-07 22:57:49 +00:00
# endif
2021-04-10 14:59:24 +00:00
bool m_in_tree { false } ;
2021-09-07 22:57:49 +00:00
[ [ no_unique_address ] ] SelfReferenceIfNeeded < Container , IsRaw > m_self ;
} ;
// Specialise IntrusiveRedBlackTree for NonnullRefPtr
// By default, red black trees cannot contain null entries anyway, so switch to RefPtr
// and just make the user-facing functions deref the pointers.
2021-09-09 10:57:19 +00:00
template < Integral K , typename V , SubstitutedIntrusiveRedBlackTreeNode < K , V , NonnullRefPtr < V > > V : : * member >
2021-09-07 22:57:49 +00:00
class IntrusiveRedBlackTree < K , V , NonnullRefPtr < V > , member > : public IntrusiveRedBlackTree < K , V , RefPtr < V > , member > {
public :
[ [ nodiscard ] ] NonnullRefPtr < V > find ( K key ) const { return IntrusiveRedBlackTree < K , V , RefPtr < V > , member > : : find ( key ) . release_nonnull ( ) ; }
[ [ nodiscard ] ] NonnullRefPtr < V > find_largest_not_above ( K key ) const { return IntrusiveRedBlackTree < K , V , RefPtr < V > , member > : : find_largest_not_above ( key ) . release_nonnull ( ) ; }
2021-04-10 14:59:24 +00:00
} ;
}
2021-09-09 10:57:19 +00:00
namespace AK {
template < Integral K , typename V , typename Container = RawPtr < K > >
using IntrusiveRedBlackTreeNode = Detail : : SubstitutedIntrusiveRedBlackTreeNode < K , V , Container > ;
template < auto member >
using IntrusiveRedBlackTree = Detail : : IntrusiveRedBlackTree <
decltype ( Detail : : ExtractIntrusiveRedBlackTreeTypes : : key ( member ) ) ,
decltype ( Detail : : ExtractIntrusiveRedBlackTreeTypes : : value ( member ) ) ,
decltype ( Detail : : ExtractIntrusiveRedBlackTreeTypes : : container ( member ) ) ,
member > ;
}
2021-04-10 14:59:24 +00:00
using AK : : IntrusiveRedBlackTree ;
using AK : : IntrusiveRedBlackTreeNode ;