Files
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

242 lines
7.7 KiB
C++

/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __avmplus_BitSet__
#define __avmplus_BitSet__
namespace avmplus
{
/**
* Bit vectors are an efficent method of keeping True/False information
* on a set of items or conditions. Class BitSet provides functions
* to manipulate individual bits in the vector.
*
* Since most vectors are rather small an array of machine words is used by
* default to house the value of the bits. If more bits are needed
* then an array is allocated dynamically outside of this object.
*
* This object is not optimized for a fixed sized bit vector
* it instead allows for dynamically growing the bit vector.
*/
class BitSet
{
private:
uintptr_t *getbits() {
return capacity > kDefaultCapacity ? bits.ptr : bits.ar;
}
const uintptr_t *getbits() const {
return capacity > kDefaultCapacity ? bits.ptr : bits.ar;
}
static const uintptr_t kOne = 1;
public:
enum { kUnit = 8*sizeof(uintptr_t),
kDefaultCapacity = 4 };
BitSet(): capacity(kDefaultCapacity) {
reset();
}
BitSet(int bitcap) : capacity(kDefaultCapacity) {
reset();
int cap = ((bitcap+kUnit-1)/kUnit);
if (cap > kDefaultCapacity)
grow(cap);
}
virtual ~BitSet() {
if (capacity > kDefaultCapacity) {
mmfx_delete_array(bits.ptr);
bits.ptr = 0;
capacity = kDefaultCapacity;
}
}
void reset()
{
uintptr_t *bits = getbits();
for (int i=0, n = capacity; i < n; i++)
bits[i] = 0;
}
void set(int bitNbr)
{
int index = bitNbr / kUnit;
int bit = bitNbr % kUnit;
int cap = this->capacity;
if (index >= cap) {
cap *= 2;
while (index >= cap) {
cap *= 2;
}
grow(cap);
}
getbits()[index] |= kOne << bit;
}
void clear(int bitNbr)
{
int index = bitNbr / kUnit;
int bit = bitNbr % kUnit;
if (index < capacity)
getbits()[index] &= ~(kOne << bit);
}
bool get(int bitNbr) const
{
int index = bitNbr / kUnit;
int bit = bitNbr % kUnit;
return index < capacity && (getbits()[index] & kOne<<bit) != 0;
}
uintptr_t setFrom(BitSet &other) {
int c = other.capacity;
if (c > capacity)
grow(c);
uintptr_t *bits = getbits();
uintptr_t *otherbits = other.getbits();
uintptr_t newbits = 0;
for (int i=0; i < c; i++) {
uintptr_t b = bits[i];
uintptr_t b2 = otherbits[i];
newbits |= b2 & ~b; // bits in b2 that are not in b
bits[i] = b|b2;
}
return newbits;
}
private:
// Grow the array until at least newCapacity big
void grow(int newCapacity)
{
uintptr_t* newBits = mmfx_new_array( uintptr_t, newCapacity);
// copy the old one
uintptr_t *bits = getbits();
for (int i=0, n=capacity; i < n; i++)
newBits[i] = bits[i];
for (int i=capacity; i < newCapacity; i++)
newBits[i] = 0;
// in with the new out with the old
if (capacity > kDefaultCapacity)
mmfx_delete_array( bits );
this->bits.ptr = newBits;
capacity = newCapacity;
}
// by default we use the array, but if the vector
// size grows beyond kDefaultCapacity we allocate
// space dynamically.
int capacity;
union
{
uintptr_t ar[kDefaultCapacity];
uintptr_t* ptr;
}
bits;
};
// a simpler version of BitSet that doesn't dynamically grow,
// and doesn't require allocation for <=31 (or 63) size. This expects
// to be embedded as a member variable in a GCObject and will
// use WB if allocation is necessary.
class FixedBitSet : public MMgc::GCInlineObject
{
public:
inline explicit FixedBitSet() : m_bits(0)
#ifdef _DEBUG
, m_cap(0)
#endif
{
}
inline void gcTrace(MMgc::GC* gc)
{
if (!(m_bits & 1))
gc->TraceLocation(&m_bits);
}
// blows away existing content, sets all bits to 0
inline void resize(MMgc::GC* gc, uint32_t cap)
{
const uint32_t MAX_INLINE_BITS = BITS_PER_UINTPTR - 1;
if (cap > MAX_INLINE_BITS)
{
// always allocate one more bit than we need to simplify the logic elsewhere (bit 0 goes unused)
const uint32_t count = (cap + (BITS_PER_UINTPTR - 1) + 1) / BITS_PER_UINTPTR;
const uint32_t sz = count * sizeof(uintptr_t);
uintptr_t* v = (uintptr_t*)gc->Alloc(sz, MMgc::GC::kZero);
void* beginning = gc->FindBeginningFast(this);
if (beginning)
{
WB(gc, beginning, &m_bits, v);
}
else
{
m_bits = uintptr_t(v);
}
}
else
{
m_bits = 0x1;
}
#ifdef _DEBUG
m_cap = cap;
#endif
}
inline void set(uint32_t bit)
{
AvmAssert(bit < m_cap);
uintptr_t* v = (m_bits & 1) ? &m_bits : (uintptr_t*)m_bits;
const uint32_t nbit = bit + 1;
v[nbit / BITS_PER_UINTPTR] |= (uintptr_t(1) << (nbit & (BITS_PER_UINTPTR-1)));
}
inline void clr(uint32_t bit)
{
AvmAssert(bit < m_cap);
uintptr_t* v = (m_bits & 1) ? &m_bits : (uintptr_t*)m_bits;
const uint32_t nbit = bit + 1;
v[nbit / BITS_PER_UINTPTR] &= ~(uintptr_t(1) << (nbit & (BITS_PER_UINTPTR-1)));
}
inline bool test(uint32_t bit) const
{
AvmAssert(bit < m_cap);
const uint32_t nbit = bit + 1;
uintptr_t w = m_bits;
if (!(w & 1))
w = ((const uintptr_t*)m_bits)[nbit / BITS_PER_UINTPTR];
return (w & (uintptr_t(1) << (nbit & (BITS_PER_UINTPTR-1)))) != 0;
}
inline size_t allocatedSize()
{
return ((m_bits & 1) || (m_bits == 0)) ? 0 : MMgc::GC::Size((void*)m_bits);
}
#ifdef _DEBUG
inline uint32_t cap() const { return uint32_t(m_cap); }
#endif
private:
enum { BITS_PER_UINTPTR = sizeof(uintptr_t)*8 };
private:
uintptr_t m_bits; // low bit 1 == inline, low bit 0 == dynamic alloc
#ifdef _DEBUG
uintptr_t m_cap;
#endif
};
}
#endif /* __avmplus_BitSet__ */