Arquivos
hhvm/hphp/runtime/vm/indexed_string_map.h
T
Jordan Delong 363d1bb20f Code move src/ -> hphp/
This change is mostly for FB internal organizational reasons.
Building is not effected beyond the fact that the target now
lands in hphp/hhvm/hhvm rather than src/hhvm/hhvm.
2013-02-11 02:10:41 -08:00

231 linhas
6.6 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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_VM_INDEXED_STRING_MAP_H_
#define incl_VM_INDEXED_STRING_MAP_H_
#include <boost/mpl/if.hpp>
#include <boost/utility/enable_if.hpp>
#include "runtime/base/string_data.h"
#include "runtime/vm/fixed_string_map.h"
namespace HPHP { namespace VM {
//////////////////////////////////////////////////////////////////////
/*
* Several VM data structures can be accessed with both a string-based
* lookup and by an index. This map supports both types of lookup.
* (The index type is a template parameter in order to allow different
* uses of this map to have different sized indexes).
*
* The number of elements must be fixed after initialization time
* (since we use a FixedStringMap internally).
*/
template<class T,
bool CaseSensitive,
class Index,
Index InvalidIndex = Index(-1)>
struct IndexedStringMap {
struct Builder;
explicit IndexedStringMap() : m_vec(0), m_size(0) {}
~IndexedStringMap() {
delete [] m_vec;
}
/*
* Create an IndexedStringMap from the supplied builder. See
* builder below.
*/
void create(const Builder& b) {
assert(!m_size && "IndexedStringMap::create called more than once");
m_map.init(b.size());
m_vec = new T[b.size()];
m_size = b.size();
std::copy(b.m_list.begin(), b.m_list.end(), m_vec);
for (typename Builder::const_iterator it = b.begin();
it != b.end();
++it) {
m_map.add(it->first, it->second);
}
}
bool contains(const StringData* k) const { return m_map.find(k); }
Index size() const { return m_size; }
const T* accessList() const { return m_vec; }
T* mutableAccessList() { return m_vec; }
// Find the index for an entry by name. Returns InvalidIndex if
// there is no entry with this name.
Index findIndex(const StringData* k) const {
Index* i = m_map.find(k);
if (!i) return InvalidIndex;
return *i;
}
// Lookup entries in the map by string. Returns the entry or the
// supplied default value if it doesn't exist.
T lookupDefault(const StringData* k, T def) const {
Index* i = m_map.find(k);
if (!i) return def;
return m_vec[*i];
}
// Lookup entries by index. Index must be in range or you get
// undefined behavior.
T& operator[](Index index) {
assert(index < size());
return m_vec[index];
}
const T& operator[](Index index) const {
return (*const_cast<IndexedStringMap*>(this))[index];
}
public:
static size_t vecOff() { return offsetof(IndexedStringMap, m_vec); }
static size_t sizeOff() { return offsetof(IndexedStringMap, m_size); }
private:
typedef FixedStringMap<Index,CaseSensitive> Map;
IndexedStringMap(const IndexedStringMap&);
IndexedStringMap& operator=(const IndexedStringMap&);
T* m_vec;
Index m_size;
Map m_map;
};
//////////////////////////////////////////////////////////////////////
/*
* Builder object for creating IndexedStringMaps. Fill one of these
* up, and then pass it to IndexedStringMap::create.
*/
template<class T, bool CaseSensitive, class Index, Index InvalidIndex>
class IndexedStringMap<T,CaseSensitive,Index,InvalidIndex>::Builder {
typedef typename boost::mpl::if_c<
CaseSensitive,
string_data_same,
string_data_isame
>::type EqObject;
typedef hphp_hash_map<const StringData*,Index,
string_data_hash,EqObject> Map;
public:
typedef typename Map::const_iterator const_iterator;
typedef typename Map::iterator iterator;
iterator find(const StringData* key) { return m_map.find(key); }
iterator begin() { return m_map.begin(); }
iterator end() { return m_map.end(); }
Index size() const { return m_list.size(); }
const_iterator find(const StringData* key) const {
return m_map.find(key);
}
const_iterator begin() const { return m_map.begin(); }
const_iterator end() const { return m_map.end(); }
T& operator[](Index idx) {
assert(idx >= 0);
assert(size_t(idx) < m_list.size());
return m_list[idx];
}
const T& operator[](Index idx) const {
return (*const_cast<Builder*>(this))[idx];
}
/*
* Add an object to the position on the end, and allow lookup by
* `name'.
*/
void add(const StringData* name, const T& t) {
if (m_list.size() >= size_t(std::numeric_limits<Index>::max())) {
assert(false && "IndexedStringMap::Builder overflowed");
abort();
}
m_map[name] = m_list.size();
m_list.push_back(t);
}
/*
* Adds objects that occupy indexes but can't be located by name.
*/
void addUnnamed(const T& t) {
m_list.push_back(t);
}
/*
* Implement custom separate versions of (de)serialization code to
* be more compact about what we put on disk. (Instead of just
* pumping through our m_list and m_map.)
*/
// Deserialization version.
template<class SerDe>
typename boost::enable_if_c<SerDe::deserializing>::type
serde(SerDe& sd) {
uint32_t size;
sd(size);
for (uint32_t i = 0; i < size; ++i) {
const StringData* name;
T t;
sd(name)(t);
if (name) {
add(name, t);
} else {
addUnnamed(t);
}
}
}
// Serialization version.
template<class SerDe>
typename boost::disable_if_c<SerDe::deserializing>::type
serde(SerDe& sd) {
std::vector<const StringData*> names(m_list.size());
for (typename Map::const_iterator it = m_map.begin();
it != m_map.end();
++it) {
names[it->second] = it->first;
}
sd(uint32_t(m_list.size()));
for (uint32_t i = 0; i < m_list.size(); ++i) {
sd(names[i])(m_list[i]);
}
}
private:
friend class IndexedStringMap;
std::vector<T> m_list;
Map m_map;
};
//////////////////////////////////////////////////////////////////////
}}
#endif