/*
- * Copyright 2013 Facebook, Inc.
+ * Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#error "This should only be included by AtomicHashArray.h"
#endif
-#include "folly/Bits.h"
-#include "folly/detail/AtomicHashUtils.h"
+#include <folly/Bits.h>
+#include <folly/detail/AtomicHashUtils.h>
namespace folly {
// AtomicHashArray private constructor --
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
AtomicHashArray(size_t capacity, KeyT emptyKey, KeyT lockedKey,
KeyT erasedKey, double maxLoadFactor, size_t cacheSize)
: capacity_(capacity), maxEntries_(size_t(maxLoadFactor * capacity_ + 0.5)),
* of key and returns true, or if key does not exist returns false and
* ret.index is set to capacity_.
*/
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-typename AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::SimpleRetT
-AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+typename AtomicHashArray<KeyT, ValueT,
+ HashFcn, EqualFcn, Allocator>::SimpleRetT
+AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
findInternal(const KeyT key_in) {
DCHECK_NE(key_in, kEmptyKey_);
DCHECK_NE(key_in, kLockedKey_);
* this will be the previously inserted value, and if the map is full it is
* default.
*/
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
template <class T>
-typename AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::SimpleRetT
-AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+typename AtomicHashArray<KeyT, ValueT,
+ HashFcn, EqualFcn, Allocator>::SimpleRetT
+AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
insertInternal(KeyT key_in, T&& value) {
const short NO_NEW_INSERTS = 1;
const short NO_PENDING_INSERTS = 2;
* erased key will never be reused. If there's an associated value, we won't
* touch it either.
*/
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-size_t AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+size_t AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
erase(KeyT key_in) {
CHECK_NE(key_in, kEmptyKey_);
CHECK_NE(key_in, kLockedKey_);
}
}
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-const typename AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::Config
-AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::defaultConfig;
-
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-typename AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::SmartPtr
-AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+const typename AtomicHashArray<KeyT, ValueT,
+ HashFcn, EqualFcn, Allocator>::Config
+AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::defaultConfig;
+
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+typename AtomicHashArray<KeyT, ValueT,
+ HashFcn, EqualFcn, Allocator>::SmartPtr
+AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
create(size_t maxSize, const Config& c) {
CHECK_LE(c.maxLoadFactor, 1.0);
CHECK_GT(c.maxLoadFactor, 0.0);
size_t capacity = size_t(maxSize / c.maxLoadFactor);
size_t sz = sizeof(AtomicHashArray) + sizeof(value_type) * capacity;
- std::unique_ptr<void, void(*)(void*)> mem(malloc(sz), free);
- new(mem.get()) AtomicHashArray(capacity, c.emptyKey, c.lockedKey, c.erasedKey,
- c.maxLoadFactor, c.entryCountThreadCacheSize);
- SmartPtr map(static_cast<AtomicHashArray*>(mem.release()));
+ auto const mem = Allocator().allocate(sz);
+ try {
+ new (mem) AtomicHashArray(capacity, c.emptyKey, c.lockedKey, c.erasedKey,
+ c.maxLoadFactor, c.entryCountThreadCacheSize);
+ } catch (...) {
+ Allocator().deallocate(mem, sz);
+ throw;
+ }
+
+ SmartPtr map(static_cast<AtomicHashArray*>((void *)mem));
/*
* Mark all cells as empty.
return map;
}
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-void AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+void AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
destroy(AtomicHashArray* p) {
assert(p);
+
+ size_t sz = sizeof(AtomicHashArray) + sizeof(value_type) * p->capacity_;
+
FOR_EACH_RANGE(i, 0, p->capacity_) {
if (p->cells_[i].first != p->kEmptyKey_) {
p->cells_[i].~value_type();
}
}
p->~AtomicHashArray();
- free(p);
+
+ Allocator().deallocate((char *)p, sz);
}
// clear -- clears all keys and values in the map and resets all counters
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
-void AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
+void AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::
clear() {
FOR_EACH_RANGE(i, 0, capacity_) {
if (cells_[i].first != kEmptyKey_) {
// Iterator implementation
-template <class KeyT, class ValueT, class HashFcn, class EqualFcn>
+template <class KeyT, class ValueT,
+ class HashFcn, class EqualFcn, class Allocator>
template <class ContT, class IterVal>
-struct AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn>::aha_iterator
+struct AtomicHashArray<KeyT, ValueT, HashFcn, EqualFcn, Allocator>::aha_iterator
: boost::iterator_facade<aha_iterator<ContT,IterVal>,
IterVal,
boost::forward_traversal_tag>