kdelibs/kjs/list.cpp
Ivailo Monev 39f1e04295 generic: add back khtml and kjs with some changes
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2015-11-09 23:23:53 +02:00

320 lines
7.5 KiB
C++

/*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "list.h"
#include <config-kjs.h>
#include "internal.h"
#include <algorithm>
#define DUMP_STATISTICS 0
using std::min;
namespace KJS {
// tunable parameters
const int poolSize = 512;
enum ListImpState { unusedInPool = 0, usedInPool, usedOnHeap, immortal };
struct ListImp : ListImpBase
{
ListImpState state;
union {
int capacity; // or 0 if data is inline
ListImp *nextInFreeList;
};
LocalStorageEntry values[inlineListValuesSize];
#if DUMP_STATISTICS
int sizeHighWaterMark;
#endif
void markValues();
};
struct HeapListImp : ListImp
{
HeapListImp *nextInHeapList;
HeapListImp *prevInHeapList;
};
static ListImp pool[poolSize];
static ListImp *poolFreeList;
static HeapListImp *heapList;
static int poolUsed;
#if DUMP_STATISTICS
static int numLists;
static int numListsHighWaterMark;
static int listSizeHighWaterMark;
static int numListsDestroyed;
static int numListsBiggerThan[17];
struct ListStatisticsExitLogger { ~ListStatisticsExitLogger(); };
static ListStatisticsExitLogger logger;
ListStatisticsExitLogger::~ListStatisticsExitLogger()
{
printf("\nKJS::List statistics:\n\n");
printf("%d lists were allocated\n", numLists);
printf("%d lists was the high water mark\n", numListsHighWaterMark);
printf("largest list had %d elements\n", listSizeHighWaterMark);
if (numListsDestroyed) {
putc('\n', stdout);
for (int i = 0; i < 17; i++) {
printf("%.1f%% of the lists (%d) had more than %d element%s\n",
100.0 * numListsBiggerThan[i] / numListsDestroyed,
numListsBiggerThan[i],
i, i == 1 ? "" : "s");
}
putc('\n', stdout);
}
}
#endif
inline void ListImp::markValues()
{
for (int i = 0; i != size; ++i) {
if (!data[i].val.valueVal->marked())
data[i].val.valueVal->mark();
}
}
void List::markProtectedLists()
{
int seen = 0;
int used = poolUsed;
for (int i = 0; i < poolSize && seen < used; i++) {
if (pool[i].state == usedInPool) {
seen++;
pool[i].markValues();
}
}
for (HeapListImp *l = heapList; l; l = l->nextInHeapList) {
l->markValues();
}
}
static inline ListImp *allocateListImp()
{
// Find a free one in the pool.
if (poolUsed < poolSize) {
ListImp *imp = poolFreeList ? poolFreeList : &pool[0];
poolFreeList = imp->nextInFreeList ? imp->nextInFreeList : imp + 1;
imp->state = usedInPool;
poolUsed++;
return imp;
}
HeapListImp *imp = new HeapListImp;
imp->state = usedOnHeap;
// link into heap list
if (heapList) {
heapList->prevInHeapList = imp;
}
imp->nextInHeapList = heapList;
imp->prevInHeapList = NULL;
heapList = imp;
return imp;
}
List::List() : _impBase(allocateListImp())
{
ListImp *imp = static_cast<ListImp *>(_impBase);
imp->size = 0;
imp->refCount = 1;
imp->capacity = 0;
imp->data = imp->values;
#if DUMP_STATISTICS
if (++numLists > numListsHighWaterMark)
numListsHighWaterMark = numLists;
imp->sizeHighWaterMark = 0;
#endif
}
void List::release()
{
ListImp *imp = static_cast<ListImp *>(_impBase);
#if DUMP_STATISTICS
if (imp->size > imp->sizeHighWaterMark)
imp->sizeHighWaterMark = imp->size;
--numLists;
++numListsDestroyed;
for (int i = 0; i < 17; i++)
if (imp->sizeHighWaterMark > i)
++numListsBiggerThan[i];
#endif
if (imp->capacity)
delete [] imp->data;
imp->data = 0;
if (imp->state == usedInPool) {
imp->state = unusedInPool;
imp->nextInFreeList = poolFreeList;
poolFreeList = imp;
poolUsed--;
} else {
assert(imp->state == usedOnHeap);
HeapListImp *list = static_cast<HeapListImp *>(imp);
// unlink from heap list
if (!list->prevInHeapList) {
heapList = list->nextInHeapList;
if (heapList) {
heapList->prevInHeapList = NULL;
}
} else {
list->prevInHeapList->nextInHeapList = list->nextInHeapList;
if (list->nextInHeapList) {
list->nextInHeapList->prevInHeapList = list->prevInHeapList;
}
}
delete list;
}
}
void List::appendSlowCase(JSValue *v)
{
ListImp *imp = static_cast<ListImp *>(_impBase);
int i = imp->size++; // insert index/old size
#if DUMP_STATISTICS
if (imp->size > listSizeHighWaterMark)
listSizeHighWaterMark = imp->size;
#endif
// If we got here, we need to use an out-of-line buffer.
if (i >= imp->capacity) {
int newCapacity = i * 2;
LocalStorageEntry* newBuffer = new LocalStorageEntry[newCapacity];
// Copy everything over
for (int c = 0; c < i; ++c)
newBuffer[c] = imp->data[c];
if (imp->capacity) // had an old out-of-line buffer
delete[] imp->data;
imp->data = newBuffer;
imp->capacity = newCapacity;
}
imp->data[i].val.valueVal = v;
}
List List::copy() const
{
List copy;
copy.copyFrom(*this);
return copy;
}
void List::copyFrom(const List& other)
{
// Assumption: we're empty (e.g. called from copy)
ListImpBase* otherImp = other._impBase;
ListImp* ourImp = static_cast<ListImp *>(_impBase);
assert(ourImp->size == 0 && ourImp->capacity == 0);
int size = otherImp->size;
ourImp->size = size;
if (size > inlineListValuesSize) {
// need an out-of-line buffer
ourImp->capacity = size;
ourImp->data = new LocalStorageEntry[size];
} else {
ourImp->capacity = 0;
}
for (int c = 0; c < size; ++c)
ourImp->data[c] = otherImp->data[c];
}
List List::copyTail() const
{
List copy;
ListImpBase* inImp = _impBase;
ListImp* outImp = static_cast<ListImp *>(copy._impBase);
int size = inImp->size - 1;
if (size < 0)
size = 0; // copyTail on empty list.
outImp->size = size;
if (size > inlineListValuesSize) {
// need an out-of-line buffer
outImp->capacity = size;
outImp->data = new LocalStorageEntry[size];
} else {
outImp->capacity = 0;
}
for (int c = 0; c < size; ++c)
outImp->data[c] = inImp->data[c+1];
return copy;
}
const List &List::empty()
{
static List emptyList;
return emptyList;
}
List &List::operator=(const List &b)
{
ListImpBase *bImpBase = b._impBase;
++bImpBase->refCount;
deref();
_impBase = bImpBase;
return *this;
}
} // namespace KJS
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;