瀏覽代碼

Adding hash set and test cases.

Samuel Jaffe 8 年之前
父節點
當前提交
4046cccae7
共有 3 個文件被更改,包括 460 次插入18 次删除
  1. 23 18
      bucket_hash_map.xcodeproj/project.pbxproj
  2. 233 0
      bucket_hash_set.hpp
  3. 204 0
      bucket_hash_set.t.h

+ 23 - 18
bucket_hash_map.xcodeproj/project.pbxproj

@@ -7,7 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		CD21AE101E4A130500536178 /* bucket_hash_map_tc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD21AE0E1E4A130500536178 /* bucket_hash_map_tc.cpp */; };
+		CD21AE101E4A130500536178 /* bucket_hash_tc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD21AE0E1E4A130500536178 /* bucket_hash_tc.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -23,10 +23,12 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-		CD21AE011E4A128F00536178 /* bucket_hash_map_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bucket_hash_map_tc; sourceTree = BUILT_PRODUCTS_DIR; };
-		CD21AE0E1E4A130500536178 /* bucket_hash_map_tc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bucket_hash_map_tc.cpp; sourceTree = "<group>"; };
+		CD21AE011E4A128F00536178 /* bucket_hash_tc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bucket_hash_tc; sourceTree = BUILT_PRODUCTS_DIR; };
+		CD21AE0E1E4A130500536178 /* bucket_hash_tc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bucket_hash_tc.cpp; sourceTree = "<group>"; };
 		CD21AE0F1E4A130500536178 /* bucket_hash_map.t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bucket_hash_map.t.h; sourceTree = "<group>"; };
 		CD21AE111E4A1F2A00536178 /* bucket_hash_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = bucket_hash_map.hpp; sourceTree = "<group>"; };
+		CD7172E61E5685F10048DFFF /* bucket_hash_set.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = bucket_hash_set.hpp; sourceTree = "<group>"; };
+		CD7172E71E57AEE20048DFFF /* bucket_hash_set.t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bucket_hash_set.t.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -52,7 +54,7 @@
 		CD21AE021E4A128F00536178 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				CD21AE011E4A128F00536178 /* bucket_hash_map_tc */,
+				CD21AE011E4A128F00536178 /* bucket_hash_tc */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -61,6 +63,7 @@
 			isa = PBXGroup;
 			children = (
 				CD21AE111E4A1F2A00536178 /* bucket_hash_map.hpp */,
+				CD7172E61E5685F10048DFFF /* bucket_hash_set.hpp */,
 			);
 			name = src;
 			sourceTree = "<group>";
@@ -69,7 +72,8 @@
 			isa = PBXGroup;
 			children = (
 				CD21AE0F1E4A130500536178 /* bucket_hash_map.t.h */,
-				CD21AE0E1E4A130500536178 /* bucket_hash_map_tc.cpp */,
+				CD7172E71E57AEE20048DFFF /* bucket_hash_set.t.h */,
+				CD21AE0E1E4A130500536178 /* bucket_hash_tc.cpp */,
 			);
 			name = test;
 			sourceTree = "<group>";
@@ -77,9 +81,9 @@
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-		CD21AE001E4A128F00536178 /* bucket_hash_map_tc */ = {
+		CD21AE001E4A128F00536178 /* bucket_hash_tc */ = {
 			isa = PBXNativeTarget;
-			buildConfigurationList = CD21AE081E4A128F00536178 /* Build configuration list for PBXNativeTarget "bucket_hash_map_tc" */;
+			buildConfigurationList = CD21AE081E4A128F00536178 /* Build configuration list for PBXNativeTarget "bucket_hash_tc" */;
 			buildPhases = (
 				CD21AE0D1E4A12CF00536178 /* ShellScript */,
 				CD21ADFD1E4A128F00536178 /* Sources */,
@@ -90,9 +94,9 @@
 			);
 			dependencies = (
 			);
-			name = bucket_hash_map_tc;
+			name = bucket_hash_tc;
 			productName = bucket_hash_map;
-			productReference = CD21AE011E4A128F00536178 /* bucket_hash_map_tc */;
+			productReference = CD21AE011E4A128F00536178 /* bucket_hash_tc */;
 			productType = "com.apple.product-type.tool";
 		};
 /* End PBXNativeTarget section */
@@ -109,7 +113,7 @@
 					};
 				};
 			};
-			buildConfigurationList = CD21ADFC1E4A128F00536178 /* Build configuration list for PBXProject "bucket_hash_map" */;
+			buildConfigurationList = CD21ADFC1E4A128F00536178 /* Build configuration list for PBXProject "bucket_hash" */;
 			compatibilityVersion = "Xcode 3.2";
 			developmentRegion = English;
 			hasScannedForEncodings = 0;
@@ -121,7 +125,7 @@
 			projectDirPath = "";
 			projectRoot = "";
 			targets = (
-				CD21AE001E4A128F00536178 /* bucket_hash_map_tc */,
+				CD21AE001E4A128F00536178 /* bucket_hash_tc */,
 			);
 		};
 /* End PBXProject section */
@@ -134,13 +138,14 @@
 			);
 			inputPaths = (
 				"$(SRCROOT)/bucket_hash_map.t.h",
+				"$(SRCROOT)/bucket_hash_set.t.h",
 			);
 			outputPaths = (
-				"$(SRCROOT)/bucket_hash_map_tc.cpp",
+				"$(SRCROOT)/bucket_hash_tc.cpp",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "cxxtestgen --error-printer -o bucket_hash_map_tc.cpp bucket_hash_map.t.h";
+			shellScript = "cxxtestgen --error-printer -o bucket_hash_tc.cpp bucket_hash_map.t.h bucket_hash_set.t.h";
 		};
 /* End PBXShellScriptBuildPhase section */
 
@@ -149,7 +154,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				CD21AE101E4A130500536178 /* bucket_hash_map_tc.cpp in Sources */,
+				CD21AE101E4A130500536178 /* bucket_hash_tc.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -242,7 +247,7 @@
 					/usr/local/include/,
 					../,
 				);
-				PRODUCT_NAME = "$(TARGET_NAME)";
+				PRODUCT_NAME = bucket_hash_tc;
 			};
 			name = Debug;
 		};
@@ -253,14 +258,14 @@
 					/usr/local/include/,
 					../,
 				);
-				PRODUCT_NAME = "$(TARGET_NAME)";
+				PRODUCT_NAME = bucket_hash_tc;
 			};
 			name = Release;
 		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-		CD21ADFC1E4A128F00536178 /* Build configuration list for PBXProject "bucket_hash_map" */ = {
+		CD21ADFC1E4A128F00536178 /* Build configuration list for PBXProject "bucket_hash" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				CD21AE061E4A128F00536178 /* Debug */,
@@ -269,7 +274,7 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
-		CD21AE081E4A128F00536178 /* Build configuration list for PBXNativeTarget "bucket_hash_map_tc" */ = {
+		CD21AE081E4A128F00536178 /* Build configuration list for PBXNativeTarget "bucket_hash_tc" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				CD21AE091E4A128F00536178 /* Debug */,

+ 233 - 0
bucket_hash_set.hpp

@@ -0,0 +1,233 @@
+//
+//  bucket_hash_set.hpp
+//  bucket_hash_set
+//
+//  Created by Sam Jaffe on 2/16/17.
+//
+
+#pragma once
+
+#include <algorithm>
+#include <list>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "iterator/join_iterator.hpp"
+
+template <typename K, typename Hash = std::hash<K>, typename KeyEqual = std::equal_to<K> >
+class bucket_hash_set;
+
+template <typename K, typename Hash, typename KeyEqual>
+class bucket_hash_set {
+public: // typedefs
+  using key_type = K;
+  using value_type = key_type const;
+  using size_type = std::size_t;
+  using difference_type = std::ptrdiff_t;
+  
+  using hasher = Hash;
+  using key_equal = KeyEqual;
+  
+  using reference = value_type &;
+  using const_reference = value_type const &;
+  using pointer = value_type *;
+  using const_pointer = value_type const *;
+  
+  using bucket_type = std::list<value_type>;
+  using impl_type = std::vector<bucket_type>;
+  
+  using iterator = joining_iterator<typename impl_type::iterator>;
+  using const_iterator = joining_iterator<typename impl_type::const_iterator>;
+  using local_iterator = typename bucket_type::const_iterator;
+  using local_const_iterator = typename bucket_type::const_iterator;
+  
+  static const constexpr size_type default_buckets = 10;
+  static const constexpr float default_load_factor = 1.0F;
+  static const constexpr float growth_factor = 2.0F;
+public:
+  // Construction
+  bucket_hash_set() : bucket_hash_set(default_buckets) {}
+  
+  bucket_hash_set(size_type num_buckets,
+                  hasher const & hash = hasher(),
+                  key_equal const & keq = key_equal()) :
+  buckets_(num_buckets), hasher_(hash), key_equals_(keq) {}
+  
+  template <typename InputIt>
+  bucket_hash_set(InputIt first, InputIt last,
+                  size_type num_buckets = default_buckets,
+                  hasher const & hash = hasher(),
+                  key_equal const & keq = key_equal())
+  : bucket_hash_set(num_buckets, hash, keq) {
+    insert(first, last);
+  }
+  
+  bucket_hash_set(std::initializer_list<value_type> && ilist,
+                  size_type num_buckets = default_buckets,
+                  hasher const & hash = hasher(),
+                  key_equal const & keq = key_equal())
+  : bucket_hash_set(num_buckets, hash, keq) {
+    insert(ilist);
+  }
+  
+  // Metadata
+  bool empty() const { return size() == 0; }
+  size_type size() const { return size_; }
+  
+  // Iterators
+  iterator begin() { return { buckets_.begin(), buckets_.end() }; }
+  const_iterator begin() const { return cbegin(); }
+  const_iterator cbegin() const { return { buckets_.begin(), buckets_.end() }; }
+  iterator end() { return { buckets_.end(), buckets_.end() }; }
+  const_iterator end() const { return cend(); }
+  const_iterator cend() const { return { buckets_.end(), buckets_.end() }; }
+  
+  // Create
+  std::pair<iterator, bool> insert(value_type const & vt) {
+    maybe_expand(1);
+    auto lookup = lookup_impl(buckets_, vt);
+    auto const end = lookup.first->end();
+    bool const create = lookup.second == end;
+    if ( create ) {
+      ++size_;
+      lookup.second = lookup.first->insert(end, vt);
+    }
+    return { {lookup.first, buckets_.end(), lookup.second, end}, create };
+  }
+  iterator insert(const_iterator, value_type const & vt) {
+    return insert(vt).first;
+  }
+  template <typename InputIt>
+  void insert(InputIt first, InputIt last) {
+    maybe_expand(std::distance(first, last));
+    while (first != last) { insert(*first++); }
+  }
+  void insert(std::initializer_list<value_type> ilist) { insert(ilist.begin(), ilist.end()); }
+  
+  // Access  
+  iterator find(key_type const & key) {
+    return find_impl<iterator>(buckets_, key);
+  }
+  std::pair<iterator, iterator> equal_range(key_type const & key) {
+    auto it = find(key);
+    return { it, ++iterator(it) };
+  }
+  const_iterator find(key_type const & key) const {
+    return find_impl<const_iterator>(buckets_, key);
+  }
+  std::pair<const_iterator, const_iterator> equal_range(key_type const & key) const {
+    auto it = find(key);
+    return { it, ++const_iterator(it) };
+  }
+  size_type count(key_type const & key) const { return find(key) != end(); }
+  
+  // Remove
+  iterator erase(const_iterator it) {
+    return erase_impl(unconst_iterator(it));
+  }
+  iterator erase(const_iterator first, const_iterator last) {
+    iterator it = unconst_iterator(first);
+    while (last != it) { it = erase_impl(it); }
+    return it;
+  }
+  size_type erase(key_type const & key) {
+    size_type old_size = size_;
+    erase(find(key));
+    return old_size - size_; // 1 or 0
+  }
+  void clear() { erase(begin(), end()); }
+  
+  // Bucket Interaction Functions
+  local_iterator begin(size_type bkt) { return buckets_[bkt].begin(); }
+  local_const_iterator begin(size_type bkt) const { return buckets_[bkt].cbegin(); }
+  local_const_iterator cbegin(size_type bkt) const { return buckets_[bkt].cbegin(); }
+  local_iterator end(size_type bkt) { return buckets_[bkt].end(); }
+  local_const_iterator end(size_type bkt) const { return buckets_[bkt].cend(); }
+  local_const_iterator cend(size_type bkt) const { return buckets_[bkt].cend(); }
+  size_type bucket_count() const { return buckets_.size(); }
+  size_type bucket_size(size_type bkt) const { return buckets_[bkt].size(); }
+  size_type bucket(key_type const & key) const { return hasher_(key) % bucket_count(); }
+  
+  // Hash Policy
+  float load_factor() const { return static_cast<float>(size()) / bucket_count(); }
+  float max_load_factor() const { return max_load_; }
+  void max_load_factor(float max_load) { max_load_ = max_load; }
+  void rehash(size_type buckets) {
+    buckets = std::max({1UL, buckets, static_cast<size_type>(size() / max_load_factor())});
+    bucket_hash_set next{buckets, hasher_, key_equals_};
+    next.max_load_factor(max_load_factor());
+    next.insert(begin(), end());
+    swap(next);
+  }
+  void reserve(size_type count) {
+    rehash(static_cast<size_type>(count / max_load_factor()));
+  }
+  
+  void swap( bucket_hash_set & other ) {
+    using std::swap;
+    swap(size_, other.size_);
+    swap(buckets_, other.buckets_);
+    swap(max_load_, other.max_load_);
+    swap(hasher_, other.hasher_);
+    swap(key_equals_, other.key_equals_);
+  }
+  friend void swap(bucket_hash_set & lhs, bucket_hash_set & rhs) { lhs.swap(rhs); }
+private:
+  void maybe_expand(size_type add) {
+    if ( static_cast<float>(size() + add) / bucket_count() > max_load_factor() ) {
+      reserve(std::max(size() + add, static_cast<size_type>(size() * growth_factor)));
+    }
+  }
+  
+  template <typename Bucket>
+  auto lookup_impl(Bucket & bkt, key_type const & key) const -> std::pair<decltype(bkt.begin()), decltype(bkt.begin()->begin())> {
+    auto listit = bkt.begin() + bucket(key);
+    auto it = search(listit, key);
+    return {listit, it};
+  }
+  
+  template <typename Iterator>
+  auto search(Iterator lit, key_type const & key) const -> decltype(lit->begin()) {
+    for ( auto it = lit->begin(); it != lit->end(); ++it ) {
+      if ( key_equals_(key, *it) ) { return it; }
+    }
+    return lit->end();
+  }
+  
+  template <typename Iterator, typename Bucket>
+  Iterator find_impl(Bucket & bkt, key_type const & key) const {
+    auto lookup = lookup_impl(bkt, key);
+    if (lookup.second == lookup.first->end()) {
+      return { bkt.end(), bkt.end() };
+    } else {
+      return { lookup.first, bkt.end(), lookup.second, lookup.first->end() };
+    }
+  }
+  
+  iterator unconst_iterator(const_iterator it) {
+    auto lit = it.join_iterator();
+    auto iter = it.element_iterator();
+    
+    if ( lit.done() ) { return end(); }
+    auto nit = buckets_.begin();
+    std::advance(nit, std::distance(buckets_.cbegin(), lit.current()));
+    
+    return { nit, buckets_.end(), nit->erase(iter.current(), iter.current()), nit->end() };
+  }
+  
+  iterator erase_impl(iterator it) {
+    auto b = it.join_iterator();
+    auto l = it.element_iterator();
+    if ( b.done() || l.done() ) { return it; }
+    --size_;
+    return { b.current(), b.end(), b->erase(l.current()), l.end(), true };
+  }
+private: // members
+  impl_type buckets_{default_buckets};
+  hasher hasher_;
+  key_equal key_equals_;
+  //allocator_type alloc_;
+  size_type size_{0};
+  float max_load_{default_load_factor};
+};

+ 204 - 0
bucket_hash_set.t.h

@@ -0,0 +1,204 @@
+//
+//  bucket_hash_set.t.h
+//  bucket_hash_map
+//
+//  Created by Sam Jaffe on 2/17/17.
+//
+
+#pragma once
+#include <cxxtest/TestSuite.h>
+
+#include "bucket_hash_set.hpp"
+
+class bucket_hash_set_TestSuite : public CxxTest::TestSuite {
+public:
+  using hashset = bucket_hash_set<int>;
+public:
+  // Construction Postconditions
+  void test_default_is_empty() {
+    TS_ASSERT( hashset{}.empty() );
+  }
+  
+  void test_construct_from_initializer_list() {
+    hashset hm{0, 1, 2};
+    TS_ASSERT_EQUALS(hm.size(), 3);
+  }
+  
+  void test_swap_hashsets() {
+    hashset hm1{};
+    hashset hm2{0, 1, 2};
+    swap(hm1, hm2);
+    TS_ASSERT(hm2.empty());
+    TS_ASSERT_EQUALS(hm1.size(), 3);
+  }
+  
+  // Insertion Behaviors
+  void test_insert_elements_effects_size() {
+    hashset hm{};
+    TS_ASSERT_THROWS_NOTHING( hm.insert(0) );
+    TS_ASSERT_EQUALS(hm.size(), 1);
+  }
+  
+  void test_insert_element_return_true() {
+    hashset hm{};
+    TS_ASSERT( hm.insert(0).second );
+  }
+  
+  void test_insert_element_return_iterator_to_elements() {
+    hashset hm{};
+    auto it = hm.insert(0).first;
+    TS_ASSERT_EQUALS( *it, 0 );
+  }
+  
+  void test_insert_same_element_does_not_create_duplicate() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_THROWS_NOTHING( hm.insert(0) );
+    TS_ASSERT_EQUALS(hm.size(), 1);
+  }
+  
+  void test_insert_same_element_returns_false() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT( !hm.insert(0).second );
+  }
+  
+  void test_insert_same_element_return_same_iterator() {
+    hashset hm{};
+    auto it = hm.insert(0).first;
+    TS_ASSERT_EQUALS(hm.insert(0).first, it);
+  }
+  
+  void test_can_insert_range() {
+    hashset hm{};
+    TS_ASSERT_THROWS_NOTHING(hm.insert({0, 0, 1}));
+  }
+  
+  // Find/Access Behaviors
+  void test_can_find_element_in_map() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_DIFFERS(hm.find(0), hm.end());
+  }
+  
+  void test_count_element_in_map() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(hm.count(0), 1);
+  }
+  
+  void test_count_element_not_in_map() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(hm.count(1), 0);
+  }
+  
+  void test_equal_range_contains_element_if_present() {
+    hashset hm{};
+    hm.insert(0);
+    auto p = hm.equal_range(0);
+    TS_ASSERT_DIFFERS(p.first, p.second);
+    TS_ASSERT_EQUALS(std::distance(p.first, p.second), 1);
+  }
+  
+  void test_equal_range_contains_end_if_absent() {
+    hashset hm{};
+    hm.insert(0);
+    auto p = hm.equal_range(1);
+    TS_ASSERT_EQUALS(p.first, p.second);
+    TS_ASSERT_EQUALS(p.first, hm.end());
+  }
+  
+  void test_found_element_is_as_expected() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(*hm.find(0), 0);
+  }
+  
+  void test_cannot_find_fake_element() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(hm.find(1), hm.end());
+  }
+    
+  // Iteration Behaviors
+  void test_iterator_advance_different() {
+    hashset hm{};
+    hm.insert(0);
+    hm.insert(1);
+    auto it = hm.begin();
+    auto it2 = ++hm.begin();
+    TS_ASSERT_DIFFERS(*it, *it2);
+  }
+  
+  void test_iterator_begin_is_end_if_empty() { // Test case in join iterator for empty first element
+    hashset hm{};
+    TS_ASSERT_EQUALS(hm.begin(), hm.end());
+  }
+  
+  void test_iterator_reaches_end() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(++hm.begin(), hm.end());
+  }
+  
+  // Erase Behaviors
+  void test_erasing_element_reduces_size() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_THROWS_NOTHING( hm.erase(hm.find(0)) );
+    TS_ASSERT_EQUALS(hm.size(), 0);
+  }
+  
+  void test_erase_end_is_fine() {
+    hashset hm{};
+    TS_ASSERT_THROWS_NOTHING(hm.erase(hm.end()));
+    hm.insert(0);
+    TS_ASSERT_THROWS_NOTHING(hm.erase(hm.end()));
+  }
+  
+  void test_erase_end_does_not_effect_size() {
+    hashset hm{};
+    hm.insert(0);
+    hm.erase(hm.end());
+    TS_ASSERT_EQUALS(hm.size(), 1);
+  }
+  
+  void test_erase_end_returns_end() {
+    hashset hm{};
+    TS_ASSERT_EQUALS(hm.erase(hm.end()), hm.end());
+  }
+  
+  void test_erase_key_missing_key_no_result() {
+    hashset hm{};
+    TS_ASSERT_EQUALS(hm.erase(0), 0);
+  }
+  
+  void test_erase_key_incorrect_key_no_result() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(hm.erase(1), 0);
+  }
+  
+  void test_erase_key_correct_key_one() {
+    hashset hm{};
+    hm.insert(0);
+    TS_ASSERT_EQUALS(hm.erase(0), 1);
+  }
+  
+  void test_erase_range() {
+    hashset hm{0, 1, 2};
+    auto it = hm.begin();
+    auto it2 = it;
+    std::advance(it2, 2);
+    TS_ASSERT_THROWS_NOTHING(hm.erase(it, it2));
+    TS_ASSERT_EQUALS(hm.size(), 1);
+  }
+  
+  void test_clear() {
+    hashset hm{0, 1, 2};
+    TS_ASSERT_THROWS_NOTHING(hm.clear());
+    TS_ASSERT(hm.empty());
+  }
+  
+};