Permalink
Browse files

fixed isPrime, improved tests, other minor changes

  • Loading branch information...
giacomodrago committed May 11, 2014
1 parent 51935ac commit 5677a025fb454572ebf1adcf49c3db6128dcd8b8
Showing with 207 additions and 195 deletions.
  1. +1 −1 LICENSE
  2. +37 −36 fcmm.hpp
  3. +2 −2 test/benchmark_tbb.cpp
  4. +38 −20 test/common.hpp
  5. +104 −121 test/correctness_test.cpp
  6. +25 −15 test/move_semantics.cpp
@@ -1,4 +1,4 @@
Copyright (c) 2013, Giacomo Drago <giacomo@giacomodrago.com>
Copyright (c) 2014, Giacomo Drago <giacomo@giacomodrago.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
@@ -6,7 +6,7 @@
*
* @section LICENSE
*
* Copyright (c) 2013, Giacomo Drago <giacomo@giacomodrago.com>
* Copyright (c) 2014, Giacomo Drago <giacomo@giacomodrago.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -67,62 +67,65 @@

namespace fcmm {

namespace {

/**
* @brief Default maximum load factor
*/
static const float DEFAULT_MAX_LOAD_FACTOR = 0.75f;
const float DEFAULT_MAX_LOAD_FACTOR = 0.75f;

/**
* @brief Default maximum number of submaps
*/
static const std::size_t DEFAULT_MAX_NUM_SUBMAPS = 128;
const std::size_t DEFAULT_MAX_NUM_SUBMAPS = 128;

/**
* @brief The capacity of a new submap is calculated as the first prime number following the capacity of the
* last submap multiplied by this constant
*/
static const std::size_t NEW_SUBMAPS_CAPACITY_MULTIPLIER = 8;
const std::size_t NEW_SUBMAPS_CAPACITY_MULTIPLIER = 8;

/**
* @brief Minimum capacity of the first submap
* @brief Minimum capacity of the first submap (it has to be a prime number greater than 2)
*/
static const std::size_t FIRST_SUBMAP_MIN_CAPACITY = 65537;
const std::size_t FIRST_SUBMAP_MIN_CAPACITY = 65537;

/**
* @brief The capacity of the first submap is calculated as:
* <code>max(FIRST_SUBMAP_MIN_CAPACITY, nextPrime(<b>FIRST_SUBMAP_CAPACITY_MULTIPLIER</b> * estimatedNumEntries / maxLoadFactor))</code>
*/
static const float FIRST_SUBMAP_CAPACITY_MULTIPLIER = 1.03f;
const float FIRST_SUBMAP_CAPACITY_MULTIPLIER = 1.03f;

/**
* @brief Auxiliary function for nextPrime(). Returns `true` if `n` is prime, `false` otherwise.
*
* Adapted from http://stackoverflow.com/a/5694432/671092
* @brief Returns `true` if `n` is prime, `false` otherwise.
*/
template<typename T>
static bool isPrime(const T& n, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) {

std::size_t divisor = 3;
while (1) {
const std::size_t quotient = n / divisor;
if (quotient < divisor)
return true;
if (n == quotient * divisor)
bool isPrime(const T& n, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) {

if (n < 2)
return false;
if (n == 2)
return true;
if (n % 2 == 0)
return false;

T div = 3;

while (div * div <= n) {
if (n % div == 0)
return false;
divisor += 2;
div += 2;
}

return true;

}

/**
* @brief Returns the smallest prime number greater than `n`
*
* Adapted from http://stackoverflow.com/a/5694432/671092
* @brief Returns the smallest prime number greater than or equal to `n`
*/
template<typename T>
static T nextPrime(T n, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) {
T nextPrime(T n, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) {

if (n <= 2)
return 2;
@@ -138,6 +141,8 @@ static T nextPrime(T n, typename std::enable_if<std::is_integral<T>::value>::typ

}

} // unnamed namespace

/**
* @brief This struct holds the statistics about a single submap of a @link Fcmm @endlink instance
*
@@ -494,7 +499,7 @@ class Fcmm {
template<typename KeyType, typename ComputeValueFunction>
std::pair<std::size_t, bool> insert(KeyType&& key, std::size_t hash1, std::size_t hash2, ComputeValueFunction computeValue) {

Value value = Value(); // to avoid "maybe-uninitialized" warnings
Value value = Value();
bool valueComputed = false;

const std::size_t startIndex = hash1 % getCapacity(); // initial position for probing
@@ -891,7 +896,7 @@ class Fcmm {
*/
template<typename ComputeValueFunction>
std::pair<const_iterator, bool> insert(Key&& key, ComputeValueFunction computeValue) {
return insertHelper(key, keyHash1(key), keyHash2(key), computeValue);
return insertHelper(std::move(key), keyHash1(key), keyHash2(key), computeValue);
}

/**
@@ -923,7 +928,7 @@ class Fcmm {
}

/**
* @brief Inserts a new entry in the map. The new entry is constructed in place using `args` as the arguments
* @brief Inserts a new entry into the map. The new entry is constructed using `args` as the arguments
* for the entry's constructor.
*
* @param args arguments used to construct a new entry (key, value)
@@ -1163,6 +1168,12 @@ class Fcmm {

public:

/**
* @brief Default constructor. The resulting iterator is invalid and should not be used.
*/
const_iterator() : map(NULL), submapIndex(0), bucketIndex(0), end(true) {
}

/**
* @brief Equality operator
*/
@@ -1209,16 +1220,6 @@ class Fcmm {
return &getEntry();
}

/**
* @brief Swap function
*/
friend void swap(const_iterator& it1, const_iterator& it2) {
std::swap(it1.map, it2.map);
std::swap(it1.submapIndex, it2.submapIndex);
std::swap(it1.bucketIndex, it2.bucketIndex);
std::swap(it1.end, it2.end);
}

};

/**
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2013, Giacomo Drago <giacomo@giacomodrago.com>
* Copyright (c) 2014, Giacomo Drago <giacomo@giacomodrago.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "fcmm.hpp"
#include <fcmm.hpp>

#include "common.hpp"

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2013, Giacomo Drago <giacomo@giacomodrago.com>
* Copyright (c) 2014, Giacomo Drago <giacomo@giacomodrago.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,24 +37,34 @@
#include <chrono>
#include <ctime>
#include <iostream>
#include <string>

static const std::string REPORT_RECIPIENT = "Giacomo Drago <giacomo@giacomodrago.com>";
static const int CALCULATE_ITERATIONS = 15;

struct Key {
std::uint16_t a;
std::uint16_t b;
std::uint16_t c;
Key() {
Key() : a(0), b(0), c(0) {
}
Key(std::uint16_t a, std::uint16_t b, std::uint16_t c) : a(a), b(b), c(c) {
}
bool operator==(const Key& other) const {
return other.a == a && other.b == b && other.c == c;
}
bool operator!=(const Key& other) const {
return !operator==(other);
}
std::string toString() const {
return "key [" + std::to_string(a) + " " + std::to_string(b) + " " + std::to_string(c) + "]";
}
};

struct KeyHash1 {
std::size_t operator()(const Key& key) const {
const std::size_t prime = 2166136261;
std::size_t hash = 2147483647;
const std::size_t prime = 16777619;
std::size_t hash = 2166136261;
hash = (hash * prime) ^ key.a;
hash = (hash * prime) ^ key.b;
hash = (hash * prime) ^ key.c;
@@ -82,10 +92,11 @@ struct Value {
bool operator!=(const Value& other) const {
return !operator==(other);
}
std::string toString() const {
return "value [" + std::to_string(u) + " " + std::to_string(v) + " " + std::to_string(w) + "]";
}
};

static const int CALCULATE_ITERATIONS = 15;

Value calculate(const Key& k) {

Value value;
@@ -106,17 +117,10 @@ Value calculate(const Key& k) {

}

bool checkEntryConsistency(const Key& key, const Value& actualValue, const Value& expectedValue) {
if (actualValue.u != expectedValue.u || actualValue.v != expectedValue.v || actualValue.w != expectedValue.w) {
return false;
}
return true;
}

template<typename FcmmType>
void printStats(const FcmmType& map) {
std::cout << "Statistics for the fcmm instance: " << std::endl;
fcmm::Stats stats = map.getStats();
const fcmm::Stats stats = map.getStats();
std::cout << "Number of entries: " << stats.numEntries << std::endl;
std::cout << "Number of submaps: " << stats.numSubmaps << std::endl;
for (std::size_t i = 0; i < stats.numSubmaps; i++) {
@@ -137,13 +141,13 @@ long long elapsedMillis(timestamp_t start, timestamp_t end) {
return std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
}

template<typename Function, typename... Arguments>
long long benchmark(Function function, Arguments... args) {
template<typename Function, typename... Args>
long long benchmark(Function function, Args&&... args) {

timestamp_t start = now();
function(args...);
timestamp_t end = now();
long long elapsedMs = elapsedMillis(start, end);
const timestamp_t start = now();
function(std::forward<Args>(args)...);
const timestamp_t end = now();
const long long elapsedMs = elapsedMillis(start, end);

return elapsedMs;

@@ -165,4 +169,18 @@ void runThreads(int numThreads, ThreadFunction threadFunction, Args&&... threadF

}

void fail(const std::string& message) {
std::cerr << std::endl << message << std::endl
<< "TEST FAILED" << std::endl
<< "Please report full test output along with your test environment" << std::endl
<< "to " << REPORT_RECIPIENT << std::endl;
exit(EXIT_FAILURE);
}

void assert(bool condition, const std::string& message) {
if (!condition) {
fail(message);
}
}

#endif // FCMM_TEST_COMMON_H_
Oops, something went wrong.

0 comments on commit 5677a02

Please sign in to comment.