Arquivos
hhvm/hphp/runtime/base/array/zend_array.h
T
2013-02-19 06:57:54 -08:00

309 linhas
10 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 __HPHP_ZEND_ARRAY_H__
#define __HPHP_ZEND_ARRAY_H__
#include <runtime/base/types.h>
#include <runtime/base/array/array_data.h>
#include <runtime/base/memory/smart_allocator.h>
#include <runtime/base/complex_types.h>
#include <runtime/base/comparisons.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class ArrayInit;
class ZendArray : public ArrayData {
static const uint LgMinSize = 3;
static const uint MinSize = 1 << LgMinSize;
enum Flag { StrongIteratorPastEnd = 1 };
enum SortFlavor { IntegerSort, StringSort, GenericSort };
public:
friend class ArrayInit;
friend class VectorArray;
ZendArray() : m_nTableMask(MinSize - 1), m_arBuckets(m_inlineBuckets),
m_pListHead(0), m_pListTail(0), m_nNextFreeElement(0) {
m_allocMode = kInline;
m_size = 0;
memset(m_inlineBuckets, 0, MinSize * sizeof(Bucket*));
}
ZendArray(uint nSize, bool nonsmart = false);
virtual ~ZendArray();
// these using directives ensure the full set of overloaded functions
// are visible in this class, to avoid triggering implicit conversions
// from a CVarRef key to int64.
using ArrayData::exists;
using ArrayData::get;
using ArrayData::getIndex;
using ArrayData::lval;
using ArrayData::lvalNew;
using ArrayData::lvalPtr;
using ArrayData::set;
using ArrayData::setRef;
using ArrayData::add;
using ArrayData::addLval;
using ArrayData::remove;
virtual ssize_t vsize() const ATTRIBUTE_COLD;
virtual Variant getKey(ssize_t pos) const;
virtual Variant getValue(ssize_t pos) const;
virtual CVarRef getValueRef(ssize_t pos) const;
virtual bool isVectorData() const;
virtual ssize_t iter_begin() const;
virtual ssize_t iter_end() const;
virtual ssize_t iter_advance(ssize_t prev) const;
virtual ssize_t iter_rewind(ssize_t prev) const;
virtual Variant reset();
virtual Variant prev();
virtual Variant current() const;
virtual Variant next();
virtual Variant end();
virtual Variant key() const;
virtual Variant value(ssize_t &pos) const;
virtual Variant each();
virtual bool isInvalid() const { return !m_pos; }
virtual bool exists(int64 k) const;
virtual bool exists(const StringData* k) const;
virtual CVarRef get(int64 k, bool error = false) const;
virtual CVarRef get(const StringData* k, bool error = false) const;
virtual ssize_t getIndex(int64 k) const;
virtual ssize_t getIndex(const StringData* k) const;
virtual ArrayData *lval(int64 k, Variant *&ret, bool copy,
bool checkExist = false);
virtual ArrayData *lval(StringData* k, Variant *&ret, bool copy,
bool checkExist = false);
virtual ArrayData *lvalPtr(int64 k, Variant *&ret, bool copy,
bool create);
virtual ArrayData *lvalPtr(StringData* k, Variant *&ret, bool copy,
bool create);
virtual ArrayData *lvalNew(Variant *&ret, bool copy);
virtual ArrayData *set(int64 k, CVarRef v, bool copy);
virtual ArrayData *set(StringData* k, CVarRef v, bool copy);
virtual ArrayData *setRef(int64 k, CVarRef v, bool copy);
virtual ArrayData *setRef(StringData* k, CVarRef v, bool copy);
virtual ArrayData *add(int64 k, CVarRef v, bool copy);
virtual ArrayData *add(StringData* k, CVarRef v, bool copy);
virtual ArrayData *addLval(int64 k, Variant *&ret, bool copy);
virtual ArrayData *addLval(StringData* k, Variant *&ret, bool copy);
virtual ArrayData *remove(int64 k, bool copy);
virtual ArrayData *remove(const StringData* k, bool copy);
virtual ArrayData *copy() const;
virtual ArrayData *copyWithStrongIterators() const;
virtual ArrayData *nonSmartCopy() const;
virtual ArrayData *append(CVarRef v, bool copy);
virtual ArrayData *appendRef(CVarRef v, bool copy);
virtual ArrayData *appendWithRef(CVarRef v, bool copy);
virtual ArrayData *append(const ArrayData *elems, ArrayOp op, bool copy);
virtual ArrayData *pop(Variant &value);
virtual ArrayData *dequeue(Variant &value);
virtual ArrayData *prepend(CVarRef v, bool copy);
virtual void renumber();
virtual void onSetEvalScalar();
virtual bool validFullPos(const FullPos &fp) const;
virtual void getFullPos(FullPos &fp);
virtual bool setFullPos(const FullPos &fp);
virtual CVarRef currentRef();
virtual CVarRef endRef();
class Bucket {
public:
Bucket() :
ikey(0), pListNext(nullptr), pListLast(nullptr), pNext(nullptr) {
data._count = 0;
}
Bucket(Variant::NoInit d) :
ikey(0), data(d), pListNext(nullptr), pListLast(nullptr), pNext(nullptr) {
data._count = 0;
}
Bucket(CVarRef d) :
ikey(0), data(d), pListNext(nullptr), pListLast(nullptr), pNext(nullptr) {
data._count = 0;
}
Bucket(CVarStrongBind d) :
ikey(0), data(d), pListNext(nullptr), pListLast(nullptr), pNext(nullptr) {
data._count = 0;
}
Bucket(CVarWithRefBind d) :
ikey(0), data(d), pListNext(nullptr), pListLast(nullptr), pNext(nullptr) {
data._count = 0;
}
// set the top bit for string hashes to make sure the hash
// value is never zero. hash value 0 corresponds to integer key.
static inline int32_t encodeHash(strhash_t h) {
return int32_t(h) | 0x80000000;
}
// These special constructors do not setup all the member fields.
// They cannot be used along but must be with the following special
// ZendArray constructor
Bucket(StringData *k, CVarRef d) :
skey(k), data(d) {
assert(k->isStatic());
data._count = encodeHash(k->getPrecomputedHash());
}
Bucket(int64 k, CVarRef d) : ikey(k), data(d) {
data._count = 0;
}
Bucket(int64 k, CVarWithRefBind d) : ikey(k), data(d) {
data._count = 0;
}
~Bucket();
/* The key is either a string pointer or an int value, and the _count
* field in data is used to discriminate the key type. _count = 0 means
* int, nonzero values contain 31 bits of a string's hashcode.
* It is critical that when we return &data to clients, that they not
* read or write the _count field! */
union {
int64 ikey;
StringData *skey;
};
Variant data;
inline bool hasStrKey() const { return data._count != 0; }
inline bool hasIntKey() const { return data._count == 0; }
inline void setStrKey(StringData* k, strhash_t h) {
skey = k;
skey->incRefCount();
data._count = encodeHash(h);
}
inline void setIntKey(int64 k) {
ikey = k;
data._count = 0;
}
inline int64 hashKey() const {
return data._count == 0 ? ikey : data._count;
}
inline int32_t hash() const {
return data._count;
}
Bucket *pListNext;
Bucket *pListLast;
Bucket *pNext;
/**
* Memory allocator methods.
*/
DECLARE_SMART_ALLOCATION(Bucket);
void dump();
};
// This constructor should never be called directly, it is only called
// from generated code.
ZendArray(uint nSize, int64 n, Bucket *bkts[]);
private:
uint m_nTableMask;
Bucket **m_arBuckets;
Bucket * m_pListHead;
Bucket *m_inlineBuckets[MinSize];
Bucket * m_pListTail;
int64 m_nNextFreeElement;
uint tableSize() const { return m_nTableMask + 1; }
Bucket *find(int64 h) const;
Bucket *find(const char *k, int len, strhash_t prehash) const;
Bucket *findForInsert(int64 h) const;
Bucket *findForInsert(const char *k, int len, strhash_t prehash) const;
Bucket ** findForErase(int64 h) const;
Bucket ** findForErase(const char *k, int len, strhash_t prehash) const;
Bucket ** findForErase(Bucket * bucketPtr) const;
bool nextInsert(CVarRef data);
bool nextInsertWithRef(CVarRef data);
bool nextInsertRef(CVarRef data);
bool addLvalImpl(int64 h, Variant **pDest, bool doFind = true);
bool addLvalImpl(StringData *key, strhash_t h, Variant **pDest,
bool doFind = true);
bool addValWithRef(int64 h, CVarRef data);
bool addValWithRef(StringData *key, CVarRef data);
bool update(int64 h, CVarRef data);
bool update(StringData *key, CVarRef data);
bool updateRef(int64 h, CVarRef data);
bool updateRef(StringData *key, CVarRef data);
void erase(Bucket ** prev, bool updateNext = false);
ZendArray *copyImpl() const;
ZendArray *copyImplHelper(bool sma) const;
void init(uint nSize);
void resize();
void rehash();
template <typename AccessorT>
SortFlavor preSort(Bucket** buffer, const AccessorT& acc, bool checkTypes);
void postSort(Bucket** buffer, bool resetKeys);
public:
ArrayData* escalateForSort();
void ksort(int sort_flags, bool ascending);
void sort(int sort_flags, bool ascending);
void asort(int sort_flags, bool ascending);
void uksort(CVarRef cmp_function);
void usort(CVarRef cmp_function);
void uasort(CVarRef cmp_function);
private:
/**
* Memory allocator methods.
*/
DECLARE_SMART_ALLOCATION(ZendArray);
};
class StaticEmptyZendArray : public ZendArray {
public:
StaticEmptyZendArray() { setStatic();}
static ZendArray *Get() { return &s_theEmptyArray; }
private:
static StaticEmptyZendArray s_theEmptyArray;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __HPHP_ZEND_ARRAY_H__