zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #11008
[Merge] lp:~paul-lucas/zorba/feature-unordered_map into lp:zorba
Paul J. Lucas has proposed merging lp:~paul-lucas/zorba/feature-unordered_map into lp:zorba.
Requested reviews:
Matthias Brantner (matthias-brantner)
For more details, see:
https://code.launchpad.net/~paul-lucas/zorba/feature-unordered_map/+merge/110657
Added C++98 subset of C++11's unordered_map. The configure process checks for a working C++11 unordered_map first: if found, it will be used instead. The goal is to phase out the old hash*map* classes over time.
--
https://code.launchpad.net/~paul-lucas/zorba/feature-unordered_map/+merge/110657
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2012-06-15 21:31:03 +0000
+++ CMakeLists.txt 2012-06-16 14:48:21 +0000
@@ -123,15 +123,29 @@
CHECK_TYPE_SIZE("__int32" ZORBA_HAVE_MS_INT32)
CHECK_TYPE_SIZE("int64_t" ZORBA_HAVE_INT64_T)
-CHECK_CXX_SOURCE_COMPILES ("#include <type_traits>\nint main() { std::enable_if<true,int> x; }" ZORBA_CXX_ENABLE_IF)
+# C++ built-in type sizes
+CHECK_TYPE_SIZE("double" ZORBA_SIZEOF_DOUBLE BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("float" ZORBA_SIZEOF_FLOAT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("int" ZORBA_SIZEOF_INT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("long" ZORBA_SIZEOF_LONG BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("long long" ZORBA_SIZEOF_LONG_LONG BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("void*" ZORBA_SIZEOF_POINTER BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("short" ZORBA_SIZEOF_SHORT BUILTIN_TYPES_ONLY)
+CHECK_TYPE_SIZE("size_t" ZORBA_SIZEOF_SIZE_T)
SET(CMAKE_EXTRA_INCLUDE_FILES wchar.h)
CHECK_TYPE_SIZE("wchar_t" ZORBA_SIZEOF_WCHAR_T)
SET(CMAKE_EXTRA_INCLUDE_FILES)
-CHECK_CXX_SOURCE_COMPILES ("#include <memory>\nint main() { std::unique_ptr<int> p; }" ZORBA_CXX_UNIQUE_PTR)
+# C++11 langauge features
CHECK_CXX_SOURCE_COMPILES("int main() { int *p = nullptr; }" ZORBA_CXX_NULLPTR)
CHECK_CXX_SOURCE_COMPILES("int main() { static_assert(1,\"\"); }" ZORBA_CXX_STATIC_ASSERT)
+# C++11 standard library types
+CHECK_CXX_SOURCE_COMPILES ("#include <type_traits>\nint main() { std::enable_if<true,int> x; }" ZORBA_HAVE_ENABLE_IF)
+CHECK_CXX_SOURCE_COMPILES ("#include <memory>\nint main() { std::unique_ptr<int> p; }" ZORBA_HAVE_UNIQUE_PTR)
+CHECK_CXX_SOURCE_COMPILES ("#include <unordered_map>\nint main() { std::unordered_map<int,int> m; }" ZORBA_HAVE_UNORDERED_MAP)
+CHECK_CXX_SOURCE_COMPILES ("#include <unordered_set>\nint main() { std::unordered_set<int> s; }" ZORBA_HAVE_UNORDERED_SET)
+
################################################################################
# Various cmake macros
=== modified file 'include/zorba/config.h.cmake'
--- include/zorba/config.h.cmake 2012-06-15 21:31:03 +0000
+++ include/zorba/config.h.cmake 2012-06-16 14:48:21 +0000
@@ -68,6 +68,15 @@
#cmakedefine ZORBA_HAVE_MS_INT32
#cmakedefine ZORBA_HAVE_MS_UINT32
#cmakedefine ZORBA_HAVE_UINT32_T
+#cmakedefine ZORBA_SIZEOF_DOUBLE @ZORBA_SIZEOF_DOUBLE@
+#cmakedefine ZORBA_SIZEOF_FLOAT @ZORBA_SIZEOF_FLOAT@
+#cmakedefine ZORBA_SIZEOF_INT @ZORBA_SIZEOF_INT@
+#cmakedefine ZORBA_SIZEOF_LONG @ZORBA_SIZEOF_LONG@
+#cmakedefine ZORBA_SIZEOF_LONG_LONG @ZORBA_SIZEOF_LONG_LONG@
+#cmakedefine ZORBA_SIZEOF_POINTER @ZORBA_SIZEOF_POINTER@
+#cmakedefine ZORBA_SIZEOF_SHORT @ZORBA_SIZEOF_SHORT@
+#cmakedefine ZORBA_SIZEOF_SIZE_T @ZORBA_SIZEOF_SIZE_T@
+#cmakedefine ZORBA_SIZEOF_WCHAR_T @ZORBA_SIZEOF_WCHAR_T@
// Platform libraries
#cmakedefine ZORBA_HAVE_CURL
@@ -96,8 +105,6 @@
typedef __int64 int64_t;
#endif /* ZORBA_HAVE_INT64_T */
-#cmakedefine ZORBA_SIZEOF_WCHAR_T @ZORBA_SIZEOF_WCHAR_T@
-
// Compiler
#cmakedefine CLANG
#cmakedefine MSVC
@@ -106,11 +113,15 @@
#cmakedefine MSVC71
#cmakedefine MSVC80
-// C++ language features
-#cmakedefine ZORBA_CXX_ENABLE_IF
+// C++11 language features
#cmakedefine ZORBA_CXX_NULLPTR
#cmakedefine ZORBA_CXX_STATIC_ASSERT
-#cmakedefine ZORBA_CXX_UNIQUE_PTR
+
+// C++11 types
+#cmakedefine ZORBA_HAVE_ENABLE_IF
+#cmakedefine ZORBA_HAVE_UNORDERED_MAP
+#cmakedefine ZORBA_HAVE_UNORDERED_SET
+#cmakedefine ZORBA_HAVE_UNIQUE_PTR
////////// C++ tr1 include directory & namespace //////////////////////////////
=== modified file 'include/zorba/internal/type_traits.h'
--- include/zorba/internal/type_traits.h 2012-06-15 21:31:03 +0000
+++ include/zorba/internal/type_traits.h 2012-06-16 14:48:21 +0000
@@ -27,7 +27,7 @@
///////////////////////////////////////////////////////////////////////////////
-#ifndef ZORBA_CXX_ENABLE_IF
+#ifndef ZORBA_HAVE_ENABLE_IF
namespace std {
/**
@@ -49,11 +49,11 @@
};
} // namespace std
-#endif /* ZORBA_CXX_ENABLE_IF */
+#endif /* ZORBA_HAVE_ENABLE_IF */
///////////////////////////////////////////////////////////////////////////////
-#ifndef ZORBA_CXX_UNIQUE_PTR
+#ifndef ZORBA_HAVE_UNIQUE_PTR
namespace zorba {
namespace internal {
@@ -90,7 +90,7 @@
} // namespace internal
} // namespace zorba
-#endif /* ZORBA_CXX_UNIQUE_PTR */
+#endif /* ZORBA_HAVE_UNIQUE_PTR */
///////////////////////////////////////////////////////////////////////////////
=== modified file 'include/zorba/internal/unique_ptr.h'
--- include/zorba/internal/unique_ptr.h 2012-06-15 21:31:03 +0000
+++ include/zorba/internal/unique_ptr.h 2012-06-16 14:48:21 +0000
@@ -19,7 +19,7 @@
#include <zorba/config.h>
-#ifdef ZORBA_CXX_UNIQUE_PTR
+#ifdef ZORBA_HAVE_UNIQUE_PTR
# include <memory> /* for unique_ptr */
# include <utility> /* for forward, move */
#else
@@ -577,6 +577,6 @@
} // namespace std
-#endif /* ZORBA_CXX_UNIQUE_PTR */
+#endif /* ZORBA_HAVE_UNIQUE_PTR */
#endif /* ZORBA_UNIQUE_PTR_H */
/* vim:set et sw=2 ts=2: */
=== modified file 'src/compiler/codegen/plan_visitor.cpp'
--- src/compiler/codegen/plan_visitor.cpp 2012-06-15 21:31:03 +0000
+++ src/compiler/codegen/plan_visitor.cpp 2012-06-16 14:48:21 +0000
@@ -26,7 +26,6 @@
#include "util/tracer.h"
#include "util/stl_util.h"
-#include "util/hashmap32.h"
#include "system/globalenv.h"
#include "system/properties.h"
=== modified file 'src/functions/function.cpp'
--- src/functions/function.cpp 2012-06-15 21:31:03 +0000
+++ src/functions/function.cpp 2012-06-16 14:48:21 +0000
@@ -24,7 +24,6 @@
#include "types/typeops.h"
-#include "util/hashmap32.h"
#include "util/string_util.h"
#include "diagnostics/assert.h"
=== modified file 'src/unit_tests/CMakeLists.txt'
--- src/unit_tests/CMakeLists.txt 2012-06-15 21:31:03 +0000
+++ src/unit_tests/CMakeLists.txt 2012-06-16 14:48:21 +0000
@@ -35,4 +35,11 @@
test_icu_streambuf.cpp)
ENDIF (NOT ZORBA_NO_ICU)
-# vim:set et sw=2 tw=2:
+IF (NOT ZORBA_CXX_UNORDERE_MAP)
+ LIST (APPEND UNIT_TEST_SRCS
+ unordered_map.cpp
+ unordered_map_instantiate.cpp
+ unordered_set.cpp)
+ENDIF (NOT ZORBA_CXX_UNORDERE_MAP)
+
+# vim:set et sw=2 ts=2:
=== modified file 'src/unit_tests/unit_test_list.h'
--- src/unit_tests/unit_test_list.h 2012-06-15 21:31:03 +0000
+++ src/unit_tests/unit_test_list.h 2012-06-16 14:48:21 +0000
@@ -34,19 +34,21 @@
int test_thesaurus( int, char*[] );
int test_tokenizer( int, char*[] );
#endif /* ZORBA_NO_FULL_TEXT */
- /**
- * ADD NEW UNIT TESTS HERE
- */
#ifndef ZORBA_NO_ICU
int test_icu_streambuf( int, char*[] );
#endif /* ZORBA_NO_ICU */
int json_parser( int, char*[] );
+#ifndef ZORBA_HAVE_UNORDERED_MAP
+ int test_unordered_map( int, char*[] );
+#endif /* ZORBA_HAVE_UNORDERED_MAP */
+#ifndef ZORBA_HAVE_UNORDERED_MAP
+ int test_unordered_set( int, char*[] );
+#endif /* ZORBA_HAVE_UNORDERED_MAP */
void initializeTestList();
};
-
-} /* namespace zorba */
+} // namespace zorba
#endif /* ZORBA_UNIT_TEST_LIST_H */
/* vim:set et sw=2 ts=2: */
=== modified file 'src/unit_tests/unit_tests.cpp'
--- src/unit_tests/unit_tests.cpp 2012-06-15 21:31:03 +0000
+++ src/unit_tests/unit_tests.cpp 2012-06-16 14:48:21 +0000
@@ -50,6 +50,12 @@
libunittests["thesaurus"] = test_thesaurus;
libunittests["tokenizer"] = test_tokenizer;
#endif /* ZORBA_NO_FULL_TEXT */
+#ifndef ZORBA_HAVE_UNORDERED_MAP
+ libunittests["unordered_map"] = test_unordered_map;
+#endif /* ZORBA_HAVE_UNORDERED_MAP */
+#ifndef ZORBA_HAVE_UNORDERED_MAP
+ libunittests["unordered_set"] = test_unordered_set;
+#endif /* ZORBA_HAVE_UNORDERED_MAP */
#ifdef ZORBA_WITH_DEBUGGER
// libunittests["debugger_protocol"] = runDebuggerProtocolTest;
=== added file 'src/unit_tests/unordered_map.cpp'
--- src/unit_tests/unordered_map.cpp 1970-01-01 00:00:00 +0000
+++ src/unit_tests/unordered_map.cpp 2012-06-16 14:48:21 +0000
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+#include <iostream>
+#include <string>
+
+#include "util/unordered_map.h"
+
+using namespace std;
+
+typedef unordered_map<string,int> map_type;
+typedef pair<map_type::iterator,bool> insert_return_type;
+typedef pair<map_type::iterator,map_type::iterator> equal_range_return_type;
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int failures;
+
+static bool assert_true( char const *expr, int line, bool result ) {
+ if ( !result ) {
+ cout << "FAILED, line " << line << ": " << expr << endl;
+ ++failures;
+ }
+ return result;
+}
+
+static void print_exception( char const *expr, int line,
+ std::exception const &e ) {
+ assert_true( expr, line, false );
+ cout << "+ exception: " << e.what() << endl;
+}
+
+#define ASSERT_TRUE( EXPR ) assert_true( #EXPR, __LINE__, !!(EXPR) )
+
+#define ASSERT_TRUE_AND_NO_EXCEPTION( EXPR ) \
+ try { ASSERT_TRUE( EXPR ); } \
+ catch ( std::exception const &e ) { print_exception( #EXPR, __LINE__, e ); } \
+ catch ( ... ) { assert_true( #EXPR, __LINE__, false ); }
+
+#define ASSERT_EXCEPTION( EXPR, EXCEPTION ) \
+ try { EXPR; assert_true( #EXPR, __LINE__, false ); } \
+ catch ( EXCEPTION const& ) { }
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_at() {
+ map_type m;
+ m[ "a" ] = 1;
+ m[ "b" ] = 2;
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "a" ) == 1 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "b" ) == 2 );
+ ASSERT_EXCEPTION( m.at( "c" ), out_of_range );
+
+ map_type const mc( m );
+ ASSERT_TRUE_AND_NO_EXCEPTION( mc.at( "a" ) == 1 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( mc.at( "b" ) == 2 );
+ ASSERT_EXCEPTION( mc.at( "c" ), out_of_range );
+}
+
+static void test_basics() {
+ map_type m;
+
+ ASSERT_TRUE( m.empty() );
+ ASSERT_TRUE( m.size() == 0 );
+
+ m[ "a" ] = 1;
+ m[ "b" ] = 2;
+
+ ASSERT_TRUE( !m.empty() );
+ ASSERT_TRUE( m.size() == 2 );
+
+ map_type m2( m );
+
+ ASSERT_TRUE( !m2.empty() );
+ ASSERT_TRUE( m2.size() == 2 );
+
+ m2.clear();
+ ASSERT_TRUE( m2.empty() );
+ ASSERT_TRUE( m2.size() == 0 );
+
+ // Ensure 'm' is unaffected by changes to 'm2'.
+ ASSERT_TRUE( !m.empty() );
+ ASSERT_TRUE( m.size() == 2 );
+}
+
+static void test_erase() {
+ map_type m;
+ map_type::iterator i;
+
+ m[ "a" ] = 1;
+ m[ "b" ] = 2;
+
+ ASSERT_TRUE( m.erase( "a" ) == 1 );
+ ASSERT_TRUE( m.erase( "a" ) == 0 );
+ ASSERT_TRUE( !m.empty() );
+ ASSERT_TRUE( m.size() == 1 );
+
+ if ( ASSERT_TRUE( (i = m.find( "b" )) != m.end() ) ) {
+ m.erase( i );
+ ASSERT_TRUE( m.empty() );
+ ASSERT_TRUE( m.size() == 0 );
+ }
+}
+
+static void test_insert() {
+ map_type m;
+ equal_range_return_type err;
+ map_type::const_iterator i;
+ insert_return_type ir;
+
+ ir = m.insert( make_pair( "a", 1 ) );
+ if ( ASSERT_TRUE( ir.second == true ) )
+ if ( ASSERT_TRUE( ir.first != m.end() ) ) {
+ ASSERT_TRUE( ir.first->first == "a" );
+ ASSERT_TRUE( ir.first->second == 1 );
+ }
+ ASSERT_TRUE( !m.empty() );
+ ASSERT_TRUE( m.size() == 1 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "a" ) == 1 );
+ ASSERT_TRUE( m[ "a" ] == 1 );
+ ASSERT_TRUE( m.count( "a" ) == 1 );
+ if ( ASSERT_TRUE( (i = m.find( "a" )) != m.end() ) ) {
+ ASSERT_TRUE( i->first == "a" );
+ ASSERT_TRUE( i->second == 1 );
+ }
+
+ err = m.equal_range( "a" );
+ if ( ASSERT_TRUE( err.first != m.end() ) )
+ ASSERT_TRUE( err.first->second == 1 );
+
+ ir = m.insert( make_pair( "b", 2 ) );
+ if ( ASSERT_TRUE( ir.second == true ) ) {
+ ASSERT_TRUE( ir.first->first == "b" );
+ ASSERT_TRUE( ir.first->second == 2 );
+ }
+ ASSERT_TRUE( !m.empty() );
+ ASSERT_TRUE( m.size() == 2 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "b" ) == 2 );
+ ASSERT_TRUE( m[ "b" ] == 2 );
+ ASSERT_TRUE( m.count( "b" ) == 1 );
+ if ( ASSERT_TRUE( (i = m.find( "b" )) != m.end() ) ) {
+ ASSERT_TRUE( i->first == "b" );
+ ASSERT_TRUE( i->second == 2 );
+ }
+ ASSERT_TRUE( m.equal_range( "b" ).first->second == 2 );
+
+ // Ensure "a" is still there.
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "a" ) == 1 );
+ ASSERT_TRUE( m[ "a" ] == 1 );
+ ASSERT_TRUE( m.count( "a" ) == 1 );
+ if ( ASSERT_TRUE( (i = m.find( "a" )) != m.end() ) ) {
+ ASSERT_TRUE( i->first == "a" );
+ ASSERT_TRUE( i->second == 1 );
+ }
+ ASSERT_TRUE( m.equal_range( "a" ).first->second == 1 );
+}
+
+static void test_local_iterator() {
+ map_type m;
+
+ char s[2];
+ s[1] = '\0';
+ for ( int i = 0; i < 26; ++i ) {
+ *s = (char)('a' + i);
+ m[ s ] = i + 1;
+ }
+
+ map_type::size_type b = m.bucket( "a" );
+ ASSERT_TRUE( m.bucket_size( b ) > 0 );
+
+ bool found_a = false;
+ map_type::local_iterator i( m.begin( b ) );
+ map_type::local_iterator const j( m.end( b ) );
+ for ( ; i != j; ++i )
+ if ( i->first == "a" ) {
+ found_a = true;
+ break;
+ }
+ ASSERT_TRUE( found_a );
+}
+
+static void test_rehash() {
+ unordered_map<int,int> m;
+ unordered_map<int,int>::size_type const initial_buckets = m.bucket_count();
+
+ // Add elements until bucket_count() changes which implies a rehash was done.
+ for ( int i = 0; m.bucket_count() == initial_buckets; ++i )
+ m[ i ] = i;
+
+ ASSERT_TRUE( m.bucket_count() > initial_buckets );
+
+ // Ensure all the elements are still there.
+ unordered_map<int,int>::size_type const size = m.size();
+ for ( int i = 0; i < size; ++i )
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( i ) == i );
+}
+
+static void test_swap() {
+ map_type m;
+ m[ "a" ] = 1;
+ m[ "b" ] = 2;
+
+ map_type m2;
+ m2[ "c" ] = 3;
+ m2[ "d" ] = 4;
+ m2[ "e" ] = 5;
+
+ m.swap( m2 );
+
+ ASSERT_TRUE( m.size() == 3 );
+ ASSERT_TRUE( m2.size() == 2 );
+
+ ASSERT_EXCEPTION( m.at( "a" ), out_of_range );
+ ASSERT_EXCEPTION( m.at( "b" ), out_of_range );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "c" ) == 3 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "d" ) == 4 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m.at( "e" ) == 5 );
+
+ ASSERT_TRUE_AND_NO_EXCEPTION( m2.at( "a" ) == 1 );
+ ASSERT_TRUE_AND_NO_EXCEPTION( m2.at( "b" ) == 2 );
+ ASSERT_EXCEPTION( m2.at( "c" ), out_of_range );
+ ASSERT_EXCEPTION( m2.at( "d" ), out_of_range );
+ ASSERT_EXCEPTION( m2.at( "e" ), out_of_range );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace zorba {
+namespace UnitTests {
+
+int test_unordered_map( int, char*[] ) {
+ test_basics();
+ test_at();
+ test_erase();
+ test_insert();
+ test_local_iterator();
+ test_rehash();
+ test_swap();
+
+ cout << failures << " test(s) failed\n";
+ return failures ? 1 : 0;
+}
+
+} // namespace UnitTests
+} // namespace zorba
+
+///////////////////////////////////////////////////////////////////////////////
+
+/* vim:set et sw=2 ts=2: */
=== added file 'src/unit_tests/unordered_map_instantiate.cpp'
--- src/unit_tests/unordered_map_instantiate.cpp 1970-01-01 00:00:00 +0000
+++ src/unit_tests/unordered_map_instantiate.cpp 2012-06-16 14:48:21 +0000
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include "util/unordered_map.h"
+
+using namespace std;
+
+static void instantiate() {
+ return;
+
+ typedef unordered_map<string,int> map_type;
+
+ map_type::iterator i, j;
+ map_type::const_iterator ci, cj;
+
+ (void)*i;
+ (void)i->first;
+ (void)i->second;
+ (void)++i;
+ (void)i++;
+ (void)(i == j);
+ (void)(i != j);
+
+ (void)*ci;
+ (void)ci->first;
+ (void)ci->second;
+ (void)++ci;
+ (void)ci++;
+ (void)(ci == cj);
+ (void)(ci != cj);
+
+ map_type::local_iterator li, lj;
+ map_type::const_local_iterator cli, clj;
+
+ (void)*li;
+ (void)li->first;
+ (void)li->second;
+ (void)++li;
+ (void)li++;
+ (void)(li == lj);
+ (void)(li != lj);
+
+ (void)*cli;
+ (void)cli->first;
+ (void)cli->second;
+ (void)++cli;
+ (void)cli++;
+ (void)(cli == clj);
+ (void)(cli != clj);
+
+ map_type m;
+ map_type m2( m );
+ m = m2;
+ map_type const cm;
+
+ i = m.begin();
+ ci = m.cbegin();
+ j = m.end();
+ cj = m.cend();
+
+ li = m.begin( 0 );
+ cli = m.cbegin( 0 );
+ lj = m.end( 0 );
+ clj = m.cend( 0 );
+
+ m.clear();
+ m.erase( i );
+ m.erase( ci );
+ m.erase( ci, ci );
+ m.erase( "x" );
+
+ m.insert( make_pair( "a", 1 ) );
+ m.insert( ci, make_pair( "a", 1 ) );
+
+ m.rehash( 41 );
+ m.swap( m2 );
+
+ m.at( "x" );
+ cm.at( "x" );
+
+ m[ "b" ] = 2;
+
+ m.count( "x" );
+ m.find( "x" );
+ cm.find( "x" );
+ m.equal_range( "x" );
+ cm.equal_range( "x" );
+
+ m.bucket( "x" );
+ m.bucket_count();
+ m.bucket_size( 0 );
+ m.max_bucket_count();
+
+ m.empty();
+ m.get_allocator();
+ m.hash_function();
+ m.key_eq();
+ m.load_factor();
+ m.max_load_factor();
+ m.max_size();
+ m.size();
+}
+/* vim:set et sw=2 ts=2: */
=== added file 'src/unit_tests/unordered_set.cpp'
--- src/unit_tests/unordered_set.cpp 1970-01-01 00:00:00 +0000
+++ src/unit_tests/unordered_set.cpp 2012-06-16 14:48:21 +0000
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdafx.h"
+#include <iostream>
+#include <string>
+
+#include "util/unordered_set.h"
+
+using namespace std;
+
+typedef unordered_set<string> set_type;
+typedef pair<set_type::iterator,bool> insert_return_type;
+typedef pair<set_type::iterator,set_type::iterator> equal_range_return_type;
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int failures;
+
+static bool assert_true( char const *expr, int line, bool result ) {
+ if ( !result ) {
+ cout << "FAILED, line " << line << ": " << expr << endl;
+ ++failures;
+ }
+ return result;
+}
+
+static void print_exception( char const *expr, int line,
+ std::exception const &e ) {
+ assert_true( expr, line, false );
+ cout << "+ exception: " << e.what() << endl;
+}
+
+#define ASSERT_TRUE( EXPR ) assert_true( #EXPR, __LINE__, !!(EXPR) )
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_basics() {
+ set_type set;
+ insert_return_type ir;
+
+ ASSERT_TRUE( set.empty() );
+ ASSERT_TRUE( set.size() == 0 );
+
+ ir = set.insert( "a" );
+ if ( ASSERT_TRUE( ir.second ) )
+ if ( ASSERT_TRUE( ir.first != set.end() ) )
+ ASSERT_TRUE( *ir.first == "a" );
+
+ ir = set.insert( "b" );
+ if ( ASSERT_TRUE( ir.second ) )
+ if ( ASSERT_TRUE( ir.first != set.end() ) )
+ ASSERT_TRUE( *ir.first == "b" );
+
+ ASSERT_TRUE( !set.empty() );
+ ASSERT_TRUE( set.size() == 2 );
+
+ set_type set2( set );
+
+ ASSERT_TRUE( !set2.empty() );
+ ASSERT_TRUE( set2.size() == 2 );
+
+ set2.clear();
+ ASSERT_TRUE( set2.empty() );
+ ASSERT_TRUE( set2.size() == 0 );
+
+ // Ensure 'set' is unaffected by changes to 'set2'.
+ ASSERT_TRUE( !set.empty() );
+ ASSERT_TRUE( set.size() == 2 );
+}
+
+static void test_erase() {
+ set_type set;
+ set_type::iterator i;
+
+ set.insert( "a" );
+ set.insert( "b" );
+
+ ASSERT_TRUE( set.erase( "a" ) == 1 );
+ ASSERT_TRUE( set.erase( "a" ) == 0 );
+ ASSERT_TRUE( !set.empty() );
+ ASSERT_TRUE( set.size() == 1 );
+
+ if ( ASSERT_TRUE( (i = set.find( "b" )) != set.end() ) ) {
+ set.erase( i );
+ ASSERT_TRUE( set.empty() );
+ ASSERT_TRUE( set.size() == 0 );
+ }
+}
+
+static void test_insert() {
+ set_type set;
+ equal_range_return_type err;
+ set_type::iterator i;
+ insert_return_type ir;
+
+ ir = set.insert( "a" );
+ if ( ASSERT_TRUE( ir.second ) )
+ ASSERT_TRUE( *ir.first == "a" );
+ ASSERT_TRUE( !set.empty() );
+ ASSERT_TRUE( set.size() == 1 );
+ ASSERT_TRUE( set.count( "a" ) == 1 );
+
+ if ( ASSERT_TRUE( (i = set.find( "a" )) != set.end() ) )
+ ASSERT_TRUE( *i == "a" );
+ err = set.equal_range( "a" );
+ if ( ASSERT_TRUE( err.first != set.end() ) )
+ ASSERT_TRUE( *err.first == "a" );
+
+ ir = set.insert( "b" );
+ if ( ASSERT_TRUE( ir.second ) )
+ if ( ASSERT_TRUE( ir.first != set.end() ) )
+ ASSERT_TRUE( *ir.first == "b" );
+ ASSERT_TRUE( !set.empty() );
+ ASSERT_TRUE( set.size() == 2 );
+ ASSERT_TRUE( set.count( "b" ) == 1 );
+
+ if ( ASSERT_TRUE( (i = set.find( "b" )) != set.end() ) )
+ ASSERT_TRUE( *i == "b" );
+ err = set.equal_range( "b" );
+ if ( ASSERT_TRUE( err.first != set.end() ) )
+ ASSERT_TRUE( *err.first == "b" );
+
+ // Ensure "a" is still there.
+ if ( ASSERT_TRUE( (i = set.find( "a" )) != set.end() ) )
+ ASSERT_TRUE( *i == "a" );
+ ASSERT_TRUE( set.count( "a" ) == 1 );
+ err = set.equal_range( "a" );
+ if ( ASSERT_TRUE( err.first != set.end() ) )
+ ASSERT_TRUE( *err.first == "a" );
+}
+
+static void test_local_iterator() {
+ set_type set;
+
+ char s[2];
+ s[1] = '\0';
+ for ( int i = 0; i < 26; ++i ) {
+ *s = (char)('a' + i);
+ set.insert( s );
+ }
+
+ set_type::size_type b = set.bucket( "a" );
+ ASSERT_TRUE( set.bucket_size( b ) > 0 );
+
+ bool found_a = false;
+ set_type::local_iterator i( set.begin( b ) );
+ set_type::local_iterator const j( set.end( b ) );
+ for ( ; i != j; ++i )
+ if ( *i == "a" ) {
+ found_a = true;
+ break;
+ }
+ ASSERT_TRUE( found_a );
+}
+
+static void test_rehash() {
+ unordered_set<int> set;
+ unordered_set<int>::const_iterator i;
+
+ unordered_set<int>::size_type const initial_buckets = set.bucket_count();
+
+ // Add elements until bucket_count() changes which implies a rehash was done.
+ for ( int n = 0; set.bucket_count() == initial_buckets; ++n )
+ set.insert( n );
+
+ ASSERT_TRUE( set.bucket_count() > initial_buckets );
+
+ // Ensure all the elements are still there.
+ unordered_set<int>::size_type const size = set.size();
+ for ( int n = 0; n < size; ++n ) {
+ if ( ASSERT_TRUE( (i = set.find( n )) != set.end() ) )
+ ASSERT_TRUE( *i == n );
+ }
+}
+
+static void test_swap() {
+ unordered_set<string>::iterator i;
+
+ set_type set;
+ set.insert( "a" );
+ set.insert( "b" );
+
+ set_type set2;
+ set2.insert( "c" );
+ set2.insert( "d" );
+ set2.insert( "e" );
+
+ set.swap( set2 );
+
+ ASSERT_TRUE( set.size() == 3 );
+ ASSERT_TRUE( set2.size() == 2 );
+
+ ASSERT_TRUE( set.find( "a" ) == set.end() );
+ ASSERT_TRUE( set.find( "b" ) == set.end() );
+
+ if ( ASSERT_TRUE( (i = set.find( "c" )) != set.end() ) )
+ ASSERT_TRUE( *i == "c" );
+ if ( ASSERT_TRUE( (i = set.find( "d" )) != set.end() ) )
+ ASSERT_TRUE( *i == "d" );
+ if ( ASSERT_TRUE( (i = set.find( "e" )) != set.end() ) )
+ ASSERT_TRUE( *i == "e" );
+
+ if ( ASSERT_TRUE( (i = set2.find( "a" )) != set2.end() ) )
+ ASSERT_TRUE( *i == "a" );
+ if ( ASSERT_TRUE( (i = set2.find( "b" )) != set2.end() ) )
+ ASSERT_TRUE( *i == "b" );
+ ASSERT_TRUE( set2.find( "c" ) == set2.end() );
+ ASSERT_TRUE( set2.find( "d" ) == set2.end() );
+ ASSERT_TRUE( set2.find( "e" ) == set2.end() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace zorba {
+namespace UnitTests {
+
+int test_unordered_set( int, char*[] ) {
+ test_basics();
+ test_erase();
+ test_insert();
+ test_local_iterator();
+ test_rehash();
+ test_swap();
+
+ cout << failures << " test(s) failed\n";
+ return failures ? 1 : 0;
+}
+
+} // namespace UnitTests
+} // namespace zorba
+
+///////////////////////////////////////////////////////////////////////////////
+
+/* vim:set et sw=2 ts=2: */
=== modified file 'src/util/CMakeLists.txt'
--- src/util/CMakeLists.txt 2012-06-15 21:31:03 +0000
+++ src/util/CMakeLists.txt 2012-06-16 14:48:21 +0000
@@ -50,3 +50,7 @@
HEADER_GROUP_SUBFOLDER(UTIL_SRCS fx)
HEADER_GROUP_SUBFOLDER(UTIL_SRCS win32)
+
+IF (NOT (ZORBA_HAVE_UNORDERED_MAP AND ZORBA_HAVE_UNORDERED_SET))
+ ADD_SRC_SUBFOLDER(UTIL_SRCS hash UTIL_HASH_SRCS)
+ENDIF (NOT (ZORBA_HAVE_UNORDERED_MAP AND ZORBA_HAVE_UNORDERED_SET))
=== added directory 'src/util/hash'
=== added file 'src/util/hash/CMakeLists.txt'
--- src/util/hash/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/util/hash/CMakeLists.txt 2012-06-16 14:48:21 +0000
@@ -0,0 +1,18 @@
+# Copyright 2006-2008 The FLWOR Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SET(UTIL_HASH_SRCS
+ hash.cpp
+ rehash_policy.cpp
+ )
=== added file 'src/util/hash/hash.cpp'
--- src/util/hash/hash.cpp 1970-01-01 00:00:00 +0000
+++ src/util/hash/hash.cpp 2012-06-16 14:48:21 +0000
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// standard
+#include <limits>
+
+// local
+#include "hash.h"
+
+using namespace std;
+
+namespace zorba {
+namespace ztd {
+
+///////////////////////////////////////////////////////////////////////////////
+
+size_t hash_bytes( void const *p, size_t len, size_t result ) {
+ unsigned char const *c = reinterpret_cast<unsigned char const*>( p );
+ unsigned char const *const end = c + len;
+#ifdef ZORBA_HASH_FN_FNV_1a
+ //
+ // FNV-1a (Fowler/Noll/Vo) hashing algorithm.
+ //
+ while ( c < end ) {
+ result *= Hash_Prime;
+ result ^= *c++;
+ }
+#endif /* ZORBA_HASH_FN_FNV_1a */
+#ifdef ZORBA_HASH_FN_PJW
+ //
+ // An adaptation of Peter J. Weinberger's (PJW) generic hashing algorithm
+ // based on Allen Holub's version. This version works for any hash code
+ // size (in this case, size_t) and not only 'unsigned' as in PJW's version.
+ //
+ // The original PJW algorithm can be found in:
+ //
+ // Fig. 7.35: Hash function hashpjw, written in C
+ // "Compilers: Principles, Techniques, and Tools," Section 7.6: "Symbol
+ // Tables," Alfred Aho, Ravi Sethi, and Jeffrey D. Ullman, Addison-Wesley,
+ // Reading, MA, 1986, pp. 435-436.
+ //
+ static size_t const BitsInSizeT = sizeof( size_t ) *
+ numeric_limits<unsigned char>::digits;
+ static size_t const ThreeFourths = BitsInSizeT * 3 / 4;
+ static size_t const OneEighth = BitsInSizeT / 8;
+ static size_t const HighBits = ~( (size_t)(~0ul) >> OneEighth );
+
+ while ( c < end ) {
+ result = (result << OneEighth) + *c++;
+ if ( size_t temp = result & HighBits )
+ result = (result ^ (temp >> ThreeFourths)) & ~HighBits;
+ }
+#endif /* ZORBA_HASH_FN_PJW */
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace ztd
+} // namespace zorba
+
+/* vim:set et ts=2 sw=2: */
=== added file 'src/util/hash/hash.h'
--- src/util/hash/hash.h 1970-01-01 00:00:00 +0000
+++ src/util/hash/hash.h 2012-06-16 14:48:21 +0000
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_HASH_H
+#define ZORBA_HASH_H
+
+// zorba
+#include <zorba/config.h>
+
+// standard
+#include <functional>
+#include <string>
+#include <sys/types.h>
+
+// Exactly ONE of these should be defined.
+#define ZORBA_HASH_FN_FNV_1a 1 /* Fowler/Noll/Vo (FNV-1a) algorithm */
+//#define ZORBA_HASH_FN_PJW 1 /* Peter J. Weinberger's (PJW) algorithm */
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace zorba {
+
+template<class RepType> class rstring;
+
+namespace ztd {
+
+#ifdef ZORBA_HASH_FN_FNV_1a
+#if ZORBA_SIZEOF_SIZE_T == 4
+size_t const Hash_Init = 2166136261ul;
+size_t const Hash_Prime = 16777619ul;
+#elif ZORBA_SIZEOF_SIZE_T == 8
+size_t const Hash_Init = 14695981039346656037ul;
+size_t const Hash_Prime = 1099511628211ul;
+#endif /* ZORBA_SIZEOF_SIZE_T */
+#endif /* ZORBA_HASH_FN_FNV_1a */
+
+#ifdef ZORBA_HASH_FN_PJW
+size_t const Hash_Init = 3339675911ul;
+#endif /* ZORBA_HASH_FN_PJW */
+
+/**
+ * Generic hash function that hashes a byte sequence.
+ *
+ * @param p A pointer to the first byte in the sequence to hash.
+ * @param len The number of bytes in the sequence.
+ * @param init The initialization value.
+ * @return Returns the hash code for the given byte sequence.
+ */
+size_t hash_bytes( void const *p, size_t len, size_t init = Hash_Init );
+
+/**
+ * Generic hash function that hashes the memory occupied by a value of some
+ * type \a T.
+ *
+ * @tparam T The value's type.
+ * @param v The value to hash.
+ * @return Returns the hash code for the given value.
+ */
+template<typename T> inline
+size_t hash_bytes( T const &v ) {
+ return hash_bytes( &v, sizeof( v ) );
+}
+
+} // namespace ztd
+} // namespace zorba
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace std {
+
+#ifndef ZORBA_HAVE_UNORDERED_MAP
+
+/**
+ * The generic %hash unary_function class.
+ *
+ * @tparam T The type to hash.
+ */
+template<typename T>
+struct hash : unary_function<T,size_t> {
+ size_t operator()( T ) const; // not defined
+};
+
+#define ZORBA_INTEGRAL_HASH(T) \
+ template<> inline \
+ size_t hash<T>::operator()( T a ) const { \
+ return static_cast<size_t>( a ); \
+ }
+
+ZORBA_INTEGRAL_HASH( bool )
+ZORBA_INTEGRAL_HASH( char )
+ZORBA_INTEGRAL_HASH( signed char )
+ZORBA_INTEGRAL_HASH( wchar_t )
+ZORBA_INTEGRAL_HASH( short )
+ZORBA_INTEGRAL_HASH( int )
+ZORBA_INTEGRAL_HASH( long )
+ZORBA_INTEGRAL_HASH( long long )
+ZORBA_INTEGRAL_HASH( unsigned char )
+ZORBA_INTEGRAL_HASH( unsigned short )
+ZORBA_INTEGRAL_HASH( unsigned int )
+ZORBA_INTEGRAL_HASH( unsigned long )
+ZORBA_INTEGRAL_HASH( unsigned long long )
+
+#undef ZORBA_INTEGRAL_HASH
+
+/** Specialization for \c float. */
+template<> inline
+size_t hash<float>::operator()( float v ) const {
+ return v != 0.0F ? zorba::ztd::hash_bytes( v ) : 0;
+}
+
+/** Specialization for \c double. */
+template<> inline
+size_t hash<double>::operator()( double v ) const {
+ return v != 0.0 ? zorba::ztd::hash_bytes( v ) : 0;
+}
+
+/** Partial specialization for pointer types. */
+template<typename T>
+struct hash<T*> : unary_function<T*,size_t> {
+ size_t operator()( T *p ) const {
+ return reinterpret_cast<size_t>( p );
+ }
+};
+
+/** Specialization for \c string. */
+template<typename CharT,class Traits,class Alloc>
+struct hash< basic_string<CharT,Traits,Alloc> > :
+ unary_function<basic_string<CharT,Traits,Alloc> const&,size_t>
+{
+ size_t operator()( basic_string<CharT,Traits,Alloc> const &s ) const {
+ return zorba::ztd::hash_bytes( s.data(), s.size() );
+ }
+};
+
+#endif /* ZORBA_HAVE_UNORDERED_MAP */
+
+/** Specialization for \c rstring. */
+template<class RepType>
+struct hash< zorba::rstring<RepType> > :
+ unary_function<zorba::rstring<RepType> const&,size_t>
+{
+ size_t operator()( zorba::rstring<RepType> const &s ) const {
+ return zorba::ztd::hash_bytes( s.data(), s.size() );
+ }
+};
+
+} // namespace std
+
+///////////////////////////////////////////////////////////////////////////////
+
+#endif /* ZORBA_HASH_H */
+/* vim:set et ts=2 sw=2: */
=== added file 'src/util/hash/hashtable.h'
--- src/util/hash/hashtable.h 1970-01-01 00:00:00 +0000
+++ src/util/hash/hashtable.h 2012-06-16 14:48:21 +0000
@@ -0,0 +1,1067 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_HASHTABLE_H
+#define ZORBA_HASHTABLE_H
+
+// standard
+#include <algorithm>
+#include <iterator>
+#include <sys/types.h>
+#include <utility> /* for pair */
+
+// local
+#include "util/cxx_util.h"
+#include "util/stl_util.h"
+
+namespace zorba {
+namespace ztd {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The base class for a hash-table implementation.
+ *
+ * @tparam KeyType They map's key type.
+ * @tparam ValueType The type the keys are mapped to.
+ * @tparam KeyExtract The unary_function to use to extract a key from a value.
+ * @tparam KeyHash The unary_function to use for generating hash codes.
+ * @tparam KeyEqual The binary_function to use to test for key equality.
+ * @tparam Allocator The allocator to use.
+ * @tparam RehashPolicy The rehash policy class to use.
+ */
+template<
+ typename KeyType,
+ typename ValueType,
+ class KeyExtract,
+ class KeyHash,
+ class KeyEqual,
+ class Allocator,
+ class RehashPolicy
+>
+class hashtable_base {
+protected:
+ struct node;
+ typedef RehashPolicy rehash_policy_type;
+public:
+ typedef KeyType key_type;
+ typedef ValueType value_type;
+ typedef KeyHash hasher;
+ typedef KeyEqual key_equal;
+ typedef Allocator allocator_type;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ typedef typename allocator_type::pointer pointer;
+ typedef typename allocator_type::const_pointer const_pointer;
+ typedef typename allocator_type::reference reference;
+ typedef typename allocator_type::const_reference const_reference;
+
+ /**
+ * Constructs a %hashtable_base.
+ *
+ * @param bucket_count The initial number of buckets to use.
+ * @param hash The hash-code unary functor to use.
+ * @param equal The key-equality functor to use.
+ * @param alloc The allocator to use.
+ */
+ hashtable_base( size_type bucket_count, hasher const &hash,
+ key_equal const &equal, allocator_type const &alloc );
+
+ /**
+ * Copy constructor.
+ *
+ * @param that The %hashtable_base to copy from.
+ */
+ hashtable_base( hashtable_base const &that );
+
+ /**
+ * Destructor.
+ */
+ ~hashtable_base();
+
+ /**
+ * Assignment operator.
+ *
+ * @param that The %hashtable_base to assign from.
+ * @return Returns \c *this.
+ */
+ hashtable_base& operator=( hashtable_base const &that );
+
+ ////////// local_iterator ///////////////////////////////////////////////////
+
+ class local_iterator :
+ public std::iterator<std::forward_iterator_tag,value_type> {
+ public:
+ local_iterator() : cur_node_( nullptr ) { }
+
+ reference operator*() const;
+ pointer operator->() const;
+ local_iterator& operator++();
+ local_iterator operator++(int);
+
+ friend bool operator==( local_iterator const &i, local_iterator const &j ) {
+ return i.cur_node_ == j.cur_node_;
+ }
+
+ friend bool operator!=( local_iterator const &i, local_iterator const &j ) {
+ return i.cur_node_ != j.cur_node_;
+ }
+
+ private:
+ node *cur_node_;
+
+ local_iterator( node *p ) : cur_node_( p ) { }
+ friend class hashtable_base;
+ };
+
+ ////////// const_local_iterator /////////////////////////////////////////////
+
+ class const_local_iterator :
+ public std::iterator<std::forward_iterator_tag,value_type const> {
+ public:
+ const_local_iterator() : cur_node_( nullptr ) { }
+
+ const_reference operator*() const;
+ const_pointer operator->() const;
+ const_local_iterator& operator++();
+ const_local_iterator operator++(int);
+
+ friend bool operator==( const_local_iterator const &i,
+ const_local_iterator const &j ) {
+ return i.cur_node_ == j.cur_node_;
+ }
+
+ friend bool operator!=( const_local_iterator const &i,
+ const_local_iterator const &j ) {
+ return i.cur_node_ != j.cur_node_;
+ }
+
+ private:
+ node const *cur_node_;
+
+ const_local_iterator( node const *p ) : cur_node_( p ) { }
+ friend class hashtable_base;
+ };
+
+ ////////// iterator /////////////////////////////////////////////////////////
+
+ class iterator : public std::iterator<std::forward_iterator_tag,value_type> {
+ public:
+ iterator() : cur_bkt_( nullptr ), cur_node_( nullptr ) { }
+
+ reference operator*() const;
+ pointer operator->() const;
+ iterator& operator++();
+ iterator operator++(int);
+
+ friend bool operator==( iterator const &i, iterator const &j ) {
+ return i.cur_node_ == j.cur_node_;
+ }
+
+ friend bool operator!=( iterator const &i, iterator const &j ) {
+ return i.cur_node_ != j.cur_node_;
+ }
+
+ private:
+ node **cur_bkt_;
+ node *cur_node_;
+
+ iterator( node **bkt, node *p );
+ void inc_bucket();
+
+ friend class hashtable_base;
+ friend class const_iterator;
+ };
+
+ ////////// const_iterator ///////////////////////////////////////////////////
+
+ class const_iterator :
+ public std::iterator<std::forward_iterator_tag,value_type const> {
+ public:
+ const_iterator() : cur_bkt_( nullptr ), cur_node_( nullptr ) { }
+ const_iterator( iterator const& );
+
+ const_reference operator*() const;
+ const_pointer operator->() const;
+ const_iterator& operator++();
+ const_iterator operator++(int);
+
+ friend bool operator==( const_iterator const &i, const_iterator const &j ) {
+ return i.cur_node_ == j.cur_node_;
+ }
+
+ friend bool operator!=( const_iterator const &i, const_iterator const &j ) {
+ return i.cur_node_ != j.cur_node_;
+ }
+
+ private:
+ node **cur_bkt_;
+ node *cur_node_;
+
+ const_iterator( node **bkt, node *p );
+ void inc_bucket();
+
+ friend class hashtable_base;
+ };
+
+ ////////// iteration ////////////////////////////////////////////////////////
+
+ /**
+ * Creates an iterator positioned at the "first" element. (Because this is
+ * an \e unordered map, "first" is arbitrary.)
+ *
+ * @return Returns said iterator.
+ */
+ iterator begin();
+
+ /**
+ * Creates an iterator positioned at the "first" element. (Because this is
+ * an \e unordered map, "first" is arbitrary.)
+ *
+ * @return Returns said iterator.
+ */
+ const_iterator begin() const;
+
+ /**
+ * Creates an iterator positioned at the "first" element. (Because this is
+ * an \e unordered map, "first" is arbitrary.)
+ *
+ * @return Returns said iterator.
+ */
+ const_iterator cbegin() const;
+
+ /**
+ * Creates an iterator positioned one past the "last" element. (Because this
+ * is an \e unordered map, "last" is arbitrary.)
+ *
+ * @return Returns said iterator.
+ */
+ iterator end();
+
+ /**
+ * Creates a const_iterator positioned one past the "last" element. (Because
+ * this is an \e unordered map, "last" is arbitrary.)
+ *
+ * @return Returns said iterator.
+ */
+ const_iterator end() const;
+
+ /**
+ * Creates a const_iterator positioned one past the "last" element. (Because
+ * this is an \e unordered map, "last" is arbitrary.)
+ *
+ * @return Returns said iterator.
+ */
+ const_iterator cend() const;
+
+ /**
+ * Creates a local_iterator positioned at the first element in the given
+ * bucket.
+ *
+ * @param bkt The index of the bucket.
+ * @return Returns said iterator.
+ */
+ local_iterator begin( size_type bkt );
+
+ /**
+ * Creates a const_local_iterator positioned at the first element in the
+ * given bucket.
+ *
+ * @param bkt The index of the bucket.
+ * @return Returns said iterator.
+ */
+ const_local_iterator begin( size_type bkt ) const;
+
+ /**
+ * Creates a const_local_iterator positioned at the first element in the
+ * given bucket.
+ *
+ * @param bkt The index of the bucket.
+ * @return Returns said iterator.
+ */
+ const_local_iterator cbegin( size_type bkt ) const;
+
+ /**
+ * Creates a local_iterator positioned at one past the last element in the
+ * given bucket.
+ *
+ * @param bkt The index of the bucket.
+ * @return Returns said iterator.
+ */
+ local_iterator end( size_type bkt );
+
+ /**
+ * Creates a const_local_iterator positioned at one past the last element in
+ * the given bucket.
+ *
+ * @param bkt The index of the bucket.
+ * @return Returns said iterator.
+ */
+ const_local_iterator end( size_type bkt ) const;
+
+ /**
+ * Creates a const_local_iterator positioned at one past the last element in
+ * the given bucket.
+ *
+ * @param bkt The index of the bucket.
+ * @return Returns said iterator.
+ */
+ const_local_iterator cend( size_type bkt ) const;
+
+ ////////// modifiers ////////////////////////////////////////////////////////
+
+ /**
+ * Clears this %hashtable_base, i.e., erases all elements.
+ */
+ void clear();
+
+ /**
+ * Erases the element at \a pos.
+ *
+ * @param pos The %iterator positioned at the element to erase.
+ * @return Returns an iterator positioned one past the erased element.
+ */
+ iterator erase( iterator pos );
+
+ /**
+ * Erases the element at \a pos.
+ *
+ * @param pos The %iterator positioned at the element to erase.
+ * @return Returns an iterator positioned one past the erased element.
+ */
+ iterator erase( const_iterator pos );
+
+ /**
+ * Erases all the elements in the range [<em>first</em>,<em>last</em>).
+ *
+ * @param first The %iterator positioned at the first element to erase.
+ * @param last The %iterator positioned one past the last element to erase.
+ * @return Returns an iterator positioned one past the last erased element.
+ */
+ iterator erase( const_iterator first, const_iterator last );
+
+ /**
+ * Erases the element having the given key.
+ *
+ * @param key The key.
+ * @return Returns the number of elements erased.
+ */
+ size_type erase( key_type const &key );
+
+ /**
+ * Attempts to insert a new value.
+ *
+ * @param value The value to insert.
+ * @return If a value with the given key is already in the %hashtable_base,
+ * returns [i,false] where \a i is positioned at the existing element;
+ * otherwise returns [i,true] where \a i is positioned at the new element.
+ */
+ std::pair<iterator,bool> insert( value_type const &value );
+
+ /**
+ * Attempts to insert a new value.
+ *
+ * @param hint An iterator providing a hint as to where to attempt to insert
+ * the new value.
+ * @param value The value to insert.
+ * @return If a value with the given key is already in the %hashtable_base,
+ * returns [i,false] where \a i is positioned at the existing element;
+ * otherwise returns [i,true] where \a i is positioned at the new element.
+ */
+ iterator insert( const_iterator hint, value_type const &value );
+
+ /**
+ * Attempts to insert the values provided by the given iterator.
+ *
+ * @tparam InputIterator The input iterator type.
+ * @param first An iterator positioned at the first element to insert.
+ * @param last An iterator positioned one past the last element to insert.
+ */
+ template<class InputIterator>
+ void insert( InputIterator first, InputIterator last );
+
+ /**
+ * Rehashes the %hashtable_base.
+ *
+ * @param bucket_count The new number of buckets.
+ */
+ void rehash( size_type bucket_count );
+
+ /**
+ * Swaps this %hashtable_base with another.
+ *
+ * @param that The %hashtable_base to swap with.
+ */
+ void swap( hashtable_base &that );
+
+ ////////// look-up //////////////////////////////////////////////////////////
+
+ /**
+ * Counts the number of elements having the given key.
+ *
+ * @param key The key to count.
+ * @return Returns said number.
+ */
+ size_type count( key_type const &key ) const;
+
+ /**
+ * Attempts to find the given \a key.
+ *
+ * @param key The key to find.
+ * @return If found, returns an iterator positioned at \a key; if not,
+ * returns an iterator positioned at end().
+ */
+ iterator find( key_type const &key );
+
+ /**
+ * Attempts to find the given \a key.
+ *
+ * @param key The key to find.
+ * @return If found, returns an iterator positioned at \a key; if not,
+ * returns an iterator positioned at end().
+ */
+ const_iterator find( key_type const &key ) const;
+
+ /**
+ * Creates a pair of iterators giving the range of elements that have the
+ * given key.
+ *
+ * @param key The key.
+ * @return Returns said iterators.
+ */
+ std::pair<iterator,iterator> equal_range( key_type const &key );
+
+ /**
+ * Creates a pair of const_iterators giving the range of elements that have
+ * the given key.
+ *
+ * @param key The key.
+ * @return Returns said iterators.
+ */
+ std::pair<const_iterator,const_iterator>
+ equal_range( key_type const &key ) const;
+
+ ////////// buckets //////////////////////////////////////////////////////////
+
+ /**
+ * Gets the index of the bucket for the \a key. Note that \a key isn't
+ * necessarily in the %hashtable_base.
+ *
+ * @param key The key.
+ * @return Returns an index in the range [0,max_bucket_count).
+ */
+ size_type bucket( key_type const &key ) const;
+
+ /**
+ * Gets the current number of buckets.
+ *
+ * @return Returns said number of buckets.
+ */
+ size_type bucket_count() const;
+
+ /**
+ * Gets the number of elements in the bucket specified by the given index.
+ *
+ * @param bucket_index The index of the bucket.
+ * @return Returns said number of elements.
+ */
+ size_type bucket_size( size_type bucket_index ) const;
+
+ /**
+ * Gets the maximum possible number of buckets.
+ *
+ * @return Returns said number of buckets.
+ */
+ size_type max_bucket_count() const;
+
+ ////////// miscellaneous ////////////////////////////////////////////////////
+
+ /**
+ * Gets whether this %hashtable_base is empty.
+ *
+ * @return Returns \c true only if it's empty.
+ */
+ bool empty() const;
+
+ /**
+ * Gets the allocator being used.
+ *
+ * @return Returns said allocator.
+ */
+ allocator_type get_allocator() const;
+
+ /**
+ * Gets the hash function being used.
+ *
+ * @return Returns said function.
+ */
+ hasher hash_function() const;
+
+ /**
+ * Gets the key equality function being used.
+ *
+ * @return Returns said function.
+ */
+ key_equal key_eq() const;
+
+ /**
+ * Gets the current load factor.
+ *
+ * @return Returns said load factor.
+ */
+ float load_factor() const;
+
+ /**
+ * Gets the maximim load factor.
+ *
+ * @return Returns said load factor.
+ */
+ float max_load_factor() const;
+
+ /**
+ * Sets the load factor that affects the number of buckets. If the new
+ * number of buckets is greater than the old number, performs a rehash.
+ *
+ * @param load_factor The new maximum load factor.
+ * @throws std::invalid_argument if \a load_factor <= 0.
+ */
+ void max_load_factor( float load_factor );
+
+ /**
+ * Gets the maximum possible number of elements.
+ *
+ * @return Returns said number of elements.
+ */
+ size_type max_size() const;
+
+ /**
+ * Gets the number of elements.
+ *
+ * @return Returns said number of elements.
+ */
+ size_type size() const;
+
+ /////////////////////////////////////////////////////////////////////////////
+
+protected:
+ struct node {
+ value_type value_;
+ node *next_;
+
+ node() : value_( value_type() ), next_( nullptr ) { }
+ node( value_type const &v ) : value_( v ), next_( nullptr ) { }
+ };
+
+ node* find_node( key_type const &key ) const {
+ return find_node( bucket( key ), key );
+ }
+
+ node* find_node( node*, key_type const& ) const;
+
+ node* find_node( size_type bkt, key_type const &key ) const {
+ return find_node( buckets_[ bkt ], key );
+ }
+
+ std::pair<iterator,bool> insert( size_type bkt, value_type const &value );
+
+private:
+ typedef typename allocator_type::template rebind<node*>::other
+ bucket_alloc_type;
+
+ typedef typename allocator_type::template rebind<node>::other
+ node_alloc_type;
+
+ typedef typename hasher::result_type hash_code_type;
+
+ node** alloc_buckets( size_type n_bkt );
+ void dealloc_buckets( node**, size_type n_bkt );
+
+ node* alloc_node( value_type const& );
+ void dealloc_node( node* );
+ void dealloc_nodes( node**, size_type n_bkt );
+
+ size_type bucket( key_type const &key, size_type n_bkt ) const {
+ return bucket_for_code( hasher_( key ), n_bkt );
+ }
+
+ size_type bucket_for_code( hash_code_type code ) const {
+ return bucket_for_code( code, n_bkt_ );
+ }
+
+ size_type bucket_for_code( hash_code_type code, size_type n_bkt ) const {
+ return code % n_bkt;
+ }
+
+ void rehash_impl( size_type new_n_bkt );
+
+ node **buckets_;
+ hasher hasher_;
+ KeyEqual equal_;
+ KeyExtract key_of;
+ size_type n_bkt_;
+ size_type n_elt_;
+ node_alloc_type node_alloc_;
+ rehash_policy_type rehash_policy_;
+};
+
+#define ZORBA_HASHTABLE_TEMPLATE \
+ template<typename K,typename V,class X,class H,class E,class A,class RP>
+
+#define ZORBA_HASHTABLE_CLASS hashtable_base<K,V,X,H,E,A,RP>
+
+////////// hashtable_base inline functions ////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE inline
+ZORBA_HASHTABLE_CLASS::~hashtable_base() {
+ clear();
+ dealloc_buckets( buckets_, n_bkt_ );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::begin() {
+ return iterator( buckets_, buckets_[0] );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_iterator
+ZORBA_HASHTABLE_CLASS::begin() const {
+ return const_iterator( buckets_, buckets_[0] );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_iterator
+ZORBA_HASHTABLE_CLASS::cbegin() const {
+ return begin();
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::local_iterator
+ZORBA_HASHTABLE_CLASS::begin( size_type bkt ) {
+ return local_iterator( buckets_[ bkt ] );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_local_iterator
+ZORBA_HASHTABLE_CLASS::begin( size_type bkt ) const {
+ return const_local_iterator( buckets_[ bkt ] );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_local_iterator
+ZORBA_HASHTABLE_CLASS::cbegin( size_type bkt ) const {
+ return begin( bkt );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::bucket( key_type const &key ) const {
+ return bucket_for_code( hasher_( key ) );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::bucket_count() const {
+ return n_bkt_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::bucket_size( size_type bkt ) const {
+ return std::distance( begin( bkt ), end( bkt ) );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+void ZORBA_HASHTABLE_CLASS::clear() {
+ dealloc_nodes( buckets_, n_bkt_ );
+ n_elt_ = 0;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+bool ZORBA_HASHTABLE_CLASS::empty() const {
+ return size() == 0;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::end() {
+ return iterator( buckets_ + n_bkt_, buckets_[ n_bkt_ ] );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_iterator
+ZORBA_HASHTABLE_CLASS::end() const {
+ return const_iterator( buckets_ + n_bkt_, buckets_[ n_bkt_ ] );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_iterator
+ZORBA_HASHTABLE_CLASS::cend() const {
+ return end();
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::local_iterator
+ZORBA_HASHTABLE_CLASS::end( size_type bkt ) {
+ return local_iterator( nullptr );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_local_iterator
+ZORBA_HASHTABLE_CLASS::end( size_type bkt ) const {
+ return const_local_iterator( nullptr );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_local_iterator
+ZORBA_HASHTABLE_CLASS::cend( size_type bkt ) const {
+ return end( bkt );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::erase( iterator i ) {
+ return erase( const_iterator( i ) );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::allocator_type
+ZORBA_HASHTABLE_CLASS::get_allocator() const {
+ return allocator_type( node_alloc_ );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::hasher
+ZORBA_HASHTABLE_CLASS::hash_function() const {
+ return hasher_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::insert( const_iterator, value_type const &value ) {
+ return insert( value ).first;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::key_equal
+ZORBA_HASHTABLE_CLASS::key_eq() const {
+ return equal_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+float ZORBA_HASHTABLE_CLASS::load_factor() const {
+ return static_cast<float>( size() ) / static_cast<float>( bucket_count() );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::max_bucket_count() const {
+ return max_size();
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+float ZORBA_HASHTABLE_CLASS::max_load_factor() const {
+ return rehash_policy_.max_load_factor();
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::max_size() const {
+ return node_alloc_.max_size();
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+void ZORBA_HASHTABLE_CLASS::rehash( size_type new_n_bkt ) {
+ rehash_impl(
+ std::max(
+ rehash_policy_.adjust_buckets( new_n_bkt ),
+ rehash_policy_.buckets_for_elements( n_elt_ + 1 )
+ )
+ );
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::size() const {
+ return n_elt_;
+}
+
+////////// local_iterator inline functions ////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::reference
+ZORBA_HASHTABLE_CLASS::local_iterator::operator*() const {
+ return cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::pointer
+ZORBA_HASHTABLE_CLASS::local_iterator::operator->() const {
+ return &cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::local_iterator&
+ZORBA_HASHTABLE_CLASS::local_iterator::operator++() {
+ cur_node_ = cur_node_->next_;
+ return *this;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::local_iterator
+ZORBA_HASHTABLE_CLASS::local_iterator::operator++(int) {
+ local_iterator const temp( cur_node_ );
+ cur_node_ = cur_node_->next_;
+ return temp;
+}
+
+////////// const_local_iterator inline functions //////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_reference
+ZORBA_HASHTABLE_CLASS::const_local_iterator::operator*() const {
+ return cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_pointer
+ZORBA_HASHTABLE_CLASS::const_local_iterator::operator->() const {
+ return &cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_local_iterator&
+ZORBA_HASHTABLE_CLASS::const_local_iterator::operator++() {
+ cur_node_ = cur_node_->next_;
+ return *this;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_local_iterator
+ZORBA_HASHTABLE_CLASS::const_local_iterator::operator++(int) {
+ const_local_iterator const temp( cur_node_ );
+ cur_node_ = cur_node_->next_;
+ return temp;
+}
+
+////////// iterator inline functions //////////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::reference
+ZORBA_HASHTABLE_CLASS::iterator::operator*() const {
+ return cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::pointer
+ZORBA_HASHTABLE_CLASS::iterator::operator->() const {
+ return &cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::iterator&
+ZORBA_HASHTABLE_CLASS::iterator::operator++() {
+ if ( !(cur_node_ = cur_node_->next_) )
+ inc_bucket();
+ return *this;
+}
+
+////////// const_iterator inline functions ////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE inline
+ZORBA_HASHTABLE_CLASS::const_iterator::const_iterator( iterator const &i ) :
+ cur_bkt_( i.cur_bkt_ ), cur_node_( i.cur_node_ )
+{
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_reference
+ZORBA_HASHTABLE_CLASS::const_iterator::operator*() const {
+ return cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_pointer
+ZORBA_HASHTABLE_CLASS::const_iterator::operator->() const {
+ return &cur_node_->value_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE inline
+typename ZORBA_HASHTABLE_CLASS::const_iterator&
+ZORBA_HASHTABLE_CLASS::const_iterator::operator++() {
+ if ( !(cur_node_ = cur_node_->next_) )
+ inc_bucket();
+ return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A hash-table implementation for when KeyType is the same as ValueType. This
+ * is used as the base class for unordered_set.
+ *
+ * @tparam KeyType They map's key type.
+ * @tparam ValueType The type the keys are mapped to.
+ * @tparam KeyExtract The unary_function to use to extract a key from a value.
+ * @tparam KeyHash The unary_function to use for generating hash codes.
+ * @tparam KeyEqual The binary_function to use to test for key equality.
+ * @tparam Allocator The allocator to use.
+ * @tparam RehashPolicy The rehash policy class to use.
+ */
+template<
+ typename KeyType,
+ typename ValueType,
+ class KeyExtract,
+ class KeyHash,
+ class KeyEqual,
+ class Allocator,
+ class RehashPolicy
+>
+class hashtable :
+ public hashtable_base<KeyType,ValueType,KeyExtract,KeyHash,KeyEqual,Allocator,
+ RehashPolicy>
+{
+ typedef hashtable_base<KeyType,ValueType,KeyExtract,KeyHash,KeyEqual,
+ Allocator,RehashPolicy> base_type;
+public:
+ typedef typename base_type::key_type key_type;
+ typedef typename base_type::value_type value_type;
+ typedef typename base_type::hasher hasher;
+ typedef typename base_type::key_equal key_equal;
+ typedef typename base_type::allocator_type allocator_type;
+ typedef typename base_type::size_type size_type;
+ typedef typename base_type::difference_type difference_type;
+
+ typedef typename base_type::pointer pointer;
+ typedef typename base_type::const_pointer const_pointer;
+ typedef typename base_type::reference reference;
+ typedef typename base_type::const_reference const_reference;
+
+ /**
+ * Constructs a %hashtable.
+ *
+ * @param bucket_count The initial number of buckets to use.
+ * @param hash The hash-code unary functor to use.
+ * @param equal The key-equality functor to use.
+ * @param alloc The allocator to use.
+ */
+ hashtable( size_type bucket_count, hasher const &hash, key_equal const &equal,
+ allocator_type const &alloc ) :
+ base_type( bucket_count, hash, equal, alloc )
+ {
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Specialization of %hashtable for use when the "value" is actually a
+ * <code>pair<KeyType const,Value></code>. This is used as the base
+ * class for unordered_map. This specialization also adds \c mapped_type,
+ * \c at(), and \c operator[]() members.
+ *
+ * @tparam KeyType They map's key type.
+ * @tparam PairType The <code>pair<KeyType const,Value></code>.
+ * @tparam KeyExtract The unary_function to use to extract a key from a pair.
+ * @tparam KeyHash The unary_function to use for generating hash codes.
+ * @tparam KeyEqual The binary_function to use to test for key equality.
+ * @tparam Allocator The allocator to use.
+ * @tparam RehashPolicy The rehash policy class to use.
+ */
+template<
+ typename KeyType,
+ class PairType,
+ class KeyHash,
+ class KeyEqual,
+ class Allocator,
+ class RehashPolicy
+>
+class hashtable<KeyType,PairType,select1st<PairType>,KeyHash,KeyEqual,
+ Allocator,RehashPolicy> :
+ public hashtable_base<KeyType,PairType,select1st<PairType>,KeyHash,KeyEqual,
+ Allocator,RehashPolicy>
+{
+ typedef hashtable_base<KeyType,PairType,select1st<PairType>,KeyHash,KeyEqual,
+ Allocator,RehashPolicy> base_type;
+ typedef typename base_type::node node;
+public:
+ typedef typename base_type::key_type key_type;
+ typedef typename base_type::value_type value_type;
+ typedef typename PairType::second_type mapped_type;
+ typedef typename base_type::hasher hasher;
+ typedef typename base_type::key_equal key_equal;
+ typedef typename base_type::allocator_type allocator_type;
+ typedef typename base_type::size_type size_type;
+ typedef typename base_type::difference_type difference_type;
+
+ typedef typename base_type::pointer pointer;
+ typedef typename base_type::const_pointer const_pointer;
+ typedef typename base_type::reference reference;
+ typedef typename base_type::const_reference const_reference;
+
+ /**
+ * Constructs a %hashtable.
+ *
+ * @param bucket_count The initial number of buckets to use.
+ * @param hash The hash-code unary functor to use.
+ * @param equal The key-equality functor to use.
+ * @param alloc The allocator to use.
+ */
+ hashtable( size_type bucket_count, hasher const &hash, key_equal const &equal,
+ allocator_type const &alloc ) :
+ base_type( bucket_count, hash, equal, alloc )
+ {
+ }
+
+ /**
+ * Attempts to find the given \a key.
+ *
+ * @param key The key to find.
+ * @return Returns a reference to the value associated with \a key.
+ * @throws std::out_of_range if \a key is not found.
+ */
+ mapped_type& at( key_type const &key );
+
+ /**
+ * Attempts to find the given \a key.
+ *
+ * @param key The key to find.
+ * @return Returns a reference to the value associated with \a key.
+ * @throws std::out_of_range if \a key is not found.
+ */
+ mapped_type const& at( key_type const &key ) const;
+
+ /**
+ * Attempts to find the given \a key.
+ *
+ * @param key The key to find.
+ * @return If found, returns a reference to the value associated with \a key;
+ * if not, creates a new key/value pair and returns a reference to the newly
+ * created value.
+ */
+ mapped_type& operator[]( key_type const &key );
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace ztd
+} // namespace zorba
+
+#include "hashtable.tcc"
+
+#endif /* ZORBA_HASHTABLE_H */
+/* vim:set et ts=2 sw=2: */
=== added file 'src/util/hash/hashtable.tcc'
--- src/util/hash/hashtable.tcc 1970-01-01 00:00:00 +0000
+++ src/util/hash/hashtable.tcc 2012-06-16 14:48:21 +0000
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_HASHTABLE_TCC
+#define ZORBA_HASHTABLE_TCC
+
+#include <stdexcept>
+
+#ifndef ZORBA_HASHTABLE_H
+#error "This file is not meant to be included directly."
+#endif /* ZORBA_HASHTABLE_H */
+
+namespace zorba {
+namespace ztd {
+
+////////// hashtable_base functions ///////////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::node**
+ZORBA_HASHTABLE_CLASS::alloc_buckets( size_type n_bkt ) {
+ bucket_alloc_type alloc( node_alloc_ );
+ //
+ // Allocate one extra bucket to be a sentinel containing an arbitrary
+ // non-null value. Iteration relies on this.
+ //
+ node **const p = alloc.allocate( n_bkt + 1 );
+ std::fill( p, p + n_bkt, static_cast<node*>( nullptr ) );
+ p[ n_bkt ] = reinterpret_cast<node*>( 0x1000 );
+ return p;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::node*
+ZORBA_HASHTABLE_CLASS::alloc_node( value_type const &v ) {
+ node *const p = node_alloc_.allocate( 1 );
+ try {
+ node_alloc_.construct( p, v );
+ p->next_ = nullptr;
+ return p;
+ }
+ catch ( ... ) {
+ node_alloc_.deallocate( p, 1 );
+ throw;
+ }
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::dealloc_buckets( node **p, size_type n_bkt ) {
+ bucket_alloc_type alloc( node_alloc_ );
+ alloc.deallocate( p, n_bkt + 1 /* sentinel */ );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::dealloc_node( node *p ) {
+ node_alloc_.destroy( p );
+ node_alloc_.deallocate( p, 1 );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::dealloc_nodes( node **buckets, size_type n_bkt ) {
+ for ( size_type bkt = 0; bkt < n_bkt; ++bkt ) {
+ node *p = buckets[ bkt ];
+ while ( p ) {
+ node *const q = p;
+ p = p->next_;
+ dealloc_node( q );
+ }
+ buckets[ bkt ] = nullptr;
+ }
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+ZORBA_HASHTABLE_CLASS::hashtable_base( size_type bucket_count,
+ hasher const &hash,
+ key_equal const &equal,
+ allocator_type const &alloc ) :
+ equal_( equal ),
+ hasher_( hash ),
+ n_bkt_( bucket_count ),
+ n_elt_( 0 ),
+ node_alloc_( alloc )
+{
+ buckets_ = alloc_buckets( n_bkt_ );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+ZORBA_HASHTABLE_CLASS::hashtable_base( hashtable_base const &that ) :
+ equal_( that.equal_ ),
+ hasher_( that.hasher_ ),
+ n_bkt_( that.n_bkt_ ),
+ n_elt_( that.n_elt_ ),
+ node_alloc_( that.node_alloc_ )
+{
+ buckets_ = alloc_buckets( n_bkt_ );
+ try {
+ for ( size_type bkt = 0; bkt < n_bkt_; ++bkt ) {
+ node **tail = buckets_ + bkt;
+ for ( node *p = that.buckets_[ bkt ]; p; p = p->next_ ) {
+ *tail = alloc_node( p->value_ );
+ tail = &(*tail)->next_;
+ }
+ }
+ }
+ catch ( ... ) {
+ clear();
+ dealloc_buckets( buckets_, n_bkt_ );
+ throw;
+ }
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+ZORBA_HASHTABLE_CLASS&
+ZORBA_HASHTABLE_CLASS::operator=( hashtable_base const &that ) {
+ hashtable_base temp( that );
+ this->swap( temp );
+ return *this;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::count( key_type const &key ) const {
+ return !!find_node( key );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::erase( const_iterator pos ) {
+ iterator result( pos.cur_bkt_, pos.cur_node_ );
+ ++result;
+
+ node *cur = *pos.cur_bkt_;
+ if ( cur == pos.cur_node_ )
+ *pos.cur_bkt_ = cur->next_;
+ else {
+ node *next = cur->next_;
+ while ( next != pos.cur_node_ ) {
+ cur = next;
+ next = cur->next_;
+ }
+ cur->next_ = next->next_;
+ }
+
+ dealloc_node( pos.cur_node_ );
+ --n_elt_;
+
+ return result;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::erase( const_iterator i, const_iterator j ) {
+ while ( i != j )
+ i = erase( i );
+ return iterator( j.cur_bkt_, j.cur_node_ );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::size_type
+ZORBA_HASHTABLE_CLASS::erase( key_type const &key ) {
+ size_type const bkt = bucket( key );
+ for ( node *p = buckets_[ bkt ], **pp = &buckets_[ bkt ]; p;
+ pp = &p->next_, p = p->next_ ) {
+ if ( equal_( key_of( p->value_ ), key ) ) {
+ *pp = p->next_;
+ dealloc_node( p );
+ --n_elt_;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::find( key_type const &key ) {
+ size_type const bkt = bucket( key );
+ if ( node *const p = find_node( bkt, key ) )
+ return iterator( buckets_ + bkt, p );
+ return end();
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::const_iterator
+ZORBA_HASHTABLE_CLASS::find( key_type const &key ) const {
+ size_type const bkt = bucket( key );
+ if ( node *const p = find_node( bkt, key ) )
+ return const_iterator( buckets_ + bkt, p );
+ return end();
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+std::pair<typename ZORBA_HASHTABLE_CLASS::iterator,
+ typename ZORBA_HASHTABLE_CLASS::iterator>
+ZORBA_HASHTABLE_CLASS::equal_range( key_type const &key ) {
+ size_type const bkt = bucket( key );
+ node **const head = buckets_ + bkt;
+ if ( node *p = find_node( *head, key ) ) {
+ node *q = p->next_;
+ for ( ; q; q = q->next_ )
+ if ( !equal_( key_of( q->value_ ), key ) )
+ break;
+ iterator first( head, p );
+ iterator last( head, q );
+ if ( !q )
+ last.inc_bucket();
+ return std::make_pair( first, last );
+ }
+ return std::make_pair( end(), end() );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+std::pair<typename ZORBA_HASHTABLE_CLASS::const_iterator,
+ typename ZORBA_HASHTABLE_CLASS::const_iterator>
+ZORBA_HASHTABLE_CLASS::equal_range( key_type const &key ) const {
+ size_type const bkt = bucket( key );
+ node **const head = buckets_ + bkt;
+ if ( node *p = find_node( *head, key ) ) {
+ node *q = p->next_;
+ for ( ; q; q = q->next_ )
+ if ( !equal_( key_of( q->value_ ), key ) )
+ break;
+ const_iterator first( head, p );
+ const_iterator last( head, q );
+ if ( !q )
+ last.inc_bucket();
+ return std::make_pair( first, last );
+ }
+ return std::make_pair( end(), end() );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::node*
+ZORBA_HASHTABLE_CLASS::find_node( node *p, key_type const &key ) const {
+ for ( ; p; p = p->next_ )
+ if ( equal_( key_of( p->value_ ), key ) )
+ return p;
+ return nullptr;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+std::pair<typename ZORBA_HASHTABLE_CLASS::iterator,bool>
+ZORBA_HASHTABLE_CLASS::insert( value_type const &value ) {
+ key_type const &key = key_of( value );
+ size_type const bkt = bucket( key );
+ node *&head = buckets_[ bkt ];
+
+ if ( node *const p = find_node( head, key ) )
+ return std::make_pair( iterator( &head, p ), false );
+ return insert( bkt, value );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+std::pair<typename ZORBA_HASHTABLE_CLASS::iterator,bool>
+ZORBA_HASHTABLE_CLASS::insert( size_type bkt, value_type const &value ) {
+ //
+ // Allocate the new node before doing the rehash (if any) so that we don't do
+ // a rehash if the allocation throws an exception.
+ //
+ node *const p = alloc_node( value );
+
+ size_type const new_n_bkt = rehash_policy_.need_rehash( n_bkt_, n_elt_, 1 );
+
+ try {
+ if ( new_n_bkt ) {
+ rehash_impl( new_n_bkt );
+ bkt = bucket( key_of( value ) );
+ }
+ node *&head = buckets_[ bkt ];
+ p->next_ = head;
+ head = p;
+ ++n_elt_;
+ return std::make_pair( iterator( &head, p ), true );
+ }
+ catch ( ... ) {
+ dealloc_node( p );
+ throw;
+ }
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+template<class InputIterator>
+void ZORBA_HASHTABLE_CLASS::insert( InputIterator first, InputIterator last ) {
+ size_type const n_ins = std::distance( first, last );
+ size_type const new_n_bkt =
+ rehash_policy_.need_rehash( n_bkt_, n_elt_, n_ins );
+ if ( new_n_bkt )
+ rehash_impl( new_n_bkt );
+ for ( ; first != last; ++first )
+ insert( *first );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::max_load_factor( float load_factor ) {
+ if ( load_factor <= 0 )
+ throw std::invalid_argument( "load_factor <= 0" );
+ rehash_policy_ = rehash_policy_type( load_factor );
+ size_type const n_bkt = rehash_policy_.buckets_for_elements( n_elt_ );
+ if ( n_bkt > n_bkt_ )
+ rehash_impl( n_bkt );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::rehash_impl( size_type new_n_bkt ) {
+ node **const new_buckets = alloc_buckets( new_n_bkt );
+ try {
+ for ( size_type bkt = 0; bkt < n_bkt_; ++bkt ) {
+ node *&head = buckets_[ bkt ];
+ while ( node *p = head ) {
+ size_type const new_bkt = bucket( key_of( p->value_ ), new_n_bkt );
+ head = p->next_;
+ p->next_ = new_buckets[ new_bkt ];
+ new_buckets[ new_bkt ] = p;
+ }
+ }
+ dealloc_buckets( buckets_, n_bkt_ );
+ buckets_ = new_buckets;
+ n_bkt_ = new_n_bkt;
+ }
+ catch ( ... ) {
+ dealloc_nodes( new_buckets, new_n_bkt );
+ dealloc_buckets( new_buckets, new_n_bkt );
+ clear();
+ throw;
+ }
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::swap( hashtable_base &that ) {
+ std::swap( buckets_, that.buckets_ );
+ std::swap( equal_, that.equal_ );
+ std::swap( hasher_, that.hasher_ );
+ std::swap( n_bkt_, that.n_bkt_ );
+ std::swap( n_elt_, that.n_elt_ );
+ std::swap( node_alloc_, that.node_alloc_ );
+ std::swap( rehash_policy_, that.rehash_policy_ );
+}
+
+////////// iterator functions /////////////////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE
+ZORBA_HASHTABLE_CLASS::iterator::iterator( node **bkt, node *p ) :
+ cur_bkt_( bkt ), cur_node_( p )
+{
+ while ( !cur_node_ )
+ cur_node_ = *++cur_bkt_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::iterator::inc_bucket() {
+ while ( !*++cur_bkt_ )
+ ;
+ cur_node_ = *cur_bkt_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::iterator
+ZORBA_HASHTABLE_CLASS::iterator::operator++(int) {
+ iterator const temp( cur_bkt_, cur_node_ );
+ operator++();
+ return temp;
+}
+
+////////// const_iterator functions ///////////////////////////////////////////
+
+ZORBA_HASHTABLE_TEMPLATE
+ZORBA_HASHTABLE_CLASS::const_iterator::const_iterator( node **bkt, node *p ) :
+ cur_bkt_( bkt ), cur_node_( p )
+{
+ while ( !cur_node_ )
+ cur_node_ = *++cur_bkt_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+void ZORBA_HASHTABLE_CLASS::const_iterator::inc_bucket() {
+ while ( !*++cur_bkt_ )
+ ;
+ cur_node_ = *cur_bkt_;
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::const_iterator
+ZORBA_HASHTABLE_CLASS::const_iterator::operator++(int) {
+ const_iterator const temp( cur_bkt_, cur_node_ );
+ operator++();
+ return temp;
+}
+
+#undef ZORBA_HASHTABLE_CLASS
+#undef ZORBA_HASHTABLE_TEMPLATE
+
+////////// hashtable specialization members ///////////////////////////////////
+
+#define ZORBA_HASHTABLE_TEMPLATE \
+ template<typename K,class P,class H,class E,class A,class RP>
+
+#define ZORBA_HASHTABLE_CLASS hashtable<K,P,select1st<P>,H,E,A,RP>
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::mapped_type&
+ZORBA_HASHTABLE_CLASS::at( key_type const &key ) {
+ if ( node *const p = this->find_node( key ) )
+ return p->value_.second;
+ throw std::out_of_range( "at()" );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::mapped_type const&
+ZORBA_HASHTABLE_CLASS::at( key_type const &key ) const {
+ if ( node const *const p = this->find_node( key ) )
+ return p->value_.second;
+ throw std::out_of_range( "at()" );
+}
+
+ZORBA_HASHTABLE_TEMPLATE
+typename ZORBA_HASHTABLE_CLASS::mapped_type&
+ZORBA_HASHTABLE_CLASS::operator[]( key_type const &key ) {
+ size_type const bkt = this->bucket( key );
+ if ( node *const p = this->find_node( bkt, key ) )
+ return p->value_.second;
+ return this->insert(
+ bkt, std::make_pair( key, mapped_type() )
+ ).first->second;
+}
+
+#undef ZORBA_HASHTABLE_CLASS
+#undef ZORBA_HASHTABLE_TEMPLATE
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace ztd
+} // namespace zorba
+
+#endif /* ZORBA_HASHTABLE_TCC */
+/* vim:set et ts=2 sw=2: */
=== added file 'src/util/hash/rehash_policy.cpp'
--- src/util/hash/rehash_policy.cpp 1970-01-01 00:00:00 +0000
+++ src/util/hash/rehash_policy.cpp 2012-06-16 14:48:21 +0000
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// standard
+#include <algorithm>
+#include <cmath>
+#include <iostream>
+
+// zorba
+#include <zorba/config.h>
+
+// local
+#include "rehash_policy.h"
+
+using namespace std;
+
+namespace zorba {
+namespace ztd {
+
+///////////////////////////////////////////////////////////////////////////////
+
+typedef unsigned long prime_type;
+
+static prime_type const primes[] = {
+ 2ul, 3ul, 5ul, 7ul, 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul, 37ul, 41ul,
+ 43ul, 47ul, 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul, 83ul, 89ul, 97ul,
+ 103ul, 109ul, 113ul, 127ul, 137ul, 139ul, 149ul, 157ul, 167ul, 179ul, 193ul,
+ 199ul, 211ul, 227ul, 241ul, 257ul, 277ul, 293ul, 313ul, 337ul, 359ul, 383ul,
+ 409ul, 439ul, 467ul, 503ul, 541ul, 577ul, 619ul, 661ul, 709ul, 761ul, 823ul,
+ 887ul, 953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, 1493ul, 1613ul, 1741ul,
+ 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, 2753ul, 2971ul, 3209ul, 3469ul,
+ 3739ul, 4027ul, 4349ul, 4703ul, 5087ul, 5503ul, 5953ul, 6427ul, 6949ul,
+ 7517ul, 8123ul, 8783ul, 9497ul, 10273ul, 11113ul, 12011ul, 12983ul, 14033ul,
+ 15173ul, 16411ul, 17749ul, 19183ul, 20753ul, 22447ul, 24281ul, 26267ul,
+ 28411ul, 30727ul, 33223ul, 35933ul, 38873ul, 42043ul, 45481ul, 49201ul,
+ 53201ul, 57557ul, 62233ul, 67307ul, 72817ul, 78779ul, 85229ul, 92203ul,
+ 99733ul, 107897ul, 116731ul, 126271ul, 136607ul, 147793ul, 159871ul,
+ 172933ul, 187091ul, 202409ul, 218971ul, 236897ul, 256279ul, 277261ul,
+ 299951ul, 324503ul, 351061ul, 379787ul, 410857ul, 444487ul, 480881ul,
+ 520241ul, 562841ul, 608903ul, 658753ul, 712697ul, 771049ul, 834181ul,
+ 902483ul, 976369ul, 1056323ul, 1142821ul, 1236397ul, 1337629ul, 1447153ul,
+ 1565659ul, 1693859ul, 1832561ul, 1982627ul, 2144977ul, 2320627ul, 2510653ul,
+ 2716249ul, 2938679ul, 3179303ul, 3439651ul, 3721303ul, 4026031ul, 4355707ul,
+ 4712381ul, 5098259ul, 5515729ul, 5967347ul, 6456007ul, 6984629ul, 7556579ul,
+ 8175383ul, 8844859ul, 9569143ul, 10352717ul, 11200489ul, 12117689ul,
+ 13109983ul, 14183539ul, 15345007ul, 16601593ul, 17961079ul, 19431899ul,
+ 21023161ul, 22744717ul, 24607243ul, 26622317ul, 28802401ul, 31160981ul,
+ 33712729ul, 36473443ul, 39460231ul, 42691603ul, 46187573ul, 49969847ul,
+ 54061849ul, 58488943ul, 63278561ul, 68460391ul, 74066549ul, 80131819ul,
+ 86693767ul, 93793069ul, 101473717ul, 109783337ul, 118773397ul, 128499677ul,
+ 139022417ul, 150406843ul, 162723577ul, 176048909ul, 190465427ul, 206062531ul,
+ 222936881ul, 241193053ul, 260944219ul, 282312799ul, 305431229ul, 330442829ul,
+ 357502601ul, 386778277ul, 418451333ul, 452718089ul, 489790921ul, 529899637ul,
+ 573292817ul, 620239453ul, 671030513ul, 725980837ul, 785430967ul, 849749479ul,
+ 919334987ul, 994618837ul, 1076067617ul, 1164186217ul, 1259520799ul,
+ 1362662261ul, 1474249943ul, 1594975441ul, 1725587117ul, 1866894511ul,
+ 2019773507ul, 2185171673ul, 2364114217ul, 2557710269ul, 2767159799ul,
+ 2993761039ul, 3238918481ul, 3504151727ul, 3791104843ul, 4101556399ul,
+ 4294967291ul,
+
+#if ZORBA_SIZEOF_LONG < 8
+ // Sentinel so we don't have to test the result of lower_bound().
+ 4294967291ul
+#else
+ 6442450933ul, 8589934583ul, 12884901857ul, 17179869143ul, 25769803693ul,
+ 34359738337ul, 51539607367ul, 68719476731ul, 103079215087ul, 137438953447ul,
+ 206158430123ul, 274877906899ul, 412316860387ul, 549755813881ul,
+ 824633720731ul, 1099511627689ul, 1649267441579ul, 2199023255531ul,
+ 3298534883309ul, 4398046511093ul, 6597069766607ul, 8796093022151ul,
+ 13194139533241ul, 17592186044399ul, 26388279066581ul, 35184372088777ul,
+ 52776558133177ul, 70368744177643ul, 105553116266399ul, 140737488355213ul,
+ 211106232532861ul, 281474976710597ul, 562949953421231ul, 1125899906842597ul,
+ 2251799813685119ul, 4503599627370449ul, 9007199254740881ul,
+ 18014398509481951ul, 36028797018963913ul, 72057594037927931ul,
+ 144115188075855859ul, 288230376151711717ul, 576460752303423433ul,
+ 1152921504606846883ul, 2305843009213693951ul, 4611686018427387847ul,
+ 9223372036854775783ul, 18446744073709551557ul, 18446744073709551557ul
+#endif /* ZORBA_SIZEOF_LONG */
+};
+
+static prime_type const *const primes_end =
+ primes + sizeof( primes ) / sizeof( primes[0] );
+
+///////////////////////////////////////////////////////////////////////////////
+
+inline void prime_rehash_policy::update_next_resize( size_type n_bkt ) const {
+ next_resize_ = static_cast<size_type>( ceil( n_bkt * max_load_factor_ ) );
+}
+
+prime_rehash_policy::prime_rehash_policy( float max_load_factor ) :
+ growth_factor_( 2.0F ),
+ max_load_factor_( max_load_factor ),
+ next_resize_( 0 )
+{
+}
+
+prime_rehash_policy::size_type
+prime_rehash_policy::adjust_buckets( size_type n_bkt ) const {
+ prime_type const *const p = lower_bound( primes, primes_end, n_bkt );
+ update_next_resize( *p );
+ return *p;
+}
+
+prime_rehash_policy::size_type
+prime_rehash_policy::buckets_for_elements( size_type n_elt ) const {
+ float const min_bkts = n_elt / max_load_factor_;
+ prime_type const *const p = lower_bound( primes, primes_end, min_bkts );
+ update_next_resize( *p );
+ return *p;
+}
+
+prime_rehash_policy::size_type
+prime_rehash_policy::need_rehash( size_type n_bkt, size_type n_elt,
+ size_type n_ins ) const {
+ if ( n_elt + n_ins > next_resize_ ) {
+ float min_bkts = (n_elt + n_ins) / max_load_factor_;
+ if ( min_bkts > n_bkt ) {
+ min_bkts = max( min_bkts, growth_factor_ * n_bkt );
+ prime_type const *const p = lower_bound( primes, primes_end, min_bkts );
+ update_next_resize( *p );
+ return *p;
+ } else {
+ update_next_resize( n_bkt );
+ }
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace ztd
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */
=== added file 'src/util/hash/rehash_policy.h'
--- src/util/hash/rehash_policy.h 1970-01-01 00:00:00 +0000
+++ src/util/hash/rehash_policy.h 2012-06-16 14:48:21 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_HASHTABLE_REHASH_POLICY_H
+#define ZORBA_HASHTABLE_REHASH_POLICY_H
+
+// standard
+#include <sys/types.h>
+
+namespace zorba {
+namespace ztd {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Provides a rehashing policy for hash tables that always uses prime numbers
+ * for the number of buckets.
+ */
+class prime_rehash_policy {
+public:
+ typedef std::size_t size_type;
+
+ enum {
+ /**
+ * The default number of buckets to create.
+ */
+ default_bucket_count = 11 // a prime number
+ };
+
+ /**
+ * Constructs a %prime_rehash_policy.
+ *
+ * @param max_load_factor The maximum load factor.
+ */
+ prime_rehash_policy( float max_load_factor = 1.0F );
+
+ /**
+ * Gets an adjusted bucket count for the given proposed number of buckets.
+ *
+ * @param n_bkt The proposed number of buckets.
+ * @return Returns a bucket count adjusted so as to be more optimal.
+ */
+ size_type adjust_buckets( size_type n_bkt ) const;
+
+ /**
+ * Calculates the number of buckets needed for the given number of elements
+ * under the maximum load factor.
+ *
+ * @param n_elt The number of elements.
+ * @return Returns said number of buckets.
+ */
+ size_type buckets_for_elements( size_type n_elt ) const;
+
+ /**
+ * Gets the maximum load factor.
+ *
+ * @return Returns said load factor.
+ */
+ float max_load_factor() const;
+
+ /**
+ * Determines whether a rehash ought to be done.
+ *
+ * @param n_bkt The current number of buckets.
+ * @param n_elt The current number of elements.
+ * @param n_ins The number of elements to be inserted.
+ * @return Returns a value > 0 (where the value is the new bucket count)
+ * if a rehash ought to be done; returns 0 if not.
+ */
+ size_type need_rehash( size_type n_bkt, size_type n_elt,
+ size_type n_ins ) const;
+
+private:
+ float growth_factor_;
+ float max_load_factor_;
+ mutable size_type next_resize_;
+
+ void update_next_resize( size_type ) const;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+inline float prime_rehash_policy::max_load_factor() const {
+ return max_load_factor_;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace ztd
+} // namespace std
+
+#endif /* ZORBA_HASHTABLE_REHASH_POLICY_H */
+/* vim:set et ts=2 sw=2: */
=== added file 'src/util/stl_misc.h'
--- src/util/stl_misc.h 1970-01-01 00:00:00 +0000
+++ src/util/stl_misc.h 2012-06-16 14:48:21 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_STL_MISC_H
+#define ZORBA_STL_MISC_H
+
+#include <zorba/config.h>
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ZORBA_CXX_NULLPTR
+
+
+#endif /* ZORBA_CXX_NULLPTR */
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef ZORBA_CXX_STATIC_ASSERT
+
+template<bool> struct zorba_static_assert; // intentionally undefined
+template<> struct zorba_static_assert<true> { };
+template<int> struct zorba_static_assert_type { };
+
+#define static_assert(expr,msg) \
+ typedef ::zorba_static_assert_type< \
+ sizeof( ::zorba_static_assert<(expr) != 0> ) \
+ > zorba_static_assert_type_##__LINE__
+
+#endif /* ZORBA_CXX_STATIC_ASSERT */
+
+///////////////////////////////////////////////////////////////////////////////
+
+#endif /* ZORBA_STL_MISC_H */
+/* vim:set et sw=2 ts=2: */
=== modified file 'src/util/stl_util.h'
--- src/util/stl_util.h 2012-06-15 21:31:03 +0000
+++ src/util/stl_util.h 2012-06-16 14:48:21 +0000
@@ -20,6 +20,7 @@
#include <algorithm>
#include <cassert>
#include <cstring>
+#include <functional>
#include <iterator>
#include <limits>
#include <set>
@@ -92,6 +93,36 @@
///////////////////////////////////////////////////////////////////////////////
/**
+ * Implementation of SGI's %identity extension.
+ * See: http://www.sgi.com/tech/stl/identity.html
+ */
+template<typename T>
+struct identity : std::unary_function<T,T> {
+ typedef T argument_type;
+ typedef T result_type;
+
+ result_type const& operator()( argument_type const &a ) const {
+ return a;
+ }
+};
+
+/**
+ * Implementation of SGI's %select1st extension.
+ * See: http://www.sgi.com/tech/stl/select1st.html
+ */
+template<typename PairType>
+struct select1st : std::unary_function<PairType,typename PairType::first_type> {
+ typedef PairType argument_type;
+ typedef typename PairType::first_type result_type;
+
+ result_type const& operator()( argument_type const &a ) const {
+ return a.first;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
* Determines whether the given type \c T is efficiently passed by value.
*/
template<typename T>
=== added file 'src/util/unordered_map.h'
--- src/util/unordered_map.h 1970-01-01 00:00:00 +0000
+++ src/util/unordered_map.h 2012-06-16 14:48:21 +0000
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#ifndef ZORBA_UNORDERED_MAP_H
+#define ZORBA_UNORDERED_MAP_H
+
+#include <zorba/config.h>
+
+#ifdef ZORBA_HAVE_UNORDERED_MAP
+# include <unordered_map> /* use the implementation version */
+#else
+
+// standard
+#include <utility> /* for pair */
+
+// local
+#include "util/hash/hash.h"
+#include "util/hash/hashtable.h"
+#include "util/hash/rehash_policy.h"
+#ifndef ZORBA_UNORDERED_MAP_REHASH_POLICY
+# define ZORBA_UNORDERED_MAP_REHASH_POLICY zorba::ztd::prime_rehash_policy
+#endif /* ZORBA_UNORDERED_MAP_REHASH_POLICY */
+#include "cxx_util.h"
+#include "stl_util.h"
+
+namespace std {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This is an implementation of the C++ %unordered_map class, but for C++98.
+ * As such, it lacks member functions that use r-value references.
+ *
+ * @tparam KeyType They map's key type.
+ * @tparam MappedType The type the keys are mapped to.
+ * @tparam KeyHash The unary_function to use for generating hash codes.
+ * @tparam KeyEqual The binary_function to use to test for key equality.
+ * @tparam Allocator The allocator to use.
+ */
+template<
+ typename KeyType,
+ typename ValueType,
+ class KeyHash = std::hash<KeyType>,
+ class KeyEqual = std::equal_to<KeyType>,
+ class Allocator = std::allocator< std::pair<KeyType const,ValueType> >
+>
+class unordered_map :
+ public zorba::ztd::hashtable<
+ KeyType, std::pair<KeyType const,ValueType>,
+ zorba::ztd::select1st<std::pair<KeyType const,ValueType> >,
+ KeyHash, KeyEqual, Allocator, ZORBA_UNORDERED_MAP_REHASH_POLICY
+ >
+{
+ typedef zorba::ztd::hashtable<
+ KeyType, std::pair<KeyType const,ValueType>,
+ zorba::ztd::select1st<std::pair<KeyType const,ValueType> >,
+ KeyHash, KeyEqual, Allocator, ZORBA_UNORDERED_MAP_REHASH_POLICY
+ > base_type;
+
+ typedef typename base_type::rehash_policy_type rehash_policy_type;
+public:
+ typedef typename base_type::key_type key_type;
+ typedef typename base_type::value_type value_type;
+ typedef typename base_type::hasher hasher;
+ typedef typename base_type::key_equal key_equal;
+ typedef typename base_type::allocator_type allocator_type;
+
+ typedef typename base_type::pointer pointer;
+ typedef typename base_type::const_pointer const_pointer;
+ typedef typename base_type::reference reference;
+ typedef typename base_type::const_reference const_reference;
+
+ typedef typename base_type::size_type size_type;
+ typedef typename base_type::difference_type difference_type;
+
+ typedef typename base_type::local_iterator local_iterator;
+ typedef typename base_type::const_local_iterator const_local_iterator;
+ typedef typename base_type::iterator iterator;
+ typedef typename base_type::const_iterator const_iterator;
+
+ /**
+ * Constructs an %unordered_map.
+ *
+ * @param bucket_count The initial number of buckets.
+ * @param hash The unary_function to use for generating hash codes.
+ * @param equal The binary_function to use to test for key equality.
+ * @param alloc The allocator to use.
+ */
+ explicit unordered_map(
+ size_type bucket_count = rehash_policy_type::default_bucket_count,
+ hasher const &hash = hasher(),
+ key_equal const &equal = key_equal(),
+ allocator_type const &alloc = allocator_type()
+ ) :
+ base_type( bucket_count, hash, equal, alloc )
+ {
+ }
+
+ /**
+ * Constructs an %unordered_map.
+ *
+ * @param alloc The allocator to use.
+ */
+ explicit unordered_map( allocator_type const &alloc ) : base_type( alloc ) {
+ }
+
+ /**
+ * Copy-constructs an %unordered_map.
+ *
+ * @param that The %unordered_map to copy from.
+ */
+ unordered_map( unordered_map const &that ) : base_type( that ) {
+ }
+
+ /**
+ * Assignment.
+ *
+ * @param that The %unordered_map to assign from.
+ */
+ unordered_map& operator=( unordered_map const &that ) {
+ base_type::operator=( that );
+ return *this;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Global %swap operator for unordered_map.
+ *
+ * @param a The first unordered_map.
+ * @param b The second unordered_map.
+ */
+template<typename K,typename M,class H,class E,class A> inline
+void swap( unordered_map<K,M,H,E,A> &a, unordered_map<K,M,H,E,A> &b ) {
+ a.swap( b );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace std
+
+#endif /* ZORBA_HAVE_UNORDERED_MAP */
+#endif /* ZORBA_UNORDERED_MAP_H */
+/* vim:set et ts=2 sw=2: */
=== added file 'src/util/unordered_set.h'
--- src/util/unordered_set.h 1970-01-01 00:00:00 +0000
+++ src/util/unordered_set.h 2012-06-16 14:48:21 +0000
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#ifndef ZORBA_UNORDERED_SET_H
+#define ZORBA_UNORDERED_SET_H
+
+#include <zorba/config.h>
+
+#ifdef ZORBA_HAVE_UNORDERED_SET
+# include <unordered_set> /* use the implementation version */
+#else
+
+// local
+#include "util/hash/hash.h"
+#include "util/hash/hashtable.h"
+#include "util/hash/rehash_policy.h"
+#ifndef ZORBA_UNORDERED_SET_REHASH_POLICY
+# define ZORBA_UNORDERED_SET_REHASH_POLICY zorba::ztd::prime_rehash_policy
+#endif /* ZORBA_UNORDERED_SET_REHASH_POLICY */
+#include "cxx_util.h"
+#include "stl_util.h"
+
+namespace std {
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * This is an implementation of the C++ %unordered_set class, but for C++98.
+ * As such, it lacks member functions that use r-value references.
+ *
+ * @tparam KeyType They set's key type.
+ * @tparam KeyHash The unary_function to use for generating hash codes.
+ * @tparam KeyEqual The binary_function to use to test for value equality.
+ * @tparam Allocator The allocator to use.
+ */
+template<
+ typename KeyType,
+ class KeyHash = std::hash<KeyType>,
+ class KeyEqual = std::equal_to<KeyType>,
+ class Allocator = std::allocator<KeyType>
+>
+class unordered_set :
+ public zorba::ztd::hashtable<
+ KeyType, KeyType, zorba::ztd::identity<KeyType>,
+ KeyHash, KeyEqual, Allocator, ZORBA_UNORDERED_SET_REHASH_POLICY
+ >
+{
+ typedef zorba::ztd::hashtable<
+ KeyType, KeyType, zorba::ztd::identity<KeyType>,
+ KeyHash, KeyEqual, Allocator, ZORBA_UNORDERED_SET_REHASH_POLICY
+ > base_type;
+
+ typedef typename base_type::rehash_policy_type rehash_policy_type;
+public:
+ typedef typename base_type::key_type key_type;
+ typedef typename base_type::value_type value_type;
+ typedef typename base_type::hasher hasher;
+ typedef typename base_type::key_equal key_equal;
+ typedef typename base_type::allocator_type allocator_type;
+
+ typedef typename base_type::pointer pointer;
+ typedef typename base_type::const_pointer const_pointer;
+ typedef typename base_type::reference reference;
+ typedef typename base_type::const_reference const_reference;
+
+ typedef typename base_type::size_type size_type;
+ typedef typename base_type::difference_type difference_type;
+
+ typedef typename base_type::local_iterator local_iterator;
+ typedef typename base_type::const_local_iterator const_local_iterator;
+ typedef typename base_type::iterator iterator;
+ typedef typename base_type::const_iterator const_iterator;
+
+ /**
+ * Constructs an %unordered_set.
+ *
+ * @param bucket_count The initial number of buckets.
+ * @param hash The unary_function to use for generating hash codes.
+ * @param equal The binary_function to use to test for key equality.
+ * @param alloc The allocator to use.
+ */
+ explicit unordered_set(
+ size_type bucket_count = rehash_policy_type::default_bucket_count,
+ hasher const &hash = hasher(),
+ key_equal const &equal = key_equal(),
+ allocator_type const &alloc = allocator_type()
+ ) :
+ base_type( bucket_count, hash, equal, alloc )
+ {
+ }
+
+ /**
+ * Constructs an %unordered_set.
+ *
+ * @param alloc The allocator to use.
+ */
+ explicit unordered_set( allocator_type const &alloc ) : base_type( alloc ) {
+ }
+
+ /**
+ * Copy-constructs an %unordered_set.
+ *
+ * @param that The %unordered_set to copy from.
+ */
+ unordered_set( unordered_set const &that ) : base_type( that ) {
+ }
+
+ /**
+ * Assignment.
+ *
+ * @param that The %unordered_set to assign from.
+ */
+ unordered_set& operator=( unordered_set const &that ) {
+ base_type::operator=( that );
+ return *this;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Global %swap operator for unordered_set.
+ *
+ * @param a The first unordered_set.
+ * @param b The second unordered_set.
+ */
+template<typename V,class H,class E,class A> inline
+void swap( unordered_set<V,H,E,A> &a, unordered_set<V,H,E,A> &b ) {
+ a.swap( b );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace std
+
+#endif /* ZORBA_HAVE_UNORDERED_SET */
+#endif /* ZORBA_UNORDERED_SET_H */
+/* vim:set et ts=2 sw=2: */
Follow ups