2021-07-11 15:16:13 +00:00
/*
2022-01-08 19:06:03 +00:00
* Copyright ( c ) 2018 - 2022 , Andreas Kling < kling @ serenityos . org >
* Copyright ( c ) 2022 , the SerenityOS developers .
2021-07-11 15:16:13 +00:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# pragma once
2022-01-08 19:06:03 +00:00
# include <AK/Error.h>
2021-07-11 15:16:13 +00:00
# include <AK/Iterator.h>
# include <AK/Span.h>
# include <AK/kmalloc.h>
namespace AK {
2022-01-12 21:28:43 +00:00
// FixedArray is an Array with a size only known at run-time.
// It guarantees to only allocate when being constructed, and to only deallocate when being destructed.
2021-07-11 15:16:13 +00:00
template < typename T >
class FixedArray {
public :
2021-09-16 06:20:31 +00:00
FixedArray ( ) = default ;
2022-01-08 19:06:03 +00:00
static ErrorOr < FixedArray < T > > try_create ( size_t size )
2021-07-11 15:16:13 +00:00
{
2022-01-08 19:06:03 +00:00
if ( size = = 0 )
return FixedArray < T > ( ) ;
T * elements = static_cast < T * > ( kmalloc_array ( size , sizeof ( T ) ) ) ;
if ( ! elements )
return Error : : from_errno ( ENOMEM ) ;
for ( size_t i = 0 ; i < size ; + + i )
new ( & elements [ i ] ) T ( ) ;
return FixedArray < T > ( size , elements ) ;
2021-07-11 15:16:13 +00:00
}
2022-01-08 19:06:03 +00:00
static FixedArray < T > must_create_but_fixme_should_propagate_errors ( size_t size )
2021-07-11 15:16:13 +00:00
{
2022-01-08 19:06:03 +00:00
return MUST ( try_create ( size ) ) ;
2021-07-11 15:16:13 +00:00
}
2022-01-08 19:06:03 +00:00
ErrorOr < FixedArray < T > > try_clone ( ) const
2021-07-11 15:16:13 +00:00
{
2022-01-08 19:06:03 +00:00
if ( m_size = = 0 )
return FixedArray < T > ( ) ;
T * elements = static_cast < T * > ( kmalloc_array ( m_size , sizeof ( T ) ) ) ;
if ( ! elements )
return Error : : from_errno ( ENOMEM ) ;
for ( size_t i = 0 ; i < m_size ; + + i )
new ( & elements [ i ] ) T ( m_elements [ i ] ) ;
return FixedArray < T > ( m_size , elements ) ;
}
FixedArray < T > must_clone_but_fixme_should_propagate_errors ( ) const
{
return MUST ( try_clone ( ) ) ;
2021-07-11 15:16:13 +00:00
}
2022-01-08 19:06:03 +00:00
// NOTE: Nobody can ever use these functions, since it would be impossible to make them OOM-safe due to their signatures. We just explicitly delete them.
FixedArray ( FixedArray < T > const & ) = delete ;
FixedArray < T > & operator = ( FixedArray < T > const & ) = delete ;
FixedArray ( FixedArray < T > & & other )
: m_size ( other . m_size )
, m_elements ( other . m_elements )
2021-07-11 15:16:13 +00:00
{
2022-01-08 19:06:03 +00:00
other . m_size = 0 ;
other . m_elements = nullptr ;
2021-07-11 15:16:13 +00:00
}
2022-01-08 19:06:03 +00:00
// NOTE: Nobody uses this function, so we just explicitly delete it.
FixedArray < T > & operator = ( FixedArray < T > & & ) = delete ;
2021-07-11 15:16:13 +00:00
2022-01-08 19:06:03 +00:00
~ FixedArray ( )
2021-07-11 15:16:13 +00:00
{
if ( ! m_elements )
return ;
for ( size_t i = 0 ; i < m_size ; + + i )
m_elements [ i ] . ~ T ( ) ;
kfree_sized ( m_elements , sizeof ( T ) * m_size ) ;
2022-01-12 21:28:43 +00:00
// NOTE: should prevent use-after-free early
2021-07-11 15:16:13 +00:00
m_size = 0 ;
2022-01-08 20:10:58 +00:00
m_elements = nullptr ;
2021-07-11 15:16:13 +00:00
}
size_t size ( ) const { return m_size ; }
T * data ( ) { return m_elements ; }
T const * data ( ) const { return m_elements ; }
T & operator [ ] ( size_t index )
{
VERIFY ( index < m_size ) ;
return m_elements [ index ] ;
}
T const & operator [ ] ( size_t index ) const
{
VERIFY ( index < m_size ) ;
return m_elements [ index ] ;
}
bool contains_slow ( T const & value ) const
{
for ( size_t i = 0 ; i < m_size ; + + i ) {
if ( m_elements [ i ] = = value )
return true ;
}
return false ;
}
2022-01-08 19:06:03 +00:00
void swap ( FixedArray < T > & other )
2021-07-11 15:16:13 +00:00
{
: : swap ( m_size , other . m_size ) ;
2022-01-08 20:10:58 +00:00
: : swap ( m_elements , other . m_elements ) ;
2021-07-11 15:16:13 +00:00
}
using Iterator = SimpleIterator < FixedArray , T > ;
2022-01-08 19:50:34 +00:00
using ConstIterator = SimpleIterator < FixedArray const , T const > ;
2021-07-11 15:16:13 +00:00
Iterator begin ( ) { return Iterator : : begin ( * this ) ; }
2022-01-08 19:50:34 +00:00
ConstIterator begin ( ) const { return ConstIterator : : begin ( * this ) ; }
2021-07-11 15:16:13 +00:00
Iterator end ( ) { return Iterator : : end ( * this ) ; }
2022-01-08 19:50:34 +00:00
ConstIterator end ( ) const { return ConstIterator : : end ( * this ) ; }
2021-07-11 15:16:13 +00:00
2021-07-11 15:38:13 +00:00
Span < T > span ( ) { return { data ( ) , size ( ) } ; }
2022-01-08 19:50:34 +00:00
Span < T const > span ( ) const { return { data ( ) , size ( ) } ; }
2021-07-11 15:38:13 +00:00
2021-07-11 15:16:13 +00:00
private :
2022-01-08 19:06:03 +00:00
FixedArray ( size_t size , T * elements )
: m_size ( size )
, m_elements ( elements )
{
}
2021-07-11 15:16:13 +00:00
size_t m_size { 0 } ;
T * m_elements { nullptr } ;
} ;
}
using AK : : FixedArray ;