size_t operator()(const Future& future) const // Return the hash of the of the specified 'future'. Note that // this uses the 'SpookyHashAlgorithm' to quickly combine the // attributes of 'Future' objects that are salient to hashing into // a hash suitable for a hash table. { SpookyHashAlgorithm hash; hash(future.getName(), strlen(future.getName())); hash(future.getMonth(), sizeof(char)); hash(future.getYear(), sizeof(short)); return static_cast<size_t>(hash.computeHash()); }
int main(int argc, char *argv[]) { int test = argc > 1 ? atoi(argv[1]) : 0; bool verbose = argc > 2; bool veryVerbose = argc > 3; bool veryVeryVerbose = argc > 4; // bool veryVeryVeryVerbose = argc > 5; printf("TEST " __FILE__ " CASE %d\n", test); switch (test) { case 0: case 5: { // -------------------------------------------------------------------- // USAGE EXAMPLE // The hashing algorithm can be used to create more powerful // components such as functors that can be used to power hash tables. // // Concerns: //: 1 The usage example provided in the component header file compiles, //: links, and runs as shown. // // Plan: //: 1 Incorporate usage example from header into test driver (C-1) // // Testing: // USAGE EXAMPLE // -------------------------------------------------------------------- if (verbose) printf("USAGE EXAMPLE\n" "=============\n"); // Then, we want to actually use our hash table on 'Future' objects. We // create an array of 'Future's based on data that was originally from some // external source: Future futures[] = { Future("Swiss Franc", 'F', 2014), Future("US Dollar", 'G', 2015), Future("Canadian Dollar", 'Z', 2014), Future("British Pound", 'M', 2015), Future("Deutsche Mark", 'X', 2016), Future("Eurodollar", 'Q', 2017)}; enum { NUM_FUTURES = sizeof futures / sizeof *futures }; // Next, we create our HashTable 'hashTable'. We pass the functor that we // defined above as the second argument: HashTable<Future, HashFuture> hashTable(futures, NUM_FUTURES); // Now, we verify that each element in our array registers with count: for ( int i = 0; i < 6; ++i) { ASSERT(hashTable.contains(futures[i])); } // Finally, we verify that futures not in our original array are correctly // identified as not being in the set: ASSERT(!hashTable.contains(Future("French Franc", 'N', 2019))); ASSERT(!hashTable.contains(Future("Swiss Franc", 'X', 2014))); ASSERT(!hashTable.contains(Future("US Dollar", 'F', 2014))); } break; case 4: { // -------------------------------------------------------------------- // TESTING 'result_type' TYPEDEF // Verify that the class offers the result_type typedef that needs to // be exposed by all 'bslh' hashing algorithms // // Concerns: //: 1 The typedef 'result_type' is publicly accessible and an alias for //: 'bslh::SpookyHashAlgorithm::result_type'. //: //: 2 'computeHash()' returns 'result_type' // // Plan: //: 1 ASSERT the typedef is accessible and is the correct type using //: 'bslmf::IsSame'. (C-1) //: //: 2 Declare the expected signature of 'computeHash()' and then assign //: to it. If it compiles, the test passes. (C-2) // // Testing: // typedef InternalHashAlgorithm::result_type result_type; // -------------------------------------------------------------------- if (verbose) printf("\nTESTING 'result_type' TYPEDEF" "\n=============================\n"); if (verbose) printf("ASSERT the typedef is accessible and is the" " correct type using 'bslmf::IsSame'. (C-1)\n"); { ASSERT((bslmf::IsSame<Obj::result_type, SpookyHashAlgorithm::result_type>::VALUE)); } if (verbose) printf("Declare the expected signature of 'computeHash()'" " and then assign to it. If it compiles, the test" " passes. (C-2)\n"); { Obj::result_type (Obj::*expectedSignature) (); expectedSignature = &Obj::computeHash; } } break; case 3: { // -------------------------------------------------------------------- // TESTING 'operator()' AND 'computeHash()' // Verify the class provides an overload for the function call // operator that can be called with some bytes and a length. Verify // that calling 'operator()' will permute the algorithm's internal // state as specified by the underlying hashing algorithm // (bslh::SpookyHashAlgorithm). Verify that 'computeHash()' returns // the final value specified by the canonical implementation of the // underlying hashing algorithm. // // Concerns: //: 1 The function call operator is callable. //: //: 2 The 'computeHash()' function is callable. //: //: 3 The output of calling 'operator()' and then 'computeHash()' //: matches the output of the underlying hashing algorithm. //: //: 4 'operator()' does a BSLS_ASSERT for null pointers. // // Plan: //: 1 Hash a number of values with 'bslh::DefaultHashAlgorithm' and //: 'bslh::SpookyHashAlgorithm' and verify that the outputs match. //: (C-1,2,3) //: //: 2 Call 'operator()' with a null pointer. (C-4) // // Testing: // void operator()(void const* key, size_t len); // result_type computeHash(); // -------------------------------------------------------------------- if (verbose) printf( "\nTESTING 'operator()' AND 'computeHash()'" "\n========================================\n"); static const struct { int d_line; const char d_value [21]; } DATA[] = { // LINE DATA { L_, "1",}, { L_, "12",}, { L_, "123",}, { L_, "1234",}, { L_, "12345",}, { L_, "123456",}, { L_, "1234567",}, { L_, "12345678",}, { L_, "123456789",}, { L_, "1234567890",}, { L_, "12345678901",}, { L_, "123456789012",}, { L_, "1234567890123",}, { L_, "12345678901234",}, { L_, "123456789012345",}, { L_, "1234567890123456",}, { L_, "12345678901234567",}, { L_, "123456789012345678",}, { L_, "1234567890123456789",}, { L_, "12345678901234567890",}, }; const int NUM_DATA = sizeof DATA / sizeof *DATA; if (verbose) printf("Hash a number of values with" " 'bslh::DefaultHashAlgorithm' and" " 'bslh::SpookyHashAlgorithm' and verify that the" " outputs match. (C-1,2,3)\n"); { for (int i = 0; i != NUM_DATA; ++i) { const int LINE = DATA[i].d_line; const char *VALUE = DATA[i].d_value; if (veryVerbose) printf("Hashing: %s\n with" " 'bslh::DefaultHashAlgorithm' and" " 'bslh::SpookyHashAlgorithm'", VALUE); Obj contiguousHash; Obj dispirateHash; SpookyHashAlgorithm cannonicalHashAlgorithm; cannonicalHashAlgorithm(VALUE, strlen(VALUE)); contiguousHash(VALUE, strlen(VALUE)); for (unsigned int j = 0; j < strlen(VALUE); ++j){ if (veryVeryVerbose) printf("Hashing by char: %c\n", VALUE[j]); dispirateHash(&VALUE[j], sizeof(char)); } SpookyHashAlgorithm::result_type hash = cannonicalHashAlgorithm.computeHash(); LOOP_ASSERT(LINE, hash == contiguousHash.computeHash()); LOOP_ASSERT(LINE, hash == dispirateHash.computeHash()); } } if (verbose) printf("Call 'operator()' with null pointers. (C-4)\n"); { const char data[5] = {'a', 'b', 'c', 'd', 'e'}; bsls::AssertFailureHandlerGuard g(bsls::AssertTest::failTestDriver); ASSERT_FAIL(Obj()( 0, 5)); ASSERT_PASS(Obj()(data, 5)); } } break; case 2: { // -------------------------------------------------------------------- // TESTING CREATORS // Ensure that the implicit destructor and the explicit default // constructor are publicly callable. // // Concerns: //: 1 Objects can be created using the parameterized constructor. //: //: 2 Objects can be destroyed. // // Plan: //: 1 Create a default constructed 'DefaultHashAlgorithm' and allow it //: to leave scope to be destroyed. (C-1,2) // // Testing: // DefaultHashAlgorithm(); // ~DefaultHashAlgorithm(); // -------------------------------------------------------------------- if (verbose) printf("\nTESTING CREATORS" "\n================\n"); if (verbose) printf("Create a default constructed" " 'DefaultHashAlgorithm' and allow it to leave" " scope to be destroyed. (C-1,2)\n"); { Obj alg1; } } break; case 1: { // -------------------------------------------------------------------- // BREATHING TEST // This case exercises (but does not fully test) basic functionality. // // Concerns: //: 1 The class is sufficiently functional to enable comprehensive //: testing in subsequent test cases. // // Plan: //: 1 Create an instance of 'bsl::DefaultHashAlgorithm'. (C-1) //: //: 2 Verify different hashes are produced for different c-strings. //: (C-1) //: //: 3 Verify the same hashes are produced for the same c-strings. (C-1) //: //: 4 Verify different hashes are produced for different 'int's. (C-1) //: //: 5 Verify the same hashes are produced for the same 'int's. (C-1) // // Testing: // BREATHING TEST // -------------------------------------------------------------------- if (verbose) printf("\nBREATHING TEST" "\n==============\n"); if (verbose) printf("Instantiate 'bsl::DefaultHashAlgorithm'\n"); { Obj hashAlg; } if (verbose) printf("Verify different hashes are produced for" " different c-strings.\n"); { Obj hashAlg1; Obj hashAlg2; const char * str1 = "Hello World"; const char * str2 = "Goodbye World"; hashAlg1(str1, strlen(str1)); hashAlg2(str2, strlen(str2)); ASSERT(hashAlg1.computeHash() != hashAlg2.computeHash()); } if (verbose) printf("Verify the same hashes are produced for the same" " c-strings.\n"); { Obj hashAlg1; Obj hashAlg2; const char * str1 = "Hello World"; const char * str2 = "Hello World"; hashAlg1(str1, strlen(str1)); hashAlg2(str2, strlen(str2)); ASSERT(hashAlg1.computeHash() == hashAlg2.computeHash()); } if (verbose) printf("Verify different hashes are produced for" " different 'int's.\n"); { Obj hashAlg1; Obj hashAlg2; int int1 = 123456; int int2 = 654321; hashAlg1(&int1, sizeof(int)); hashAlg2(&int2, sizeof(int)); ASSERT(hashAlg1.computeHash() != hashAlg2.computeHash()); } if (verbose) printf("Verify the same hashes are produced for the same" " 'int's.\n"); { Obj hashAlg1; Obj hashAlg2; int int1 = 123456; int int2 = 123456; hashAlg1(&int1, sizeof(int)); hashAlg2(&int2, sizeof(int)); ASSERT(hashAlg1.computeHash() == hashAlg2.computeHash()); } } break; default: { fprintf(stderr, "WARNING: CASE `%d' NOT FOUND.\n", test); testStatus = -1; } } if (testStatus > 0) { fprintf(stderr, "Error, non-zero test status = %d.\n", testStatus); } return testStatus; }