From 17810a58bf3fe40106d4dda4bec29e509b657cbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Thu, 9 Nov 2017 09:36:06 +0100
Subject: [PATCH] Sets - Index-backed implementation

---
 Sets-inline.hh | 133 +++++++++++++++++++++++++++++++++++++++++++++++++
 Sets.hh        |  12 ++++-
 2 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/Sets-inline.hh b/Sets-inline.hh
index 95599e3..544196f 100644
--- a/Sets-inline.hh
+++ b/Sets-inline.hh
@@ -212,6 +212,139 @@ M_TMPL_ void M_TYPE_::clear( ) noexcept
 #undef M_TYPE_
 
 
+/*= SET IMPLEMENTATION - INDEX ===============================================*/
+
+template<
+	typename Type ,
+	uint32_t InitialSize ,
+	uint32_t HashSize ,
+	uint32_t Growth
+> class T_SetImplementation< Type , IndexBacked< InitialSize , HashSize , Growth > >
+{
+	static_assert( InitialSize > 0 , "invalid initial size" );
+	static_assert( HashSize > 0 , "invalid hash array size" );
+	static_assert( Growth > 0 , "invalid growth" );
+
+    private:
+	T_HashIndex index_{ HashSize , InitialSize , Growth };
+	T_Array< Type > items_{ Growth };
+
+    public:
+	uint32_t size( ) const noexcept;
+	int32_t indexOf( Type const& item ) const noexcept;
+	Type const* access( uint32_t item ) const noexcept;
+
+	bool add( Type const& item ) noexcept;
+	bool add( Type&& item ) noexcept;
+	bool remove( Type const& item ) noexcept;
+
+	void free( ) noexcept;
+	void clear( ) noexcept;
+
+    private:
+	uint32_t find( Type const& k ,
+			const uint32_t hash ) const noexcept;
+};
+
+/*----------------------------------------------------------------------------*/
+
+#define M_TMPL_ template< typename Type , uint32_t ISize , uint32_t HSize , uint32_t Growth >
+#define M_TYPE_ T_SetImplementation< Type , IndexBacked< ISize , HSize , Growth > >
+
+M_TMPL_ uint32_t M_TYPE_::size( ) const noexcept
+{
+	return items_.size( );
+}
+
+M_TMPL_ int32_t M_TYPE_::indexOf(
+		Type const& item ) const noexcept
+{
+	const auto idx{ find( item , ComputeHash( item ) ) };
+	return idx == T_HashIndex::INVALID_INDEX ? -1 : int32_t( idx );
+}
+
+M_TMPL_ Type const* M_TYPE_::access(
+		const uint32_t item ) const noexcept
+{
+	return &items_[ item ];
+}
+
+/*----------------------------------------------------------------------------*/
+
+M_TMPL_ bool M_TYPE_::add(
+		Type const& item ) noexcept
+{
+	const auto hash{ ComputeHash( item ) };
+	const auto idx{ find( item , hash ) };
+	if ( idx == T_HashIndex::INVALID_INDEX ) {
+		index_.add( hash );
+		items_.add( item );
+	}
+	return idx == T_HashIndex::INVALID_INDEX;
+}
+
+M_TMPL_ bool M_TYPE_::add(
+		Type&& item ) noexcept
+{
+	const auto hash{ ComputeHash( item ) };
+	const auto idx{ find( item , hash ) };
+	if ( idx == T_HashIndex::INVALID_INDEX ) {
+		index_.add( hash );
+		items_.add( std::move( item ) );
+	}
+	return idx == T_HashIndex::INVALID_INDEX;
+}
+
+M_TMPL_ bool M_TYPE_::remove(
+		Type const& item ) noexcept
+{
+	const auto hash{ ComputeHash( item ) };
+	const auto idx{ find( item , hash ) };
+	if ( idx != T_HashIndex::INVALID_INDEX ) {
+		items_.removeSwap( idx );
+		index_.remove( idx );
+	}
+	return idx != T_HashIndex::INVALID_INDEX;
+}
+
+/*----------------------------------------------------------------------------*/
+
+M_TMPL_ void M_TYPE_::free( ) noexcept
+{
+	index_.free( );
+	items_.free( );
+}
+
+M_TMPL_ void M_TYPE_::clear( ) noexcept
+{
+	index_.clear( );
+	items_.clear( );
+}
+
+/*----------------------------------------------------------------------------*/
+
+M_TMPL_ uint32_t M_TYPE_::find(
+		Type const& k ,
+		const uint32_t hash ) const noexcept
+{
+	uint32_t idx = index_.first( hash );
+	while ( idx != T_HashIndex::INVALID_INDEX ) {
+		// XXX use a match function?
+//		if ( match_( keys_[ idx ] , k ) ) {
+//			break;
+//		}
+		if ( items_[ idx ] == k ) {
+			break;
+		}
+		idx = index_.next( idx );
+	}
+	return idx;
+}
+
+#undef M_TMPL_
+#undef M_TYPE_
+
+
 /*= COMMON HANDLER ===========================================================*/
 
 // In-place version
diff --git a/Sets.hh b/Sets.hh
index f8836fc..d15b9ed 100644
--- a/Sets.hh
+++ b/Sets.hh
@@ -5,6 +5,7 @@
 #ifndef _H_EBCL_SETS
 #define _H_EBCL_SETS
 #include <ebcl/Arrays.hh>
+#include <ebcl/HashIndex.hh>
 namespace ebcl {
 
 // FIXME move this to utilities \/
@@ -41,7 +42,14 @@ M_DEFINE_TEMPLATE_TAG( ArrayBacked ,
 	uint32_t InPlace ,
 	uint32_t Growth = 0
 );
-//M_DEFINE_TAG( IndexBacked );
+
+// IndexBacked implementation tag - the implementation will use a
+// T_HashIndex and an array. InitialSize and HashSize affect the index,
+// Growth affects both the index and the array.
+M_DEFINE_TEMPLATE_TAG( IndexBacked ,
+	uint32_t InitialSize = T_HashIndex::DEFAULT_SIZE ,
+	uint32_t HashSize = T_HashIndex::DEFAULT_SIZE ,
+	uint32_t Growth = T_HashIndex::DEFAULT_GROWTH );
 
 
 // Templated horrors used by the main T_Set class.
@@ -49,7 +57,7 @@ struct T_SetHelper
 {
 	// Default implementation to use; also determines the in-place
 	// storage size
-	using DefaultImplementation = ArrayBacked< 8 >; // FIXME should use Index by default
+	using DefaultImplementation = IndexBacked< >;
 
 	// Default implementation class
 	template< typename Type