File: //usr/include/hphp/util/atomic-vector.h
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_ATOMIC_VECTOR_H
#define incl_HPHP_ATOMIC_VECTOR_H
#include <algorithm>
#include <atomic>
#include <functional>
#include <folly/String.h>
#include "hphp/util/trace.h"
namespace HPHP {
/*
* AtomicVector is a simple vector intended for use by many concurrent readers
* and writers. The size given to the constructor determines how many elements
* the AtomicVector will initially hold, and each one will be initialized to
* the given default value. Elements may be retrieved and exchanged with any
* valid index by many readers and writers concurrently, though the operations
* may be very slow if std::atomic<Value>::is_lock_free() == false.
*
* The only way to increase the size of an AtomicVector is with the ensureSize
* method. It does not reallocate the internal storage to grow; it allocates a
* new AtomicVector and chains to that for increased capacity. This means that
* if the initial size is too low, reading and modifying elements at high
* indexes will be increasingly slower as the chain of AtomicVectors is walked
* to find the right element.
*
* An AtomicVector cannot shrink, and will only reclaim memory when destructed.
*/
template<typename Value>
struct AtomicVector {
AtomicVector(size_t size, const Value& def);
~AtomicVector();
void ensureSize(size_t size);
Value exchange(size_t i, const Value& val);
std::atomic<Value>& operator[](size_t i);
const std::atomic<Value>& operator[](size_t i) const;
size_t size() const;
Value get(size_t i) const;
template <typename F> void foreach(F fun) const;
Value defaultValue() const;
/*
* Reconstruct a currently empty vector with new initial size. Thread-unsafe.
*
* A number of AtomicVectors have sizes that we'd like to control with runtime
* options, but these options are parsed after the relevant AtomicVectors are
* constructed. This method allows us to reconstruct them once the options
* have been parsed.
*/
template<typename V>
friend void UnsafeReinitEmptyAtomicVector(AtomicVector<V>& vec, size_t size);
private:
static std::string typeName();
const size_t m_size;
std::atomic<AtomicVector*> m_next;
const Value m_default;
std::unique_ptr<std::atomic<Value>[]> m_vals;
TRACE_SET_MOD(atomicvector);
};
}
#include "hphp/util/atomic-vector-inl.h"
#endif