Compare commits

..

2 Commits

Author SHA1 Message Date
fur%netscape.com
1c43d4984f This is a copy of regalloc_code2_BRANCH from Netscape's private repository,
as it existed in January of 1998.


git-svn-id: svn://10.0.0.236/branches/regalloc_code2_BRANCH@22571 18797224-902f-48f8-a5cc-f745e15eee43
1999-03-02 16:12:08 +00:00
(no author)
cfe021ff88 This commit was manufactured by cvs2svn to create branch
'regalloc_code2_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/regalloc_code2_BRANCH@22567 18797224-902f-48f8-a5cc-f745e15eee43
1999-03-02 15:57:58 +00:00
176 changed files with 5222 additions and 54340 deletions

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "BitSet.h"
// Return the next bit after index set to true or -1 if none.
//
Int32 BitSet::nextOne(Int32 pos) const
{
++pos;
if (pos < 0 || Uint32(pos) >= universeSize)
return -1;
Uint32 offset = getWordOffset(pos);
Uint8 index = getBitOffset(pos);
Word* ptr = &word[offset];
Word currentWord = *ptr++ >> index;
if (currentWord != Word(0)) {
while ((currentWord & Word(1)) == 0) {
++index;
currentWord >>= 1;
}
return (offset << nBitsInWordLog2) + index;
}
Word* limit = &word[getSizeInWords(universeSize)];
while (ptr < limit) {
++offset;
currentWord = *ptr++;
if (currentWord != Word(0)) {
index = 0;
while ((currentWord & Word(1)) == 0) {
++index;
currentWord >>= 1;
}
return (offset << nBitsInWordLog2) + index;
}
}
return -1;
}
// Return the next bit after index set to false or -1 if none.
//
Int32 BitSet::nextZero(Int32 pos) const
{
++pos;
if (pos < 0 || Uint32(pos) >= universeSize)
return -1;
Uint32 offset = getWordOffset(pos);
Uint8 index = getBitOffset(pos);
Word* ptr = &word[offset];
Word currentWord = *ptr++ >> index;
if (currentWord != Word(~0)) {
for (; index < nBitsInWord; ++index) {
if ((currentWord & Word(1)) == 0) {
Int32 ret = (offset << nBitsInWordLog2) + index;
return (Uint32(ret) < universeSize) ? ret : -1;
}
currentWord >>= 1;
}
}
Word* limit = &word[getSizeInWords(universeSize)];
while (ptr < limit) {
++offset;
currentWord = *ptr++;
if (currentWord != Word(~0)) {
for (index = 0; index < nBitsInWord; ++index) {
if ((currentWord & Word(1)) == 0) {
Int32 ret = (offset << nBitsInWordLog2) + index;
return (Uint32(ret) < universeSize) ? ret : -1;
}
currentWord >>= 1;
}
}
}
return -1;
}
#ifdef DEBUG_LOG
// Print the set.
//
void BitSet::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("[ "));
for (Int32 i = firstOne(); i != -1; i = nextOne(i)) {
Int32 currentBit = i;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", currentBit));
Int32 nextBit = nextOne(currentBit);
if (nextBit != currentBit + 1) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" "));
continue;
}
while ((nextBit != -1) && (nextBit == (currentBit + 1))) {
currentBit = nextBit;
nextBit = nextOne(nextBit);
}
if (currentBit > (i+1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("-%d ", currentBit));
else
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" %d ", currentBit));
i = currentBit;
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("]\n"));
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,195 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _BITSET_H_
#define _BITSET_H_
#include "Fundamentals.h"
#include "LogModule.h"
#include "Pool.h"
#include <string.h>
//------------------------------------------------------------------------------
// BitSet -
class BitSet
{
private:
#if (PR_BITS_PER_WORD == 64)
typedef Uint64 Word;
#elif (PR_BITS_PER_WORD == 32)
typedef Uint32 Word;
#endif
static const nBitsInWord = PR_BITS_PER_WORD;
static const nBytesInWord = PR_BYTES_PER_WORD;
static const nBitsInWordLog2 = PR_BITS_PER_WORD_LOG2;
static const nBytesInWordLog2 = PR_BYTES_PER_WORD_LOG2;
// Return the number of Word need to store the universe.
static Uint32 getSizeInWords(Uint32 sizeOfUniverse) {return (sizeOfUniverse + (nBitsInWord - 1)) >> nBitsInWordLog2;}
// Return the given element offset in its containing Word.
static Uint32 getBitOffset(Uint32 element) {return element & (nBitsInWord - 1);}
// Return the Word offset for the given element int the universe.
static Uint32 getWordOffset(Uint32 element) {return element >> nBitsInWordLog2;}
// Return the mask for the given bit index.
static Word getMask(Uint8 index) {return Word(1) << index;}
private:
Uint32 universeSize; // Size of the universe
Word* word; // universe memory.
private:
// No copy constructor.
BitSet(const BitSet&);
// Check if the given set's universe is of the same size than this universe.
void checkUniverseCompatibility(const BitSet& set) const {assert(set.universeSize == universeSize);}
// Check if pos is valid for this set's universe.
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
public:
// Create a bitset of universeSize bits.
BitSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {word = new(pool) Word[getSizeInWords(universeSize)]; clear();}
// Return the size of this bitset.
Uint32 getSize() const {return universeSize;}
// Clear the bitset.
void clear() {memset(word, 0x00, getSizeInWords(universeSize) << nBytesInWordLog2);}
// Clear the bit at index.
void clear(Uint32 index) {checkMember(index); word[getWordOffset(index)] &= ~getMask(index);}
// Set the bitset.
void set() {memset(word, 0xFF, getSizeInWords(universeSize) << nBytesInWordLog2);}
// Set the bit at index.
void set(Uint32 index) {checkMember(index); word[getWordOffset(index)] |= getMask(index);}
// Return true if the bit at index is set.
bool test(Uint32 index) const {checkMember(index); return (word[getWordOffset(index)] & getMask(index)) != 0;}
// Union with the given bitset.
inline void or(const BitSet& set);
// Intersection with the given bitset.
inline void and(const BitSet& set);
// Difference with the given bitset.
inline void difference(const BitSet& set);
// Copy set.
inline BitSet& operator = (const BitSet& set);
// Return true if the bitset are identical.
friend bool operator == (const BitSet& set1, const BitSet& set2);
// Return true if the bitset are different.
friend bool operator != (const BitSet& set1, const BitSet& set2);
// Logical operators.
BitSet& operator |= (const BitSet& set) {or(set); return *this;}
BitSet& operator &= (const BitSet& set) {and(set); return *this;}
BitSet& operator -= (const BitSet& set) {difference(set); return *this;}
// Return the first bit at set to true or -1 if none.
Int32 firstOne() const {return nextOne(-1);}
// Return the next bit after index set to true or -1 if none.
Int32 nextOne(Int32 pos) const;
// Return the first bit at set to false or -1 if none.
Int32 firstZero() const {return nextZero(-1);}
// Return the next bit after index set to false or -1 if none.
Int32 nextZero(Int32 pos) const;
// Iterator to conform with the set API.
typedef Int32 iterator;
// Return true if the walk is ordered.
static bool isOrdered() {return true;}
// Return the iterator for the first element of this set.
iterator begin() const {return firstOne();}
// Return the next iterator.
iterator advance(iterator pos) const {return nextOne(pos);}
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos == -1;}
// Return the element corresponding to the given iterator.
Uint32 get(iterator pos) const {return pos;}
#ifdef DEBUG_LOG
// Print the set.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
// Union with the given bitset.
//
inline void BitSet::or(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ |= *src++;
}
// Intersection with the given bitset.
//
inline void BitSet::and(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ &= *src++;
}
// Difference with the given bitset.
//
inline void BitSet::difference(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ &= ~*src++;
}
// Copy the given set into this set.
//
inline BitSet& BitSet::operator = (const BitSet& set)
{
checkUniverseCompatibility(set);
if (this != &set)
memcpy(word, set.word, getSizeInWords(universeSize) << nBytesInWordLog2);
return *this;
}
// Return true if the given set is identical to this set.
inline bool operator == (const BitSet& set1, const BitSet& set2)
{
set1.checkUniverseCompatibility(set2);
if (&set1 == &set2)
return true;
return memcmp(set1.word, set2.word, BitSet::getSizeInWords(set1.universeSize) << BitSet::nBytesInWordLog2) == 0;
}
inline bool operator != (const BitSet& set1, const BitSet& set2) {return !(set1 == set2);}
#endif // _BITSET_H

View File

@@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _COALESCING_H_
#define _COALESCING_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "RegisterPressure.h"
#include "InterferenceGraph.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "SparseSet.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
#if 1
// Performing an ultra conservative coalescing meens that when we look at
// candidates (source,destination) for coalescing we need to make sure
// that the combined interference of the source and destination register
// will not exceed the total number of register available for the register
// class.
#define ULTRA_CONSERVATIVE_COALESCING
#else
// If we are not doing an ultra conservative coalescing we have to make sure
// that the total number of neighbor whose degree is greater than the total
// number of register is not greater than the total number of register.
#undef ULTRA_CONSERVATIVE_COALESCING
#endif
template <class RegisterPressure>
struct Coalescing
{
static bool coalesce(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
bool Coalescing<RegisterPressure>::coalesce(RegisterAllocator& registerAllocator)
{
Pool& pool = registerAllocator.pool;
// Initialize the lookup table
//
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* newRange = new RegisterName[2 * rangeCount];
RegisterName* coalescedRange = &newRange[rangeCount];
RegisterName* name2range = registerAllocator.name2range;
init(coalescedRange, rangeCount);
SparseSet interferences(pool, rangeCount);
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
bool removedInstructions = false;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.lndList;
Uint32 nNodes = controlGraph.nNodes;
// Walk the nodes in the loop nesting depth list.
for (Int32 n = nNodes - 1; n >= 0; n--) {
InstructionList& instructions = nodes[n]->getInstructions();
InstructionList::iterator it = instructions.begin();
while (!instructions.done(it)) {
Instruction& instruction = instructions.get(it);
it = instructions.advance(it);
if ((instruction.getFlags() & ifCopy) != 0) {
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
RegisterName source = findRoot(name2range[instruction.getInstructionUseBegin()[0].getRegisterName()], coalescedRange);
RegisterName destination = findRoot(name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()], coalescedRange);
if (source == destination) {
instruction.remove();
} else if (!iGraph.interfere(source, destination)) {
InterferenceVector* sourceVector = iGraph.getInterferenceVector(source);
InterferenceVector* destinationVector = iGraph.getInterferenceVector(destination);
#ifdef ULTRA_CONSERVATIVE_COALESCING
interferences.clear();
InterferenceVector* vector;
for (vector = sourceVector; vector != NULL; vector = vector->next) {
RegisterName* neighbors = vector->neighbors;
for (Uint32 i = 0; i < vector->count; i++)
interferences.set(findRoot(neighbors[i], coalescedRange));
}
for (vector = destinationVector; vector != NULL; vector = vector->next) {
RegisterName* neighbors = vector->neighbors;
for (Uint32 i = 0; i < vector->count; i++)
interferences.set(findRoot(neighbors[i], coalescedRange));
}
Uint32 count = interferences.getSize();
#else // ULTRA_CONSERVATIVE_COALESCING
trespass("not implemented");
Uint32 count = 0;
#endif // ULTRA_CONSERVATIVE_COALESCING
if (count < 6 /* FIX: should get the number from the class */) {
// Update the interferences vector.
if (sourceVector == NULL) {
iGraph.setInterferenceVector(source, destinationVector);
sourceVector = destinationVector;
} else if (destinationVector == NULL)
iGraph.setInterferenceVector(destination, sourceVector);
else {
InterferenceVector* last = NULL;
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next)
last = v;
assert(last);
last->next = destinationVector;
iGraph.setInterferenceVector(destination, sourceVector);
}
// Update the interference matrix.
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next) {
RegisterName* neighbors = v->neighbors;
for (Uint32 i = 0; i < v->count; i++) {
RegisterName neighbor = findRoot(neighbors[i], coalescedRange);
iGraph.setInterference(neighbor, source);
iGraph.setInterference(neighbor, destination);
}
}
instruction.remove();
coalescedRange[source] = destination;
removedInstructions = true;
}
}
}
}
}
registerAllocator.rangeCount = compress(registerAllocator.name2range, coalescedRange, registerAllocator.nameCount, rangeCount);
delete newRange;
return removedInstructions;
}
#endif // _COALESCING_H_

View File

@@ -0,0 +1,283 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef NEW_LAURENTM_CODE
#include "Coloring.h"
#include "VirtualRegister.h"
#include "FastBitSet.h"
#include "FastBitMatrix.h"
#include "CpuInfo.h"
bool Coloring::
assignRegisters(FastBitMatrix& interferenceMatrix)
{
PRUint32 *stackPtr = new(pool) PRUint32[vRegManager.count()];
return select(interferenceMatrix, stackPtr, simplify(interferenceMatrix, stackPtr));
}
PRInt32 Coloring::
getLowestSpillCostRegister(FastBitSet& bitset)
{
PRInt32 lowest = bitset.firstOne();
if (lowest != -1)
{
Flt32 cost = vRegManager.getVirtualRegister(lowest).spillInfo.spillCost;
for (PRInt32 r = bitset.nextOne(lowest); r != -1; r = bitset.nextOne(r))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
if (!vReg.spillInfo.infiniteSpillCost && (vReg.spillInfo.spillCost < cost))
{
cost = vReg.spillInfo.spillCost;
lowest = r;
}
}
}
return lowest;
}
PRUint32* Coloring::
simplify(FastBitMatrix interferenceMatrix, PRUint32* stackPtr)
{
// first we construct the sets low and high. low contains all nodes of degree
// inferior to the number of register available on the processor. All the
// nodes with an high degree and a finite spill cost are placed in high.
// Nodes of high degree and infinite spill cost are not included in either sets.
PRUint32 nRegisters = vRegManager.count();
FastBitSet low(pool, nRegisters);
FastBitSet high(pool, nRegisters);
FastBitSet stack(pool, nRegisters);
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
if (vReg.getClass() == vrcStackSlot)
{
stack.set(i);
vReg.colorRegister(nRegisters);
}
else
{
if (vReg.colorInfo.interferenceDegree < NUMBER_OF_REGISTERS)
low.set(i);
else // if (!vReg.spillInfo.infiniteSpillCost)
high.set(i);
// Set coloring info.
vReg.spillInfo.willSpill = false;
switch(vReg.getClass())
{
case vrcInteger:
vReg.colorRegister(LAST_GREGISTER + 1);
break;
case vrcFloatingPoint:
case vrcFixedPoint:
vReg.colorRegister(LAST_FPREGISTER + 1);
break;
default:
PR_ASSERT(false); // Cannot happen.
}
}
}
// push the stack registers
PRInt32 j;
for (j = stack.firstOne(); j != -1; j = stack.nextOne(j))
*stackPtr++ = j;
// simplify
while (true)
{
PRInt32 r;
while ((r = getLowestSpillCostRegister(low)) != -1)
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
/* update low and high */
FastBitSet inter(interferenceMatrix.getRow(r), nRegisters);
for (j = inter.firstOne(); j != -1; j = inter.nextOne(j))
{
VirtualRegister& neighbor = vRegManager.getVirtualRegister(j);
// if the new interference degree of one of his neighbor becomes
// NUMBER_OF_REGISTERS - 1 then it is added to the set 'low'.
PRUint32 maxInterference = 0;
switch (neighbor.getClass())
{
case vrcInteger:
maxInterference = NUMBER_OF_GREGISTERS;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
maxInterference = NUMBER_OF_FPREGISTERS;
break;
default:
PR_ASSERT(false);
}
if ((vRegManager.getVirtualRegister(j).colorInfo.interferenceDegree-- == maxInterference))
{
high.clear(j);
low.set(j);
}
vReg.colorInfo.interferenceDegree--;
interferenceMatrix.clear(r, j);
interferenceMatrix.clear(j, r);
}
low.clear(r);
// Push this register.
*stackPtr++ = r;
}
if ((r = getLowestSpillCostRegister(high)) != -1)
{
high.clear(r);
low.set(r);
}
else
break;
}
return stackPtr;
}
bool Coloring::
select(FastBitMatrix& interferenceMatrix, PRUint32* stackBase, PRUint32* stackPtr)
{
PRUint32 nRegisters = vRegManager.count();
FastBitSet usedRegisters(NUMBER_OF_REGISTERS + 1); // usedRegisters if used for both GR & FPR.
FastBitSet preColoredRegisters(NUMBER_OF_REGISTERS + 1);
FastBitSet usedStack(nRegisters + 1);
bool success = true;
Int32 lastUsedSSR = -1;
// select
while (stackPtr != stackBase)
{
// Pop one register.
PRUint32 r = *--stackPtr;
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
FastBitSet neighbors(interferenceMatrix.getRow(r), nRegisters);
if (vReg.getClass() == vrcStackSlot)
// Stack slots coloring.
{
usedStack.clear();
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
usedStack.set(vRegManager.getVirtualRegister(i).getColor());
Int32 color = usedStack.firstZero();
vReg.colorRegister(color);
if (color > lastUsedSSR)
lastUsedSSR = color;
}
else
// Integer & Floating point register coloring.
{
usedRegisters.clear();
preColoredRegisters.clear();
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
{
VirtualRegister& nvReg = vRegManager.getVirtualRegister(i);
usedRegisters.set(nvReg.getColor());
if (nvReg.isPreColored())
preColoredRegisters.set(nvReg.getPreColor());
}
if (vReg.hasSpecialInterference)
usedRegisters |= vReg.specialInterference;
PRInt8 c = -1;
PRInt8 maxColor = 0;
PRInt8 firstColor = 0;
switch (vReg.getClass())
{
case vrcInteger:
firstColor = FIRST_GREGISTER;
maxColor = LAST_GREGISTER;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
firstColor = FIRST_FPREGISTER;
maxColor = LAST_FPREGISTER;
break;
default:
PR_ASSERT(false);
}
if (vReg.isPreColored())
{
c = vReg.getPreColor();
if (usedRegisters.test(c))
c = -1;
}
else
{
for (c = usedRegisters.nextZero(firstColor - 1); (c >= 0) && (c <= maxColor) && (preColoredRegisters.test(c));
c = usedRegisters.nextZero(c)) {}
}
if ((c >= 0) && (c <= maxColor))
{
vReg.colorRegister(c);
}
else
{
VirtualRegister& stackRegister = vRegManager.newVirtualRegister(vrcStackSlot);
vReg.equivalentRegister[vrcStackSlot] = &stackRegister;
vReg.spillInfo.willSpill = true;
success = false;
}
}
}
#ifdef DEBUG
if (success)
{
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
switch (vReg.getClass())
{
case vrcInteger:
if (vReg.getColor() > LAST_GREGISTER)
PR_ASSERT(false);
break;
case vrcFloatingPoint:
case vrcFixedPoint:
#if NUMBER_OF_FPREGISTERS != 0
if (vReg.getColor() > LAST_FPREGISTER)
PR_ASSERT(false);
#endif
break;
default:
break;
}
}
}
#endif
vRegManager.nUsedStackSlots = lastUsedSSR + 1;
return success;
}
#endif // NEW_LAURENTM_CODE

View File

@@ -0,0 +1,284 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "VirtualRegister.h"
#include "InterferenceGraph.h"
#include "SparseSet.h"
#include "Spilling.h"
#include "Splits.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
template <class RegisterPressure>
class Coloring
{
private:
static RegisterName* simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack);
static bool select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr);
public:
static bool color(RegisterAllocator& registerAllocator);
static void finalColoring(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
void Coloring<RegisterPressure>::finalColoring(RegisterAllocator& registerAllocator)
{
RegisterName* color = registerAllocator.color;
RegisterName* name2range = registerAllocator.name2range;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
usePtr->setRegisterName(color[name2range[usePtr->getRegisterName()]]);
#ifdef DEBUG
RegisterID rid = usePtr->getRegisterID();
setColoredRegister(rid);
usePtr->setRegisterID(rid);
#endif // DEBUG
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
definePtr->setRegisterName(color[name2range[definePtr->getRegisterName()]]);
#ifdef DEBUG
RegisterID rid = definePtr->getRegisterID();
setColoredRegister(rid);
definePtr->setRegisterID(rid);
#endif // DEBUG
}
}
}
}
template <class RegisterPressure>
bool Coloring<RegisterPressure>::select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* color = new RegisterName[rangeCount];
registerAllocator.color = color;
for (Uint32 r = 1; r < rangeCount; r++)
color[r] = RegisterName(6); // FIX;
// Color the preColored registers.
//
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
RegisterName* name2range = registerAllocator.name2range;
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
if (machinePtr->id != invalidID) {
color[name2range[getName(machinePtr->id)]] = machinePtr->color;
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill preColor range %d as %d\n", name2range[getName(machinePtr->id)], machinePtr->color));
}
SpillCost* cost = registerAllocator.spillCost;
Pool& pool = registerAllocator.pool;
SparseSet& spill = *new(pool) SparseSet(pool, rangeCount);
registerAllocator.willSpill = &spill;
SparseSet neighborColors(pool, 6); // FIX
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
bool coloringFailed = false;
while (coloringStackPtr > coloringStack) {
RegisterName range = *--coloringStackPtr;
if (!cost[range].infinite && cost[range].cost < 0) {
coloringFailed = true;
spill.set(range);
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, will spill.\n", range));
} else {
neighborColors.clear();
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = vector->count - 1; i >= 0; --i) {
RegisterName neighborColor = color[vector->neighbors[i]];
if (neighborColor < 6) // FIX
neighborColors.set(neighborColor);
}
if (neighborColors.getSize() == 6) { // FIX
coloringFailed = true;
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, ", range));
if (!Splits<RegisterPressure>::findSplit(registerAllocator, color, range)) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will spill.\n"));
spill.set(range);
} else
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will split.\n"));
} else {
for (Uint32 i = 0; i < 6; i++) // FIX
if (!neighborColors.test(i)) {
fprintf(stdout, "\twill color %d as %d\n", range, i);
color[range] = RegisterName(i);
break;
}
}
}
}
#ifdef DEBUG_LOG
if (coloringFailed) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring failed:\n"));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill spill: "));
spill.printPretty(UT_LOG_MODULE(RegAlloc));
} else {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring succeeded:\n"));
for (Uint32 i = 1; i < rangeCount; i++)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\trange %d colored as %d\n", i, color[i]));
}
#endif
return !coloringFailed;
}
template <class RegisterPressure>
RegisterName* Coloring<RegisterPressure>::simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack)
{
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
SpillCost* spillCost = registerAllocator.spillCost;
Uint32 rangeCount = registerAllocator.rangeCount;
Uint32* degree = new Uint32[rangeCount];
for (RegisterName i = RegisterName(1); i < rangeCount; i = RegisterName(i + 1)) {
InterferenceVector* vector = iGraph.getInterferenceVector(i);
degree[i] = (vector != NULL) ? vector->count : 0;
}
Pool& pool = registerAllocator.pool;
SparseSet low(pool, rangeCount);
SparseSet high(pool, rangeCount);
SparseSet highInfinite(pool, rangeCount);
SparseSet preColored(pool, rangeCount);
// Get the precolored registers.
//
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
RegisterName* name2range = registerAllocator.name2range;
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
if (machinePtr->id != invalidID)
preColored.set(name2range[getName(machinePtr->id)]);
// Insert the live ranges in the sets.
//
for (Uint32 range = 1; range < rangeCount; range++)
if (!preColored.test(range))
if (degree[range] < 6) // FIX
low.set(range);
else if (!spillCost[range].infinite)
high.set(range);
else
highInfinite.set(range);
#ifdef DEBUG_LOG
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring sets:\n\tlow = "));
low.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thigh = "));
high.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thighInfinite = "));
highInfinite.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tpreColored = "));
preColored.printPretty(UT_LOG_MODULE(RegAlloc));
#endif // DEBUG_LOG
RegisterName* coloringStackPtr = coloringStack;
while (low.getSize() != 0 || high.getSize() != 0) {
while (low.getSize() != 0) {
RegisterName range = RegisterName(low.getOne());
low.clear(range);
*coloringStackPtr++ = range;
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = (vector->count - 1); i >= 0; --i) {
RegisterName neighbor = vector->neighbors[i];
degree[neighbor]--;
if (degree[neighbor] < 6) // FIX
if (high.test(neighbor)) {
high.clear(neighbor);
low.set(neighbor);
} else if (highInfinite.test(neighbor)) {
highInfinite.clear(neighbor);
low.set(neighbor);
}
}
}
if (high.getSize() != 0) {
RegisterName best = RegisterName(high.getOne());
double bestCost = spillCost[best].cost;
double bestDegree = degree[best];
// Choose the next best candidate.
//
for (SparseSet::iterator i = high.begin(); !high.done(i); i = high.advance(i)) {
RegisterName range = RegisterName(high.get(i));
double thisCost = spillCost[range].cost;
double thisDegree = degree[range];
if (thisCost * bestDegree < bestCost * thisDegree) {
best = range;
bestCost = thisCost;
bestDegree = thisDegree;
}
}
high.clear(best);
low.set(best);
}
}
assert(highInfinite.getSize() == 0);
delete degree;
#ifdef DEBUG_LOG
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring stack:\n\t"));
for (RegisterName* sp = coloringStack; sp < coloringStackPtr; ++sp)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("%d ", *sp));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\n"));
#endif // DEBUG_LOG
return coloringStackPtr;
}
template <class RegisterPressure>
bool Coloring<RegisterPressure>::color(RegisterAllocator& registerAllocator)
{
RegisterName* coloringStack = new RegisterName[registerAllocator.rangeCount];
return select(registerAllocator, coloringStack, simplify(registerAllocator, coloringStack));
}

View File

@@ -0,0 +1,212 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include <string.h>
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "DominatorGraph.h"
DominatorGraph::DominatorGraph(ControlGraph& controlGraph) : controlGraph(controlGraph)
{
Uint32 nNodes = controlGraph.nNodes;
GtoV = new Uint32[nNodes + 1];
VtoG = new Uint32[nNodes + 1];
Uint32 v = 1;
for (Uint32 n = 0; n < nNodes; n++) {
VtoG[v] = n;
GtoV[n] = v++;
}
// Initialize all the 1-based arrays.
//
parent = new Uint32[v];
semi = new Uint32[v];
vertex = new Uint32[v];
label = new Uint32[v];
size = new Uint32[v];
ancestor = new Uint32[v];
child = new Uint32[v];
dom = new Uint32[v];
bucket = new DGLinkedList*[v];
memset(semi, '\0', v * sizeof(Uint32));
memset(bucket, '\0', v * sizeof(DGLinkedList*));
vCount = v;
build();
delete parent;
delete semi;
delete vertex;
delete label;
delete size;
delete ancestor;
delete child;
delete dom;
delete bucket;
}
Uint32 DominatorGraph::DFS(Uint32 vx, Uint32 n)
{
semi[vx] = ++n;
vertex[n] = label[vx] = vx;
ancestor[vx] = child[vx] = 0;
size[vx] = 1;
ControlNode& node = *controlGraph.dfsList[VtoG[vx]];
ControlEdge* successorEnd = node.getSuccessorsEnd();
for (ControlEdge* successorPtr = node.getSuccessorsBegin(); successorPtr < successorEnd; successorPtr++) {
Uint32 w = GtoV[successorPtr->getTarget().dfsNum];
if (semi[w] == 0) {
parent[w] = vx;
n = DFS(w, n);
}
}
return n;
}
void DominatorGraph::LINK(Uint32 vx, Uint32 w)
{
Uint32 s = w;
while (semi[label[w]] < semi[label[child[s]]]) {
if (size[s] + size[child[child[s]]] >= (size[child[s]] << 1)) {
ancestor[child[s]] = s;
child[s] = child[child[s]];
} else {
size[child[s]] = size[s];
s = ancestor[s] = child[s];
}
}
label[s] = label[w];
size[vx] += size[w];
if(size[vx] < (size[w] << 1)) {
Uint32 t = s;
s = child[vx];
child[vx] = t;
}
while( s != 0 ) {
ancestor[s] = vx;
s = child[s];
}
}
void DominatorGraph::COMPRESS(Uint32 vx)
{
if(ancestor[ancestor[vx]] != 0) {
COMPRESS(ancestor[vx]);
if(semi[label[ancestor[vx]]] < semi[label[vx]])
label[vx] = label[ancestor[vx]];
ancestor[vx] = ancestor[ancestor[vx]];
}
}
Uint32 DominatorGraph::EVAL(Uint32 vx)
{
if(ancestor[vx] == 0)
return label[vx];
COMPRESS(vx);
return (semi[label[ancestor[vx]]] >= semi[label[vx]]) ? label[vx] : label[ancestor[vx]];
}
void DominatorGraph::build()
{
Uint32 n = DFS(GtoV[0], 0);
size[0] = label[0] = semi[0];
for (Uint32 i = n; i >= 2; i--) {
Uint32 w = vertex[i];
ControlNode& node = *controlGraph.dfsList[VtoG[w]];
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
Uint32 vx = GtoV[predecessors.get(p).getSource().dfsNum];
Uint32 u = EVAL(vx);
if(semi[u] < semi[w])
semi[w] = semi[u];
}
DGLinkedList* elem = new DGLinkedList();
elem->next = bucket[vertex[semi[w]]];
elem->index = w;
bucket[vertex[semi[w]]] = elem;
LINK(parent[w], w);
elem = bucket[parent[w]];
while(elem != NULL) {
Uint32 vx = elem->index;
Uint32 u = EVAL(vx);
dom[vx] = (semi[u] < semi[vx]) ? u : parent[w];
elem = elem->next;
}
}
memset(size, '\0', n * sizeof(Uint32));
Pool& pool = controlGraph.pool;
nodes = new(pool) DGNode[n];
for(Uint32 j = 2; j <= n; j++) {
Uint32 w = vertex[j];
Uint32 d = dom[w];
if(d != vertex[semi[w]]) {
d = dom[d];
dom[w] = d;
}
size[d]++;
}
dom[GtoV[0]] = 0;
for (Uint32 k = 1; k <= n; k++) {
DGNode& node = nodes[VtoG[k]];
Uint32 count = size[k];
node.successorsEnd = node.successorsBegin = (count) ? new(pool) Uint32[count] : (Uint32*) 0;
}
for (Uint32 l = 2; l <= n; l++)
*(nodes[VtoG[dom[l]]].successorsEnd)++ = VtoG[l];
}
#ifdef DEBUG_LOG
void DominatorGraph::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Dominator Graph:\n"));
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 i = 0; i < nNodes; i++) {
DGNode& node = nodes[i];
if (node.successorsBegin != node.successorsEnd) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tN%d dominates ", i));
for (Uint32* successorsPtr = node.successorsBegin; successorsPtr < node.successorsEnd; successorsPtr++)
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d ", *successorsPtr));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _DOMINATOR_GRAPH_H_
#define _DOMINATOR_GRAPH_H_
#include "LogModule.h"
class ControlGraph;
struct DGNode
{
Uint32* successorsBegin;
Uint32* successorsEnd;
};
struct DGLinkedList
{
DGLinkedList* next;
Uint32 index;
};
class DominatorGraph
{
private:
ControlGraph& controlGraph;
Uint32 vCount;
Uint32* VtoG;
Uint32* GtoV;
Uint32* parent;
Uint32* semi;
Uint32* vertex;
Uint32* label;
Uint32* size;
Uint32* ancestor;
Uint32* child;
Uint32* dom;
DGLinkedList** bucket;
DGNode* nodes;
private:
void build();
Uint32 DFS(Uint32 vx, Uint32 n);
void LINK(Uint32 vx, Uint32 w);
void COMPRESS(Uint32 vx);
Uint32 EVAL(Uint32 vx);
public:
DominatorGraph(ControlGraph& controlGraph);
Uint32* getSuccessorsBegin(Uint32 n) const {return nodes[n].successorsBegin;}
Uint32* getSuccessorsEnd(Uint32 n) const {return nodes[n].successorsEnd;}
#ifdef DEBUG_LOG
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
#endif // _DOMINATOR_GRAPH_H_

View File

@@ -0,0 +1,20 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HashSet.h"

View File

@@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HASH_SET_H_
#define _HASH_SET_H_
#include "Fundamentals.h"
#include "Pool.h"
#include <string.h>
struct HashSetElement
{
Uint32 index;
HashSetElement* next;
};
class HashSet
{
private:
static const hashSize = 64;
// Return the hash code for the given element index.
static Uint32 getHashCode(Uint32 index) {return index & (hashSize - 1);} // Could be better !
private:
Pool& allocationPool;
HashSetElement** bucket;
HashSetElement* free;
private:
// No copy constructor.
HashSet(const HashSet&);
// No copy operator.
void operator = (const HashSet&);
public:
// Create a new HashSet.
inline HashSet(Pool& pool, Uint32 universeSize);
// Clear the hashset.
void clear();
// Clear the element for the given index.
void clear(Uint32 index);
// Set the element for the given index.
void set(Uint32 index);
// Return true if the element at index is a member.
bool test(Uint32 index) const;
// Union with the given hashset.
inline void or(const HashSet& set);
// Intersection with the given hashset.
inline void and(const HashSet& set);
// Difference with the given hashset.
inline void difference(const HashSet& set);
// Logical operators.
HashSet& operator |= (const HashSet& set) {or(set); return *this;}
HashSet& operator &= (const HashSet& set) {and(set); return *this;}
HashSet& operator -= (const HashSet& set) {difference(set); return *this;}
// Iterator to conform with the set API.
typedef HashSetElement* iterator;
// Return the iterator for the first element of this set.
iterator begin() const;
// Return the next iterator.
iterator advance(iterator pos) const;
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos == NULL;}
};
inline HashSet::HashSet(Pool& pool, Uint32 /*universeSize*/)
: allocationPool(pool), free(NULL)
{
bucket = new(pool) HashSetElement*[hashSize];
memset(bucket, '\0', sizeof(HashSetElement*));
}
#endif // _HASH_SET_H_

View File

@@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _INDEXED_POOL_H_
#define _INDEXED_POOL_H_
#include "Fundamentals.h"
#include <string.h>
#include <stdlib.h>
//------------------------------------------------------------------------------
// IndexedPool<IndexedObjectSubclass> is an indexed pool of objects. The
// template parameter 'IndexedObjectSubclass' must be a subclass of the struct
// IndexedObject.
//
// When the indexed pool is ask to allocate and initialize a new object (using
// the operator new(anIndexedPool) it will zero the memory used to store the
// object and initialize the field 'index' of this object to its position in
// the pool.
//
// An object allocated by the indexed pool can be freed by calling the method
// IndexedPool::release(IndexedElement& objectIndex).
//
// example:
//
// IndexedPool<IndexedElement> elementPool;
//
// IndexedElement& element1 = *new(elementPool) IndexedElement();
// IndexedElement& element2 = *new(elementPool) IndexedElement();
//
// indexedPool.release(element1);
// IndexedElement& element3 = *new(elementPool) IndexedElement();
//
// At this point element1 is no longer a valid object, element2 is at
// index 2 and element3 is at index 1.
//
//------------------------------------------------------------------------------
// IndexedObject -
//
template<class Object>
struct IndexedObject
{
Uint32 index; // Index in the pool.
Object* next; // Used to link IndexedObject together.
Uint32 getIndex() {return index;}
};
//------------------------------------------------------------------------------
// IndexedPool<IndexedObject> -
//
template <class IndexedObject>
class IndexedPool
{
private:
static const blockSize = 4; // Size of one block.
Uint32 nBlocks; // Number of blocks in the pool.
IndexedObject** block; // Array of block pointers.
IndexedObject* freeObjects; // Chained list of free IndexedObjects.
Uint32 nextIndex; // Index of the next free object in the last block.
private:
void allocateAnotherBlock();
IndexedObject& newObject();
public:
IndexedPool() : nBlocks(0), block(NULL), freeObjects(NULL), nextIndex(1) {}
~IndexedPool();
IndexedObject& get(Uint32 index) const;
void release(IndexedObject& object);
void setSize(Uint32 size) {assert(size < nextIndex); nextIndex = size;}
// Return the universe size.
Uint32 getSize() {return nextIndex;}
friend void* operator new(size_t, IndexedPool<IndexedObject>& pool); // Needs to call newObject().
};
// Free all the memory allocated for this object.
//
template <class IndexedObject>
IndexedPool<IndexedObject>::~IndexedPool()
{
for (Uint32 n = 0; n < nBlocks; n++)
free(&((IndexedObject **) &block[n][n*blockSize])[-(n + 1)]);
}
// Release the given. This object will be iserted in the chained
// list of free IndexedObjects. To minimize the fragmentation the chained list
// is ordered by ascending indexes.
//
template <class IndexedObject>
void IndexedPool<IndexedObject>::release(IndexedObject& object)
{
Uint32 index = object.index;
IndexedObject* list = freeObjects;
assert(&object == &get(index)); // Make sure that object is owned by this pool.
if (list == NULL) { // The list is empty.
freeObjects = &object;
object.next = NULL;
} else { // The list contains at least 1 element.
if (index < list->index) { // insert as first element.
freeObjects = &object;
object.next = list;
} else { // Find this object's place.
while ((list->next) != NULL && (list->next->index < index))
list = list->next;
object.next = list->next;
list->next = &object;
}
}
#ifdef DEBUG
// Sanity check to be sure that the list is correctly ordered.
for (IndexedObject* obj = freeObjects; obj != NULL; obj = obj->next)
if (obj->next != NULL)
assert(obj->index < obj->next->index);
#endif
}
// Create a new block of IndexedObjects. We will allocate the memory to
// store IndexedPool::blockSize IndexedObject and the new Array of block
// pointers.
// The newly created IndexedObjects will not be initialized.
//
template <class IndexedObject>
void IndexedPool<IndexedObject>::allocateAnotherBlock()
{
void* memory = (void *) malloc((nBlocks + 1) * sizeof(Uint32) + blockSize * sizeof(IndexedObject));
memcpy(memory, block, nBlocks * sizeof(Uint32));
block = (IndexedObject **) memory;
IndexedObject* objects = (IndexedObject *) &block[nBlocks + 1];
block[nBlocks] = &objects[-(nBlocks * blockSize)];
nBlocks++;
}
// Return the IndexedObject at the position 'index' in the pool.
//
template <class IndexedObject>
IndexedObject& IndexedPool<IndexedObject>::get(Uint32 index) const
{
Uint32 blockIndex = index / blockSize;
assert(blockIndex < nBlocks);
return block[blockIndex][index];
}
// Return the reference of an unused object in the pool.
//
template <class IndexedObject>
IndexedObject& IndexedPool<IndexedObject>::newObject()
{
if (freeObjects != NULL) {
IndexedObject& newObject = *freeObjects;
freeObjects = newObject.next;
return newObject;
}
Uint32 nextIndex = this->nextIndex++;
Uint32 blockIndex = nextIndex / blockSize;
while (blockIndex >= nBlocks)
allocateAnotherBlock();
IndexedObject& newObject = block[blockIndex][nextIndex];
newObject.index = nextIndex;
return newObject;
}
// Return the address of the next unsused object in the given
// indexed pool. The field index of the newly allocated object
// will be initialized to the corresponding index of this object
// in the pool.
//
template <class IndexedObject>
void* operator new(size_t size, IndexedPool<IndexedObject>& pool)
{
assert(size == sizeof(IndexedObject));
return (void *) &pool.newObject();
}
#endif // _INDEXED_POOL_H_

View File

@@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _INTERFERENCE_GRAPH_H_
#define _INTERFERENCE_GRAPH_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "Primitives.h"
#include "Instruction.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h"
#include "SparseSet.h"
#include <string.h>
struct InterferenceVector
{
Uint32 count;
InterferenceVector* next;
RegisterName* neighbors;
InterferenceVector() : count(0), next(NULL) {}
};
class RegisterAllocator;
template <class RegisterPressure>
class InterferenceGraph
{
private:
RegisterAllocator& registerAllocator;
RegisterPressure::Set* interferences;
InterferenceVector** vector;
Uint32* offset;
Uint32 rangeCount;
private:
// No copy constructor.
InterferenceGraph(const InterferenceGraph&);
// No copy operator.
void operator = (const InterferenceGraph&);
// Check if reg is a member of the universe.
void checkMember(RegisterName name) {assert(name < rangeCount);}
// Return the edge index for the interference between name1 and name2.
Uint32 getEdgeIndex(RegisterName name1, RegisterName name2);
public:
InterferenceGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
// Calculate the interferences.
void build();
// Return true if reg1 and reg2 interfere.
bool interfere(RegisterName name1, RegisterName name2);
// Return the interference vector for the given register or NULL if there is none.
InterferenceVector* getInterferenceVector(RegisterName name) {return vector[name];}
// Set the interference between name1 and name2.
void setInterference(RegisterName name1, RegisterName name2);
// Set the interference vector for the given register.
void setInterferenceVector(RegisterName name, InterferenceVector* v) {vector[name] = v;}
#ifdef DEBUG_LOG
// Print the interferences.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::build()
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
this->rangeCount = rangeCount;
// Initialize the structures.
//
offset = new(pool) Uint32[rangeCount + 1];
vector = new(pool) InterferenceVector*[rangeCount];
memset(vector, '\0', sizeof(InterferenceVector*) * rangeCount);
Uint32 o = 0;
offset[0] = 0;
for (Uint32 i = 1; i <= rangeCount; ++i) {
offset[i] = o;
o += i;
}
interferences = new(pool) RegisterPressure::Set(pool, (rangeCount * rangeCount) / 2);
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
LivenessInfo<RegisterPressure> liveness = Liveness<RegisterPressure>::analysis(controlGraph, rangeCount, name2range);
registerAllocator.liveness = liveness;
SparseSet currentLive(pool, rangeCount);
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
currentLive = liveness.liveOut[n];
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
// Handle the copy instruction to avoid unnecessary interference between the 2 registers.
if ((instruction.getFlags() & ifCopy) != 0) {
assert(useBegin != useEnd && useBegin[0].isRegister());
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
}
// Create the interferences.
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName define = name2range[definePtr->getRegisterName()];
for (SparseSet::iterator e = currentLive.begin(); !currentLive.done(e); e = currentLive.advance(e)) {
RegisterName live = RegisterName(currentLive.get(e));
if ((live != define) && !interfere(live, define) && registerAllocator.canInterfere(live, define)) {
if (vector[define] == NULL)
vector[define] = new(pool) InterferenceVector();
vector[define]->count++;
if (vector[live] == NULL)
vector[live] = new(pool) InterferenceVector();
vector[live]->count++;
setInterference(live, define);
}
}
}
// Now update the liveness.
//
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
currentLive.set(name2range[usePtr->getRegisterName()]);
}
}
// Allocate the memory to store the interferences.
//
for (Uint32 e = 0; e < rangeCount; e++)
if (vector[e] != NULL) {
InterferenceVector& v = *vector[e];
v.neighbors = new(pool) RegisterName[v.count];
v.count = 0;
}
// Initialize the edges.
//
if (RegisterPressure::Set::isOrdered()) {
RegisterName name1 = RegisterName(0);
for (RegisterPressure::Set::iterator i = interferences->begin(); !interferences->done(i); i = interferences->advance(i)) {
Uint32 interferenceIndex = interferences->get(i);
while(interferenceIndex >= offset[name1 + 1])
name1 = RegisterName(name1 + 1);
assert((interferenceIndex >= offset[name1]) && (interferenceIndex < offset[name1 + 1]));
RegisterName name2 = RegisterName(interferenceIndex - offset[name1]);
assert(interfere(name1, name2));
InterferenceVector& vector1 = *vector[name1];
vector1.neighbors[vector1.count++] = name2;
InterferenceVector& vector2 = *vector[name2];
vector2.neighbors[vector2.count++] = name1;
}
} else {
trespass("not Implemented"); // FIX: need one more pass to initialize the vectors.
}
}
template <class RegisterPressure>
Uint32 InterferenceGraph<RegisterPressure>::getEdgeIndex(RegisterName name1, RegisterName name2)
{
checkMember(name1); checkMember(name2);
assert(name1 != name2); // This is not possible.
return (name1 < name2) ? offset[name2] + name1 : offset[name1] + name2;
}
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::setInterference(RegisterName name1, RegisterName name2)
{
interferences->set(getEdgeIndex(name1, name2));
}
template <class RegisterPressure>
bool InterferenceGraph<RegisterPressure>::interfere(RegisterName name1, RegisterName name2)
{
return interferences->test(getEdgeIndex(name1, name2));
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Vectors:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
if (vector[i] != NULL) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tvr%d: (", i));
for (InterferenceVector* v = vector[i]; v != NULL; v = v->next)
for (Uint32 j = 0; j < v->count; j++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", v->neighbors[j]));
if (v->next != NULL || j != (v->count - 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (","));
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (")\n"));
}
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Matrix:\n"));
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && interfere(name1, name2)) ? '1' : '0'));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _INTERFERENCE_GRAPH_H_

View File

@@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVE_RANGE_H_
#define _LIVE_RANGE_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
template <class RegisterPressure>
struct LiveRange
{
static void build(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
void LiveRange<RegisterPressure>::build(RegisterAllocator& registerAllocator)
{
// Intialize the lookup table.
//
Uint32 nameCount = registerAllocator.nameCount;
RegisterName* nameTable = new(registerAllocator.pool) RegisterName[2*nameCount];
RegisterName* rangeName = &nameTable[nameCount];
init(rangeName, nameCount);
// Walk the graph.
//
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
SparseSet destination(registerAllocator.pool, nameCount);
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
destination.clear();
for (InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
Instruction& phiNode = phiNodes.get(i);
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
destination.set(findRoot(phiNode.getInstructionDefineBegin()[0].getRegisterName(), rangeName));
}
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
RegisterName destinationName = phiNode.getInstructionDefineBegin()[0].getRegisterName();
RegisterName destinationRoot = findRoot(destinationName, rangeName);
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
assert(usePtr->isRegister());
RegisterName sourceName = usePtr->getRegisterName();
RegisterName sourceRoot = findRoot(sourceName, rangeName);
if (sourceRoot != destinationRoot && !destination.test(sourceRoot))
rangeName[sourceRoot] = destinationRoot;
}
}
}
registerAllocator.rangeCount = compress(registerAllocator.name2range, rangeName, nameCount, nameCount);
}
#endif // _LIVE_RANGE_H_

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVE_RANGE_GRAPH_
#define _LIVE_RANGE_GRAPH_
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterTypes.h"
class RegisterAllocator;
template <class RegisterPressure>
class LiveRangeGraph
{
private:
RegisterAllocator& registerAllocator;
RegisterPressure::Set* edges;
Uint32 rangeCount;
public:
//
//
LiveRangeGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
//
//
void build();
//
//
void addEdge(RegisterName name1, RegisterName name2);
//
//
bool haveEdge(RegisterName name1, RegisterName name2);
#ifdef DEBUG_LOG
//
//
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::build()
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
this->rangeCount = rangeCount;
edges = new(pool) RegisterPressure::Set(pool, rangeCount * rangeCount);
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
LivenessInfo<RegisterPressure>& liveness = registerAllocator.liveness;
SparseSet currentLive(pool, rangeCount);
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
currentLive = liveness.liveOut[n];
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
if ((instruction.getFlags() & ifCopy) != 0) {
assert(useBegin != useEnd && useBegin[0].isRegister());
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName define = name2range[definePtr->getRegisterName()];
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
RegisterName live = RegisterName(currentLive.get(l));
if (define != live && registerAllocator.canInterfere(define, live))
addEdge(define, live);
}
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
currentLive.set(name2range[usePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName use = name2range[usePtr->getRegisterName()];
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
RegisterName live = RegisterName(currentLive.get(l));
if (use != live && registerAllocator.canInterfere(use, live))
addEdge(use, live);
}
}
}
}
}
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::addEdge(RegisterName name1, RegisterName name2)
{
assert(name1 != name2);
edges->set(name1 * rangeCount + name2);
}
template <class RegisterPressure>
bool LiveRangeGraph<RegisterPressure>::haveEdge(RegisterName name1, RegisterName name2)
{
assert(name1 != name2);
return edges->test(name1 * rangeCount + name2);
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Live ranges graph:\n"));
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && haveEdge(name1, name2)) ? '1' : '0'));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _LIVE_RANGE_GRAPH_

View File

@@ -16,12 +16,6 @@
* Reserved.
*/
#include "nsIEnumerator.idl"
#include "Fundamentals.h"
#include "Liveness.h"
interface nsIFile;
[scriptable, uuid(D7BEA930-59D7-11d3-8C46-00609792278C)]
interface nsIDirectoryEnumerator : nsISimpleEnumerator
{
void Init(in nsIFile parent, in boolean resolveSymlinks);
};

View File

@@ -0,0 +1,301 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVENESS_H_
#define _LIVENESS_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterTypes.h"
// ----------------------------------------------------------------------------
// LivenessInfo -
template <class RegisterPressure>
struct LivenessInfo
{
RegisterPressure::Set* liveIn;
RegisterPressure::Set* liveOut;
DEBUG_LOG_ONLY(Uint32 size);
#ifdef DEBUG_LOG
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
// ----------------------------------------------------------------------------
// Liveness
//
// The liveness is defined by the following data-flow equations:
//
// LiveIn(n) = LocalLive(n) U (LiveOut(n) - Killed(n)).
// LiveOut(n) = U LiveIn(s) (s a successor of n).
//
// where LocalLive(n) is the set of used registers in the block n, Killed(n)
// is the set of defined registers in the block n, LiveIn(n) is the set of
// live registers at the begining of the block n and LiveOut(n) is the set
// of live registers at the end of the block n.
//
//
// We will compute the liveness analysis in two stages:
//
// 1- Build LocalLive(n) (wich is an approximation of LiveIn(n)) and Killed(n)
// for each block n.
// 2- Perform a backward data-flow analysis to propagate the liveness information
// through the entire control-flow graph.
//
template <class RegisterPressure>
struct Liveness
{
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range);
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 nameCount);
};
template <class RegisterPressure>
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Allocate the temporary sets.
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
// Allocate the globals sets.
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
//
for (Uint32 n = 0; n < (nNodes - 1); n++) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLocalLive = liveIn[n];
RegisterPressure::Set& currentKilled = killed[n];
// Find the instructions contributions to the sets LocalLive and Killed.
//
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
Uint32 index = name2range[usePtr->getRegisterName()];
if (!currentKilled.test(index))
currentLocalLive.set(index);
}
// If a Virtualregister is 'defined' then we add it to the set Killed.
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentKilled.set(name2range[definePtr->getRegisterName()]);
}
}
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
// control-flow graph.
//
RegisterPressure::Set temp(pool, rangeCount);
bool changed;
do {
changed = false;
// For all nodes is this graph except the endNode.
for (Int32 n = (nNodes - 2); n >= 0; n--) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLiveIn = liveIn[n];
RegisterPressure::Set& currentLiveOut = liveOut[n];
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
// temp will be the new LiveOut(n).
Uint32 nSuccessors = node.nSuccessors();
if (nSuccessors != 0) {
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
for (Uint32 s = 1; s < nSuccessors; s++)
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
} else
temp.clear();
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
// new LiveIn(n).
if (currentLiveOut != temp) {
currentLiveOut = temp;
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
temp |= currentLiveIn;
if (currentLiveIn != temp) {
currentLiveIn = temp;
changed = true;
}
}
}
} while(changed);
LivenessInfo<RegisterPressure> liveness;
liveness.liveIn = liveIn;
liveness.liveOut = liveOut;
DEBUG_LOG_ONLY(liveness.size = nNodes);
return liveness;
}
template <class RegisterPressure>
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 nameCount)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Allocate the temporary sets.
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
RegisterPressure::Set* usedByPhiNodes = NULL;
// Allocate the globals sets.
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
//
for (Uint32 n = 0; n < (nNodes - 1); n++) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLocalLive = liveIn[n];
RegisterPressure::Set& currentKilled = killed[n];
InstructionList& phiNodes = node.getPhiNodeInstructions();
if ((usedByPhiNodes == NULL) && !phiNodes.empty())
usedByPhiNodes = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
InstructionDefine& define = phiNode.getInstructionDefineBegin()[0];
currentKilled.set(define.getRegisterName());
typedef DoublyLinkedList<ControlEdge> ControlEdgeList;
const ControlEdgeList& predecessors = node.getPredecessors();
ControlEdgeList::iterator p = predecessors.begin();
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++, p = predecessors.advance(p))
if (usePtr->isRegister())
usedByPhiNodes[predecessors.get(p).getSource().dfsNum].set(usePtr->getRegisterName());
}
// Find the instructions contributions to the sets LocalLive and Killed.
//
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
Uint32 index = usePtr->getRegisterName();
if (!currentKilled.test(index))
currentLocalLive.set(index);
}
// If a Virtualregister is 'defined' then we add it to the set Killed.
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentKilled.set(definePtr->getRegisterName());
}
}
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
// control-flow graph.
//
RegisterPressure::Set temp(pool, nameCount);
bool changed;
do {
changed = false;
// For all nodes is this graph except the endNode.
for (Int32 n = (nNodes - 2); n >= 0; n--) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLiveIn = liveIn[n];
RegisterPressure::Set& currentLiveOut = liveOut[n];
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
// temp will be the new LiveOut(n).
Uint32 nSuccessors = node.nSuccessors();
if (nSuccessors != 0) {
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
for (Uint32 s = 1; s < nSuccessors; s++)
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
} else
temp.clear();
// Insert the phiNodes contribution.
if (usedByPhiNodes != NULL)
temp |= usedByPhiNodes[n];
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
// new LiveIn(n).
if (currentLiveOut != temp) {
currentLiveOut = temp;
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
temp |= currentLiveIn;
if (currentLiveIn != temp) {
currentLiveIn = temp;
changed = true;
}
}
}
} while(changed);
LivenessInfo<RegisterPressure> liveness;
liveness.liveIn = liveIn;
liveness.liveOut = liveOut;
DEBUG_LOG_ONLY(liveness.size = nNodes);
return liveness;
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void LivenessInfo<RegisterPressure>::printPretty(LogModuleObject log)
{
for (Uint32 n = 0; n < size; n++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Node N%d:\n\tliveIn = ", n));
liveIn[n].printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tliveOut = "));
liveOut[n].printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _LIVENESS_H_

View File

@@ -0,0 +1,40 @@
#! gmake
DEPTH = ../..
MODULE_NAME = RegisterAllocator
include $(DEPTH)/config/config.mk
INCLUDES += \
-I$(DEPTH)/Utilities/General \
-I$(DEPTH)/Utilities/zlib \
-I$(DEPTH)/Runtime/ClassReader \
-I$(DEPTH)/Runtime/NativeMethods \
-I$(DEPTH)/Runtime/System \
-I$(DEPTH)/Runtime/ClassInfo \
-I$(DEPTH)/Runtime/FileReader \
-I$(DEPTH)/Compiler/PrimitiveGraph \
-I$(DEPTH)/Compiler/FrontEnd \
-I$(DEPTH)/Compiler/Optimizer \
-I$(DEPTH)/Compiler/CodeGenerator \
-I$(DEPTH)/Compiler/CodeGenerator/md \
-I$(DEPTH)/Compiler/CodeGenerator/md/$(CPU_ARCH) \
-I$(DEPTH)/Compiler/RegisterAllocator \
-I$(DEPTH)/Driver/StandAloneJava \
-I$(DEPTH)/Debugger \
$(NULL)
CXXSRCS = \
RegisterAllocator.cpp \
RegisterAllocatorTools.cpp \
DominatorGraph.cpp \
VirtualRegister.cpp \
BitSet.cpp \
SparseSet.cpp \
$(NULL)
include $(DEPTH)/config/rules.mk
libs:: $(MODULE)

View File

@@ -0,0 +1,392 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _PHI_NODE_REMOVER_H_
#define _PHI_NODE_REMOVER_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "DominatorGraph.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h"
#include "Liveness.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "SparseSet.h"
#include <string.h>
//------------------------------------------------------------------------------
// RegisterNameNode -
struct RegisterNameNode
{
RegisterNameNode* next;
RegisterName newName;
Uint32 nextPushed;
};
//------------------------------------------------------------------------------
// CopyData -
struct CopyData
{
RegisterName source;
RegisterClassKind classKind;
Uint32 useCount;
bool isLiveOut;
RegisterName sourceNameToUse;
RegisterName temporaryName;
RegisterNameNode* newName;
};
//------------------------------------------------------------------------------
// PhiNodeRemover<RegisterPressure> -
template <class RegisterPressure>
struct PhiNodeRemover
{
// Replace the phi nodes by copy instructions.
static void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
};
// Split some of the critical edges and return true if there are still some
// in the graph after that.
//
static bool splitCriticalEdges(ControlGraph& /*cg*/)
{
// FIX: not implemented.
return true;
}
inline void pushName(Pool& pool, RegisterNameNode** stack, SparseSet& pushed, Uint32* nodeListPointer, RegisterName oldName, RegisterName newName)
{
RegisterNameNode& newNode = *new(pool) RegisterNameNode();
if (pushed.test(oldName))
(*stack)->newName = newName;
else {
newNode.newName = newName;
newNode.nextPushed = *nodeListPointer;
*nodeListPointer = oldName;
newNode.next = *stack;
*stack = &newNode;
pushed.set(oldName);
}
}
template <class RegisterPressure>
void PhiNodeRemover<RegisterPressure>::replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Initialize the local variables.
//
// When we insert the copies we will also need to create new VirtualRegisters for
// the insertion of temporaries. The maximum number of temporary register will not
// exceed the number of phiNodes in the primitive graph.
Uint32 nameCount = vrManager.getSize();
Uint32 maxNameCount = nameCount;
for (Uint32 n = 0; n < nNodes; n++)
maxNameCount += nodes[n]->getPhiNodes().length();
// If the CFG contains some critical edges (backward edge which source has more than one
// outgoing edge and destination has more than one incomimg edge) then we need the liveness
// information to be able to insert temporary copies.
RegisterPressure::Set* liveOut = NULL;
if (splitCriticalEdges(controlGraph))
liveOut = Liveness<LowRegisterPressure>::analysis(controlGraph, nameCount).liveOut;
DominatorGraph dGraph(controlGraph);
SparseSet pushed(pool, maxNameCount);
SparseSet destinationList(pool, maxNameCount);
SparseSet workList(pool, maxNameCount);
CopyData* copyStats = new(pool) CopyData[maxNameCount];
memset(copyStats, '\0', maxNameCount*sizeof(CopyData));
struct NodeStack {
Uint32* next;
Uint32* limit;
Uint32 pushedList;
};
// Allocate the node stack and initialize the node stack pointer.
NodeStack* nodeStack = new(pool) NodeStack[nNodes + 1];
NodeStack* nodeStackPtr = nodeStack;
// We start by the begin node.
Uint32 startNode = 0;
Uint32* next = &startNode;
Uint32* limit = &startNode + 1;
while (true) {
if (next == limit) {
// If there are no more node in the sibling, we have to pop the current
// frame from the stack and update the copyStats of the pushed nodes.
//
if (nodeStackPtr == nodeStack)
// We are at the bottom of the stack and there are no more nodes
// to look at. We are done !
break;
--nodeStackPtr;
// We are done with all the children of this node in the dominator tree.
// We need to update the copy information of all the new names pushed
// during the walk over this node.
Uint32 pushedList = nodeStackPtr->pushedList;
while (pushedList != 0) {
Uint32 nextName = copyStats[pushedList].newName->nextPushed;
copyStats[pushedList].newName = copyStats[pushedList].newName->next;
pushedList = nextName;
}
// restore the previous frame.
next = nodeStackPtr->next;
limit = nodeStackPtr->limit;
} else {
Uint32 currentNode = *next++;
Uint32 pushedList = 0;
// Initialize the sets.
pushed.clear();
destinationList.clear();
// STEP1:
// Walk the instruction list and to replace all the instruction uses with their new name.
// If the instruction is a phi node and its defined register is alive at the end of this
// block then we push the defined register into the stack.
//
ControlNode& node = *nodes[currentNode];
RegisterPressure::Set* currentLiveOut = (liveOut != NULL) ? &liveOut[currentNode] : (RegisterPressure::Set*) 0;
InstructionList& phiNodes = node.getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
assert(usePtr->isRegister());
RegisterName name = usePtr->getRegisterName();
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
usePtr->setRegisterName(copyStats[name].newName->newName);
}
if (currentLiveOut != NULL) {
// This is a phi node and we have to push its defined name if it is live
// at the end of the node. We only need to do this if the CFG has critical edges.
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
RegisterName name = phiNode.getInstructionDefineBegin()[0].getRegisterName();
if (currentLiveOut->test(name))
pushName(pool, &(copyStats[name].newName), pushed, &pushedList, name, name);
}
}
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
usePtr->setRegisterName(copyStats[name].newName->newName);
}
}
// STEP2:
// Look at this node's successors' phiNodes. We keep track of the number of time
// a VR will be used by another copy instruction and insert each definition into the
// destinationList. This is the only pass over this node's successors as we will
// get all the information we need in the CopyData structures.
//
ControlEdge* successorEdgeEnd = node.getSuccessorsEnd();
for (ControlEdge* successorEdgePtr = node.getSuccessorsBegin(); successorEdgePtr < successorEdgeEnd; successorEdgePtr++) {
Uint32 useIndex = successorEdgePtr->getIndex();
ControlNode& successor = successorEdgePtr->getTarget();
// Look at its phi nodes. The phi nodes are at the top of the instruction list. We exit
// as soon as we find an instruction which is not a phi node
InstructionList& phiNodes = successor.getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
assert((phiNode.getInstructionUseBegin() + useIndex) < phiNode.getInstructionUseEnd());
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd());
InstructionUse& source = phiNode.getInstructionUseBegin()[useIndex];
InstructionDefine& destination = phiNode.getInstructionDefineBegin()[0];
assert(source.isRegister() && destination.isRegister());
RegisterName sourceName = source.getRegisterName();
RegisterName destinationName = destination.getRegisterName();
// Get the correct name for the source.
if (copyStats[sourceName].newName != NULL)
sourceName = copyStats[sourceName].newName->newName;
// Update the CopyData structures.
if ((sourceName != rnInvalid) && (sourceName != destinationName)) {
copyStats[destinationName].source = sourceName;
copyStats[destinationName].classKind = destination.getRegisterClass();
copyStats[destinationName].isLiveOut = (currentLiveOut != NULL) ? currentLiveOut->test(destinationName) : false;
copyStats[destinationName].sourceNameToUse = destinationName;
copyStats[sourceName].sourceNameToUse = sourceName;
copyStats[sourceName].useCount++;
destinationList.set(destinationName);
}
}
}
// STEP3:
// Insert into the worklist only the destination registers that will be not used in
// another copy instruction in this block.
//
assert(workList.getSize() == 0);
for (SparseSet::iterator d = destinationList.begin(); !destinationList.done(d); d = destinationList.advance(d)) {
Uint32 dest = destinationList.get(d);
if (copyStats[dest].useCount == 0)
workList.set(dest);
}
// STEP4:
// Insert the copy instructions.
//
Uint32 destinationListSize = destinationList.getSize();
InstructionList::iterator endOfTheNode = instructions.end();
// Find the right place to insert the copy instructions.
if (destinationListSize != 0)
while (instructions.get(endOfTheNode).getFlags() & ifControl)
endOfTheNode = instructions.retreat(endOfTheNode);
while (destinationListSize != 0) {
while(workList.getSize()) {
RegisterName destinationName = RegisterName(workList.getOne());
RegisterName sourceName = copyStats[destinationName].source;
workList.clear(destinationName);
if (copyStats[destinationName].isLiveOut && !copyStats[destinationName].temporaryName) {
// Lost copy problem.
copyStats[destinationName].isLiveOut = false;
RegisterName sourceName = destinationName;
RegisterClassKind classKind = copyStats[sourceName].classKind;
RegisterName destinationName = getName(vrManager.newVirtualRegister(classKind));
assert(destinationName < maxNameCount);
copyStats[destinationName].classKind = classKind;
copyStats[sourceName].useCount = 0;
// We need to insert a copy to a temporary register to keep the
// source register valid at the end of the node defining it.
// This copy will be inserted right after the phi node defining it.
RegisterName from = copyStats[sourceName].sourceNameToUse;
Instruction* definingPhiNode = vrManager.getVirtualRegister(from).getDefiningInstruction();
assert(definingPhiNode && (definingPhiNode->getFlags() & ifPhiNode) != 0);
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*definingPhiNode->getPrimitive(), fromID, toID);
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
definingPhiNode->getPrimitive()->getContainer()->getInstructions().addFirst(copy);
copyStats[sourceName].temporaryName = destinationName;
copyStats[sourceName].sourceNameToUse = destinationName;
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
}
// Insert the copy instruction at the end of the current node.
RegisterName from = copyStats[sourceName].sourceNameToUse;
RegisterClassKind classKind = copyStats[destinationName].classKind;
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
instructions.insertAfter(copy, endOfTheNode);
endOfTheNode = instructions.advance(endOfTheNode);
copyStats[sourceName].useCount = 0;
if (destinationList.test(sourceName) && copyStats[sourceName].isLiveOut)
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
copyStats[sourceName].isLiveOut = false;
copyStats[sourceName].sourceNameToUse = destinationName;
if (destinationList.test(sourceName))
workList.set(sourceName);
destinationList.clear(destinationName);
}
destinationListSize = destinationList.getSize();
if (destinationListSize != 0) {
RegisterName sourceName = RegisterName(destinationList.getOne());
RegisterName destinationName;
if (!copyStats[sourceName].temporaryName) {
// Cycle problem.
RegisterClassKind classKind = copyStats[sourceName].classKind;
destinationName = getName(vrManager.newVirtualRegister(classKind));
assert(destinationName < maxNameCount);
copyStats[destinationName].classKind = classKind;
copyStats[sourceName].temporaryName = destinationName;
// Insert the copy instruction at the end of the current node.
RegisterName from = copyStats[sourceName].sourceNameToUse;
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
instructions.insertAfter(copy, endOfTheNode);
endOfTheNode = instructions.advance(endOfTheNode);
} else
destinationName = copyStats[sourceName].temporaryName;
copyStats[sourceName].useCount = 0;
copyStats[sourceName].isLiveOut = false;
copyStats[sourceName].sourceNameToUse = destinationName;
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
workList.set(sourceName);
}
}
nodeStackPtr->pushedList = pushedList;
nodeStackPtr->next = next;
nodeStackPtr->limit = limit;
++nodeStackPtr;
next = dGraph.getSuccessorsBegin(currentNode);
limit = dGraph.getSuccessorsEnd(currentNode);
}
}
}
#endif // _PHI_NODE_REMOVER_H_

View File

@@ -0,0 +1,155 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "LogModule.h"
#include "RegisterAllocator.h"
#include "RegisterPressure.h"
#include "RegisterAllocatorTools.h"
#include "PhiNodeRemover.h"
#include "LiveRange.h"
#include "Liveness.h"
#include "InterferenceGraph.h"
#include "LiveRangeGraph.h"
#include "Coalescing.h"
#include "Spilling.h"
#include "Coloring.h"
#include "Splits.h"
class Pool;
class ControlGraph;
class VirtualRegisterManager;
class InstructionEmitter;
UT_DEFINE_LOG_MODULE(RegAlloc);
void RegisterAllocator::allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
{
// Insert the phi node instructions. We want to do this to have a single defined register per instruction.
// If we keep the PhiNode (as a DataNode) and a PhiNode is of DoubleWordKind then we have to execute
// some special code for the high word annotation.
//
RegisterAllocatorTools::insertPhiNodeInstructions(controlGraph, emitter);
// Perform some tests on the instruction graph.
//
DEBUG_ONLY(RegisterAllocatorTools::testTheInstructionGraph(controlGraph, vrManager));
// Replace the phi node instructions by their equivalent copy instructions.
//
PhiNodeRemover<LowRegisterPressure>::replacePhiNodes(controlGraph, vrManager, emitter);
// Do the register allocation.
//
RegisterAllocator registerAllocator(pool, controlGraph, vrManager, emitter);
registerAllocator.doGraphColoring();
}
void RegisterAllocator::doGraphColoring()
{
// Initialize the liverange map.
//
initLiveRanges();
// Build the live ranges. We do this to compress the number of RegisterNames
// used in the insterference graph.
//
LiveRange<LowRegisterPressure>::build(*this);
// Remove unnecessary copies.
//
RegisterAllocatorTools::removeUnnecessaryCopies(*this);
for (Uint8 loop = 0; loop < 10; loop++) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********* RegisterAllocator loop %d *********\n", loop));
while(true) {
// Build the interference graph.
//
iGraph.build();
// Coalesce the copy instructions.
//
if (!Coalescing<LowRegisterPressure>::coalesce(*this))
break;
}
// Print the interference graph.
//
DEBUG_LOG_ONLY(iGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
// Calculate the spill costs.
//
Spilling<LowRegisterPressure>::calculateSpillCosts(*this);
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSpillCosts(*this));
// Calculate the split costs.
//
Splits<LowRegisterPressure>::calculateSplitCosts(*this);
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSplitCosts(*this));
// Build the live range graph.
//
lGraph.build();
DEBUG_LOG_ONLY(lGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
// Color the graph. If it succeeds then we're done with the
// register allocation.
//
if (Coloring<LowRegisterPressure>::color(*this)) {
// Write the final colors in the instruction graph.
//
Coloring<LowRegisterPressure>::finalColoring(*this);
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********** RegisterAllocator done **********\n"));
DEBUG_LOG_ONLY(RegisterAllocatorTools::printInstructions(*this));
return;
}
// We need to spill some registers.
//
Spilling<LowRegisterPressure>::insertSpillCode(*this);
// Insert the split instructions.
//
Splits<LowRegisterPressure>::insertSplitCode(*this);
// Update the live ranges.
//
// FIX
}
#ifdef DEBUG_LOG
RegisterAllocatorTools::updateInstructionGraph(*this);
RegisterAllocatorTools::printInstructions(*this);
#endif
fprintf(stderr, "!!! Coloring failed after 10 loops !!!\n");
abort();
}
void RegisterAllocator::initLiveRanges()
{
Uint32 count = this->nameCount;
RegisterName* name2range = new(pool) RegisterName[nameCount];
for (RegisterName r = RegisterName(1); r < count; r = RegisterName(r + 1))
name2range[r] = r;
this->name2range = name2range;
rangeCount = count;
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_ALLOCATOR_H_
#define _REGISTER_ALLOCATOR_H_
class Pool;
class ControlGraph;
class InstructionEmitter;
struct SpillCost;
struct SplitCost;
#include "Liveness.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h" // This should included by Backend.cpp
#include "InterferenceGraph.h"
#include "LiveRangeGraph.h"
//template <class RegisterPressure>
class RegisterAllocator
{
public:
Pool& pool; //
ControlGraph& controlGraph; //
VirtualRegisterManager& vrManager; //
InstructionEmitter& emitter; //
RegisterName* name2range; //
RegisterName* color; //
SpillCost* spillCost; //
SparseSet* willSpill; //
SplitCost* splitCost; //
NameLinkedList** splitAround; //
InterferenceGraph<LowRegisterPressure> iGraph; //
LiveRangeGraph<LowRegisterPressure> lGraph; //
LivenessInfo<LowRegisterPressure> liveness; //
Uint32 nameCount; //
Uint32 rangeCount; //
bool splitFound; //
private:
//
//
void doGraphColoring();
public:
//
//
inline RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
//
//
bool canInterfere(RegisterName /*name1*/, RegisterName /*name2*/) const {return true;}
//
//
void initLiveRanges();
//
//
static void allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
};
//
//
inline RegisterAllocator::RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
: pool(pool), controlGraph(controlGraph), vrManager(vrManager), emitter(emitter), iGraph(*this), lGraph(*this), nameCount(vrManager.getSize()) {}
#endif // _REGISTER_ALLOCATOR_H_

View File

@@ -0,0 +1,355 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "LogModule.h"
#include "RegisterAllocatorTools.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "InstructionEmitter.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "Spilling.h"
#include "Splits.h"
#include "BitSet.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
#ifdef DEBUG
void RegisterAllocatorTools::testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
{
// Test the declared VirtualRegisters. The register allocator tries to condense the register universe.
// Any gap in the VirtualRegister names will be a loss of efficiency !!!!
Uint32 nameCount = vrManager.getSize();
BitSet registerSeen(controlGraph.pool, nameCount);
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
registerSeen.set(usePtr->getRegisterName());
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
registerSeen.set(definePtr->getRegisterName());
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
registerSeen.set(usePtr->getRegisterName());
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
registerSeen.set(definePtr->getRegisterName());
}
}
bool renameRegisters = false;
for (BitSet::iterator i = registerSeen.nextZero(0); !registerSeen.done(i); i = registerSeen.nextZero(i)) {
renameRegisters = true;
fprintf(stderr,
"WARNING: The VirtualRegister vr%d has been allocated during CodeGeneration but\n"
" is never used nor defined by any instruction in the instruction graph\n"
" PLEASE FIX \n",
i);
}
if (renameRegisters) {
Instruction** definingInstruction = new Instruction*[nameCount];
memset(definingInstruction, '\0', nameCount * sizeof(Instruction*));
RegisterName* newName = new RegisterName[nameCount];
memset(newName, '\0', nameCount * sizeof(RegisterName));
RegisterName nextName = RegisterName(1);
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
usePtr->setRegisterName(newName[name]);
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName name = definePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
definePtr->setRegisterName(newName[name]);
}
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
usePtr->setRegisterName(newName[name]);
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName name = definePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
definePtr->setRegisterName(newName[name]);
}
}
}
vrManager.setSize(nextName);
for (RegisterName r = RegisterName(1); r < nextName; r = RegisterName(r + 1))
vrManager.getVirtualRegister(r).definingInstruction = definingInstruction[r];
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("RegisterMap:\n"));
for (Uint32 i = 1; i < nameCount; i++)
if (newName[i] != 0)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d becomes vr%d.\n", i, newName[i]));
else
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d is dead.\n", i));
delete newName;
delete definingInstruction;
}
}
#endif // DEBUG
void RegisterAllocatorTools::removeUnnecessaryCopies(RegisterAllocator& registerAllocator)
{
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i);) {
Instruction& instruction = instructions.get(i);
i = instructions.advance(i);
if (instruction.getFlags() & ifCopy) {
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
RegisterName source = name2range[instruction.getInstructionUseBegin()[0].getRegisterName()];
RegisterName destination = name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()];
if (source == destination)
instruction.remove();
}
}
}
}
void RegisterAllocatorTools::updateInstructionGraph(RegisterAllocator& registerAllocator)
{
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
}
}
}
void RegisterAllocatorTools::insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
if (!phiNodes.empty()) {
// Set the index of the incoming edges.
Uint32 index = 0;
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p))
predecessors.get(p).setIndex(index++);
// Insert the phi node instruction in the instruction list.
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
PhiNode& phiNode = phiNodes.get(i);
ValueKind kind = phiNode.getKind();
if (!isStorableKind(kind))
continue;
RegisterClassKind classKind = rckGeneral; // FIX: get class kind from phi node kind.
Uint32 nInputs = phiNode.nInputs();
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drLow);
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drLow);
node.addPhiNodeInstruction(phiNodeInstruction);
if (isDoublewordKind(kind)) {
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drHigh);
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drHigh);
node.addPhiNodeInstruction(phiNodeInstruction);
}
}
}
}
}
#ifdef DEBUG_LOG
void RegisterAllocatorTools::printSpillCosts(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
Uint32 rangeCount = registerAllocator.rangeCount;
SpillCost* cost = registerAllocator.spillCost;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Spill costs:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : ", i));
if (cost[i].infinite)
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("infinite\n"));
else
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%f\n", cost[i].cost));
}
}
void RegisterAllocatorTools::printSplitCosts(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
Uint32 rangeCount = registerAllocator.rangeCount;
SplitCost* cost = registerAllocator.splitCost;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Split costs:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : loads = %f stores = %f\n", i, cost[i].loads, cost[i].stores));
}
}
void RegisterAllocatorTools::printInstructions(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
ControlNode** nodes = registerAllocator.controlGraph.dfsList;
Uint32 nNodes = registerAllocator.controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d:\n", n));
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
InstructionList& instructions = nodes[n]->getInstructions();
if (!phiNodes.empty()) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" PhiNodes:\n", n));
for(InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
phiNodes.get(i).printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
if (!instructions.empty())
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" Instructions:\n", n));
}
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
instructions.get(i).printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,117 @@
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
//
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
// NETSCAPE COMMUNICATIONS CORPORATION
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
// Reserved. Use of this Source Code is subject to the terms of the
// applicable license agreement from Netscape Communications Corporation.
// The copyright notice(s) in this Source Code does not indicate actual or
// intended publication of this Source Code.
//
// $Id: RegisterAllocatorTools.h,v 1.1.2.1 1999-03-02 16:12:05 fur%netscape.com Exp $
//
#ifndef _REGISTER_ALLOCATOR_TOOLS_H_
#define _REGISTER_ALLOCATOR_TOOLS_H_
#include "LogModule.h"
#include "RegisterTypes.h"
#include <string.h>
class RegisterAllocator;
class ControlGraph;
class InstructionEmitter;
class VirtualRegisterManager;
struct RegisterAllocatorTools
{
//
//
static void insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter);
//
//
static void updateInstructionGraph(RegisterAllocator& registerAllocator);
//
//
static void removeUnnecessaryCopies(RegisterAllocator& registerAllocator);
#ifdef DEBUG
//
//
static void testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
#endif // DEBUG
#ifdef DEBUG_LOG
//
//
static void printInstructions(RegisterAllocator& registerAllocator);
//
//
static void printSpillCosts(RegisterAllocator& registerAllocator);
//
//
static void printSplitCosts(RegisterAllocator& registerAllocator);
#endif // DEBUG_LOG
};
//
// FIX: this should go in a class (LookupTable ?)
//
inline RegisterName findRoot(RegisterName name, RegisterName* table)
{
RegisterName* stack = table;
RegisterName* stackPtr = stack;
RegisterName newName;
while((newName = table[name]) != name) {
*--stackPtr = name;
name = newName;
}
while (stackPtr != stack)
table[*stackPtr++] = name;
return name;
}
inline void init(RegisterName* table, Uint32 nameCount)
{
for (RegisterName r = RegisterName(0); r < nameCount; r = RegisterName(r + 1))
table[r] = r;
}
inline Uint32 compress(RegisterName* name2range, RegisterName* table, Uint32 nameCount, Uint32 tableSize)
{
RegisterName* liveRange = new RegisterName[tableSize];
memset(liveRange, '\0', tableSize * sizeof(RegisterName));
// Update the lookup table.
for (RegisterName r = RegisterName(1); r < tableSize; r = RegisterName(r + 1))
findRoot(r, table);
// Count the liveranges.
Uint32 liveRangeCount = 1;
for (RegisterName s = RegisterName(1); s < tableSize; s = RegisterName(s + 1))
if (table[s] == s)
liveRange[s] = RegisterName(liveRangeCount++);
for (RegisterName t = RegisterName(1); t < nameCount; t = RegisterName(t + 1))
name2range[t] = liveRange[table[name2range[t]]];
return liveRangeCount;
}
inline double doLog10(Uint32 power)
{
double log = 1.0;
while (power--)
log *= 10.0;
return log;
}
#endif // _REGISTER_ALLOCATOR_TOOLS_H_

View File

@@ -16,25 +16,23 @@
* Reserved.
*/
#ifndef nsBufferPoolService_h___
#define nsBufferPoolService_h___
#ifndef _REGISTER_ASSIGNER_H_
#define _REGISTER_ASSIGNER_H_
#include "nsIBufferPoolService.h"
#include "Fundamentals.h"
#include "VirtualRegister.h"
class nsBufferPoolService : public nsIBufferPoolService {
public:
NS_DECL_ISUPPORTS
// nsIBufferPoolService methods:
NS_IMETHOD NewBuffer(PRUint32 minSize, PRUint32 maxSize,
nsIByteBuffer* *result);
// nsBufferPoolService methods:
nsBufferPoolService();
virtual ~nsBufferPoolService();
class FastBitMatrix;
class RegisterAssigner
{
protected:
VirtualRegisterManager& vRegManager;
public:
RegisterAssigner(VirtualRegisterManager& vrMan) : vRegManager(vrMan) {}
virtual bool assignRegisters(FastBitMatrix& interferenceMatrix) = 0;
};
#endif // nsBufferPoolService_h___
#endif /* _REGISTER_ASSIGNER_H_ */

View File

@@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
@@ -16,11 +16,10 @@
* Reserved.
*/
#ifndef nsISimpleEnumerator_h__
#define nsISimpleEnumerator_h__
#ifndef _REGISTER_CLASS_H_
#define _REGISTER_CLASS_H_
// This file is needed to pacify the xpidl-generated header files.
#include "nsIEnumerator.h"
#endif // nsISimpleEnumerator_h__
#include "Fundamentals.h"
#include "RegisterTypes.h"
#endif // _REGISTER_CLASS_H_

View File

@@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
@@ -16,28 +16,22 @@
* Reserved.
*/
#ifndef nsAtomTable_h__
#define nsAtomTable_h__
#ifndef _REGISTER_PRESSURE_H_
#define _REGISTER_PRESSURE_H_
#include "nsIAtom.h"
#include "BitSet.h"
#include "HashSet.h"
class AtomImpl : public nsIAtom {
public:
AtomImpl();
virtual ~AtomImpl();
NS_DECL_ISUPPORTS
NS_DECL_NSIATOM
void* operator new(size_t size, const PRUnichar* us, PRInt32 uslen);
void operator delete(void* ptr) {
::operator delete(ptr);
}
// Actually more; 0 terminated. This slot is reserved for the
// terminating zero.
PRUnichar mString[1];
struct LowRegisterPressure
{
typedef BitSet Set;
static const bool setIsOrdered = true;
};
#endif // nsAtomTable_h__
struct HighRegisterPressure
{
typedef HashSet Set;
static const bool setIsOrdered = false;
};
#endif // _REGISTER_PRESSURE_H_

View File

@@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_TYPES_H_
#define _REGISTER_TYPES_H_
#include "Fundamentals.h"
//------------------------------------------------------------------------------
// RegisterName -
//
enum RegisterName {
rnInvalid = 0,
};
//------------------------------------------------------------------------------
// RegisterClassKind -
//
enum RegisterClassKind {
rckInvalid = 0,
rckGeneral,
rckStackSlot,
nRegisterClassKind
};
//------------------------------------------------------------------------------
// RegisterID -
//
enum RegisterID {
invalidID = 0
};
//------------------------------------------------------------------------------
// RegisterKind -
//
enum RegisterKind {
rkCallerSave = 0,
rkCalleeSave,
};
struct NameLinkedList {
RegisterName name;
NameLinkedList* next;
};
#ifdef DEBUG
const registerNameMask = 0x03ffffff;
const coloredRegisterMask = 0x04000000;
const machineRegisterMask = 0x08000000;
const registerClassMask = 0xf0000000;
const registerNameShift = 0;
const coloredRegisterShift = 26;
const machineRegisterShift = 27;
const registerClassShift = 28;
#else // DEBUG
const registerNameMask = 0x0fffffff;
const registerClassMask = 0xf0000000;
const registerNameShift = 0;
const registerClassShift = 28;
#endif // DEBUG
inline RegisterClassKind getClass(RegisterID registerID) {return RegisterClassKind((registerID & registerClassMask) >> registerClassShift);}
inline RegisterName getName(RegisterID registerID) {return RegisterName((registerID & registerNameMask) >> registerNameShift);}
inline void setClass(RegisterID& registerID, RegisterClassKind classKind) {registerID = RegisterID((registerID & ~registerClassMask) | ((classKind << registerClassShift) & registerClassMask));}
inline void setName(RegisterID& registerID, RegisterName name) {assert((name & ~registerNameMask) == 0); registerID = RegisterID((registerID & ~registerNameMask) | ((name << registerNameShift) & registerNameMask));}
inline RegisterID buildRegisterID(RegisterName name, RegisterClassKind classKind) {return RegisterID(((classKind << registerClassShift) & registerClassMask) | ((name << registerNameShift) & registerNameMask));}
#ifdef DEBUG
inline bool isMachineRegister(RegisterID rid) {return (rid & machineRegisterMask) != 0;}
inline void setMachineRegister(RegisterID& rid) {rid = RegisterID(rid | machineRegisterMask);}
inline bool isColoredRegister(RegisterID rid) {return (rid & coloredRegisterMask) != 0;}
inline void setColoredRegister(RegisterID& rid) {rid = RegisterID(rid | coloredRegisterMask);}
#endif // DEBUG
#endif // _REGISTER_TYPES_H_

View File

@@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SSATools.h"
#include "ControlGraph.h"
#include "VirtualRegister.h"
#include "Liveness.h"
void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
{
if (!controlGraph.hasBackEdges)
return;
Liveness liveness(controlGraph.pool);
liveness.buildLivenessAnalysis(controlGraph, vrManager);
}

View File

@@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SSA_TOOLS_H_
#define _SSA_TOOLS_H_
#include "Fundamentals.h"
class ControlGraph;
class VirtualRegisterManager;
extern void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
#endif // _SSA_TOOLS_H_

View File

@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SparseSet.h"
#include "BitSet.h"
#include "Pool.h"
#ifdef DEBUG_LOG
// Print the set.
//
void SparseSet::printPretty(LogModuleObject log)
{
Pool pool;
BitSet set(pool, universeSize);
for (Uint32 i = 0; i < count; i++)
set.set(node[i].element);
set.printPretty(log);
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,168 @@
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
//
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
// NETSCAPE COMMUNICATIONS CORPORATION
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
// Reserved. Use of this Source Code is subject to the terms of the
// applicable license agreement from Netscape Communications Corporation.
// The copyright notice(s) in this Source Code does not indicate actual or
// intended publication of this Source Code.
//
// $Id: SparseSet.h,v 1.1.2.1 1999-03-02 16:12:07 fur%netscape.com Exp $
//
#ifndef _SPARSE_SET_H_
#define _SPARSE_SET_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "LogModule.h"
#include "BitSet.h"
class SparseSet
{
private:
struct Node {
Uint32 element;
Uint32 stackIndex;
};
Node* node;
Uint32 count;
Uint32 universeSize;
private:
// No copy constructor.
SparseSet(const SparseSet&);
// Check if the given set's universe is of the same size than this universe.
void checkUniverseCompatibility(const SparseSet& set) const {assert(set.universeSize == universeSize);}
// Check if pos is valid for this set's universe.
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
public:
SparseSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {node = new(pool) Node[universeSize]; clear();}
// Clear the sparse set.
void clear() {count = 0;}
// Clear the element at index.
inline void clear(Uint32 index);
// Set the element at index.
inline void set(Uint32 index);
// Return true if the element at index is set.
inline bool test(Uint32 index) const;
// Union with the given sparse set.
inline void or(const SparseSet& set);
// Intersection with the given sparse set.
inline void and(const SparseSet& set);
// Difference with the given sparse set.
inline void difference(const SparseSet& set);
// Copy set.
inline SparseSet& operator = (const SparseSet& set);
inline SparseSet& operator = (const BitSet& set);
// Return true if the sparse sets are identical.
friend bool operator == (const SparseSet& set1, const SparseSet& set2);
// Return true if the sparse sets are different.
friend bool operator != (const SparseSet& set1, const SparseSet& set2);
// Logical operators.
SparseSet& operator |= (const SparseSet& set) {or(set); return *this;}
SparseSet& operator &= (const SparseSet& set) {and(set); return *this;}
SparseSet& operator -= (const SparseSet& set) {difference(set); return *this;}
// Iterator to conform with the set API.
typedef Int32 iterator;
// Return the iterator for the first element of this set.
iterator begin() const {return count - 1;}
// Return the next iterator.
iterator advance(iterator pos) const {return --pos;}
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos < 0;}
// Return the element for the given iterator;
Uint32 get(iterator pos) const {return node[pos].element;}
// Return one element of this set.
Uint32 getOne() const {assert(count > 0); return node[0].element;}
// Return the size of this set.
Uint32 getSize() const {return count;}
#ifdef DEBUG_LOG
// Print the set.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
inline void SparseSet::clear(Uint32 element)
{
checkMember(element);
Uint32 count = this->count;
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
if ((stackIndex < count) && (node[stackIndex].element == element)) {
Uint32 stackTop = node[count - 1].element;
node[stackIndex].element = stackTop;
node[stackTop].stackIndex = stackIndex;
this->count = count - 1;
}
}
inline void SparseSet::set(Uint32 element)
{
checkMember(element);
Uint32 count = this->count;
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
if ((stackIndex >= count) || (node[stackIndex].element != element)) {
node[count].element = element;
node[element].stackIndex = count;
this->count = count + 1;
}
}
inline bool SparseSet::test(Uint32 element) const
{
checkMember(element);
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
return ((stackIndex < count) && (node[stackIndex].element == element));
}
inline SparseSet& SparseSet::operator = (const SparseSet& set)
{
checkUniverseCompatibility(set);
Uint32 sourceCount = set.getSize();
Node* node = this->node;
memcpy(node, set.node, sourceCount * sizeof(Node));
for (Uint32 i = 0; i < sourceCount; i++) {
Uint32 element = node[i].element;
node[element].stackIndex = i;
}
count = sourceCount;
return *this;
}
inline SparseSet& SparseSet::operator = (const BitSet& set)
{
// FIX: there's room for optimization here.
assert(universeSize == set.getSize());
clear();
for (Int32 i = set.firstOne(); i != -1; i = set.nextOne(i))
this->set(i);
return *this;
}
#endif // _SPARSE_SET_H_

View File

@@ -0,0 +1,270 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef NEW_LAURENTM_CODE
#define INCLUDE_EMITTER
#include "CpuInfo.h"
#include "Fundamentals.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "Spilling.h"
void Spilling::
insertSpillCode(ControlNode** dfsList, Uint32 nNodes)
{
PRUint32 nVirtualRegisters = vRegManager.count();
FastBitSet currentLive(vRegManager.pool, nVirtualRegisters);
FastBitSet usedInThisInstruction(vRegManager.pool, nVirtualRegisters);
RegisterFifo grNeedLoad(nVirtualRegisters);
RegisterFifo fpNeedLoad(nVirtualRegisters);
for (PRInt32 n = nNodes - 1; n >= 0; n--)
{
PR_ASSERT(grNeedLoad.empty() & fpNeedLoad.empty());
ControlNode& node = *dfsList[n];
currentLive = node.liveAtEnd;
PRUint32 nGeneralAlive = 0;
PRUint32 nFloatingPointAlive = 0;
// Get the number of registers alive at the end of this node.
for (PRInt32 j = currentLive.firstOne(); j != -1; j = currentLive.nextOne(j))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(j);
if (vReg.spillInfo.willSpill)
{
currentLive.clear(j);
}
else
{
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive++;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive++;
break;
default:
break;
}
}
}
// if(node.dfsNum == 8) printf("\n________Begin Node %d________\n", node.dfsNum);
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i))
{
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
InstructionDefine* defPtr;
// if(node.dfsNum == 8) { printf("\n");
// instruction.printPretty(stdout);
// printf("\n"); }
// Handle definitions
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
if (defPtr->isVirtualRegister())
{
VirtualRegister& vReg = defPtr->getVirtualRegister();
currentLive.clear(vReg.getRegisterIndex());
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive--;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive--;
break;
default:
break;
}
}
// Check for deaths
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isVirtualRegister())
{
VirtualRegister& vReg = usePtr->getVirtualRegister();
if (!currentLive.test(vReg.getRegisterIndex()))
// This is the last use of this register.
{
currentLive.set(vReg.getRegisterIndex());
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive++;
while (/*(nGeneralAlive > NUMBER_OF_GREGISTERS) &&*/ !grNeedLoad.empty())
{
PRUint32 toLoad = grNeedLoad.get();
currentLive.clear(toLoad);
nGeneralAlive--;
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
nReg.releaseSelf();
}
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive++;
while (/*(nFloatingPointAlive > NUMBER_OF_FPREGISTERS) &&*/ !fpNeedLoad.empty())
{
PRUint32 toLoad = fpNeedLoad.get();
currentLive.clear(toLoad);
nFloatingPointAlive--;
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
nReg.releaseSelf();
}
break;
default:
break;
}
}
}
// Handle uses
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isVirtualRegister())
{
VirtualRegister& vReg = usePtr->getVirtualRegister();
PRUint32 registerIndex = vReg.getRegisterIndex();
if (vReg.spillInfo.willSpill) {
#if defined(GENERATE_FOR_X86)
if (!instruction.switchUseToSpill((usePtr - useBegin), *vReg.equivalentRegister[vrcStackSlot]))
#endif
{
switch (vReg.getClass())
{
case vrcInteger:
if (!grNeedLoad.test(registerIndex))
{
grNeedLoad.put(registerIndex);
VirtualRegister& alias = vRegManager.newVirtualRegister(vrcInteger);
if (vReg.isPreColored())
alias.preColorRegister(vReg.getPreColor());
/* if (vReg.hasSpecialInterference) {
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
alias.specialInterference = vReg.specialInterference;
alias.hasSpecialInterference = true;
} */
vReg.setAlias(alias);
vReg.retainSelf();
}
break;
case vrcFloatingPoint:
case vrcFixedPoint:
if (!fpNeedLoad.test(registerIndex))
{
fpNeedLoad.put(registerIndex);
VirtualRegister& alias = vRegManager.newVirtualRegister(vReg.getClass());
if (vReg.isPreColored())
alias.preColorRegister(vReg.getPreColor());
/*if (vReg.hasSpecialInterference) {
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
alias.specialInterference = vReg.specialInterference;
alias.hasSpecialInterference = true;
} */
vReg.setAlias(alias);
vReg.retainSelf();
}
break;
default:
break;
}
usePtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
usedInThisInstruction.set(registerIndex);
vReg.spillInfo.lastUsingInstruction = &instruction;
}
currentLive.clear(registerIndex);
} else { // will not spill
currentLive.set(registerIndex);
}
}
// Handle definitions
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
if (defPtr->isVirtualRegister())
{
VirtualRegister& vReg = defPtr->getVirtualRegister();
if (vReg.spillInfo.willSpill)
#if defined(GENERATE_FOR_X86)
if (!instruction.switchDefineToSpill((defPtr - defBegin), *vReg.equivalentRegister[vrcStackSlot]))
#endif
{
if (usedInThisInstruction.test(vReg.getRegisterIndex()))
// this virtualRegister was used in this instruction and is also defined. We need to move
// this virtual register to its alias first and then save it to memory.
{
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
vReg.getAlias(), *vReg.equivalentRegister[vrcStackSlot]);
defPtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
}
else
{
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
vReg, *vReg.equivalentRegister[vrcStackSlot]);
}
}
}
}
while (!grNeedLoad.empty())
{
PRUint32 nl = grNeedLoad.get();
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
nlReg.releaseSelf();
}
while (!fpNeedLoad.empty())
{
PRUint32 nl = fpNeedLoad.get();
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
nlReg.releaseSelf();
}
// if(node.dfsNum == 8) printf("\n________End Node %d________\n", node.dfsNum);
}
}
#endif

View File

@@ -0,0 +1,269 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPILLING_H_
#define _SPILLING_H_
#include "Fundamentals.h"
#include <string.h>
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "SparseSet.h"
template <class RegisterPressure>
class Spilling
{
private:
static void insertStoreAfter(Instruction& instruction, RegisterName name);
static void insertLoadBefore(Instruction& instruction, RegisterName name);
public:
static void calculateSpillCosts(RegisterAllocator& registerAllocator);
static void insertSpillCode(RegisterAllocator& registerAllocator);
};
struct SpillCost
{
double loads;
double stores;
double copies;
double cost;
bool infinite;
};
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertSpillCode(RegisterAllocator& registerAllocator)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
Pool& pool = registerAllocator.pool;
SparseSet currentLive(pool, rangeCount);
SparseSet needLoad(pool, rangeCount);
SparseSet mustSpill(pool, rangeCount);
SparseSet& willSpill = *registerAllocator.willSpill;
ControlGraph& controlGraph = registerAllocator.controlGraph;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
needLoad.clear();
currentLive = liveOut[n];
mustSpill = currentLive;
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i);) {
Instruction& instruction = instructions.get(i);
i = instructions.retreat(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
bool foundLiveDefine = false;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
if (currentLive.test(name2range[definePtr->getRegisterName()])) {
foundLiveDefine = true;
break;
}
} else {
foundLiveDefine = true;
break;
}
if (defineBegin != defineEnd && !foundLiveDefine) {
fprintf(stderr, "!!! Removed instruction because it was only defining unused registers !!!\n");
instruction.remove();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName range = name2range[definePtr->getRegisterName()];
#ifdef DEBUG
if (needLoad.test(range))
if (!mustSpill.test(range) && registerAllocator.spillCost[range].infinite && willSpill.test(range)) {
fprintf(stderr, "Tried to spill a register with infinite spill cost\n");
abort();
}
#endif // DEBUG
if (willSpill.test(range))
insertStoreAfter(instruction, range);
needLoad.clear(range);
}
if (instruction.getFlags() & ifCopy)
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
if (!currentLive.test(range))
for (SparseSet::iterator r = needLoad.begin(); !needLoad.done(r); r = needLoad.advance(r)) {
RegisterName load = RegisterName(needLoad.get(r));
if (willSpill.test(load))
insertLoadBefore(instruction, load);
mustSpill.set(load);
}
needLoad.clear();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
currentLive.set(range);
needLoad.set(range);
}
}
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
RegisterName load = RegisterName(needLoad.get(l));
if (willSpill.test(load))
insertLoadBefore(instructions.first(), load);
}
}
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertLoadBefore(Instruction& /*instruction*/, RegisterName name)
{
fprintf(stdout, "will insert load for range %d\n", name);
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertStoreAfter(Instruction& /*instruction*/, RegisterName name)
{
fprintf(stdout, "will insert store for range %d\n", name);
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::calculateSpillCosts(RegisterAllocator& registerAllocator)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
Pool& pool = registerAllocator.pool;
SparseSet live(pool, rangeCount);
SparseSet needLoad(pool, rangeCount);
SparseSet mustSpill(pool, rangeCount);
SparseSet alreadyStored(pool, rangeCount); // FIX: should get this from previous spilling.
SpillCost* cost = new SpillCost[rangeCount];
memset(cost, '\0', rangeCount * sizeof(SpillCost));
ControlGraph& controlGraph = registerAllocator.controlGraph;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
double weight = doLog10(node.loopDepth);
needLoad.clear();
live = liveOut[n];
mustSpill = live;
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName range = name2range[definePtr->getRegisterName()];
if (needLoad.test(range))
if (!mustSpill.test(range))
cost[range].infinite = true;
if ((false /* !rematerializable(range) */ || !needLoad.test(range)) && !alreadyStored.test(range))
cost[range].stores += weight;
needLoad.clear(range);
}
if (instruction.getFlags() & ifCopy)
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
if (!live.test(name2range[usePtr->getRegisterName()])) {
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
Uint32 range = needLoad.get(l);
cost[range].loads += weight;
mustSpill.set(range);
}
needLoad.clear();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
live.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
live.set(range);
needLoad.set(range);
}
if (instruction.getFlags() & ifCopy) {
assert(useBegin != useEnd && useBegin[0].isRegister());
assert(defineBegin != defineEnd && defineBegin[0].isRegister());
RegisterName source = name2range[useBegin[0].getRegisterName()];
RegisterName destination = name2range[defineBegin[0].getRegisterName()];
cost[source].copies += weight;
cost[destination].copies += weight;
}
}
for (SparseSet::iterator s = needLoad.begin(); !needLoad.done(s); s = needLoad.advance(s))
cost[needLoad.get(s)].loads += weight;
}
for (Uint32 r = 0; r < rangeCount; r++) {
SpillCost& c = cost[r];
c.cost = 2 * (c.loads + c.stores) - c.copies;
}
registerAllocator.spillCost = cost;
}
#endif // _SPILLING_H_

View File

@@ -0,0 +1,239 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPLITS_H_
#define _SPLITS_H_
#include "Fundamentals.h"
#include <string.h>
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
template <class RegisterPressure>
struct Splits
{
static void calculateSplitCosts(RegisterAllocator& registerAllocator);
static bool findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range);
static void insertSplitCode(RegisterAllocator& registerAllocator);
};
struct SplitCost
{
double loads;
double stores;
};
template <class RegisterPressure>
void Splits<RegisterPressure>::insertSplitCode(RegisterAllocator& /*registerAllocator*/)
{
// FIX
}
template <class RegisterPressure>
bool Splits<RegisterPressure>::findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range)
{
Pool& pool = registerAllocator.pool;
NameLinkedList** neighborsWithColor = new(pool) NameLinkedList*[6]; // FIX
memset(neighborsWithColor, '\0', 6 * sizeof(NameLinkedList*));
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = vector->count - 1; i >=0; --i) {
RegisterName neighbor = vector->neighbors[i];
RegisterName c = color[neighbor];
if (c < 6) { // FIX
NameLinkedList* node = new(pool) NameLinkedList();
node->name = neighbor;
node->next = neighborsWithColor[c];
neighborsWithColor[c] = node;
}
}
bool splitAroundName = true;
LiveRangeGraph<RegisterPressure>& lGraph = registerAllocator.lGraph;
RegisterName bestColor = RegisterName(6); // FIX
double bestCost = registerAllocator.spillCost[range].cost;
SplitCost* splitCost = registerAllocator.splitCost;
for (RegisterName i = RegisterName(0); i < 6; i = RegisterName(i + 1)) { // FIX
double splitAroundNameCost = 0.0;
bool canSplitAroundName = true;
SplitCost& sCost = splitCost[range];
double addedCost = 2.0 * (sCost.stores + sCost.loads);
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
RegisterName neighbor = node->name;
if (lGraph.haveEdge(neighbor, range)) {
canSplitAroundName = false;
break;
} else
splitAroundNameCost += addedCost;
}
if (canSplitAroundName && splitAroundNameCost < bestCost) {
bestCost = splitAroundNameCost;
bestColor = i;
splitAroundName = true;
}
double splitAroundColorCost = 0.0;
bool canSplitAroundColor = true;
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
RegisterName neighbor = node->name;
if (lGraph.haveEdge(range, neighbor)) {
canSplitAroundColor = false;
break;
} else {
SplitCost& sCost = splitCost[neighbor];
double addedCost = 2.0 * (sCost.stores + sCost.loads);
splitAroundColorCost += addedCost;
}
}
if (canSplitAroundColor && splitAroundColorCost < bestCost) {
bestCost = splitAroundColorCost;
bestColor = i;
splitAroundName = false;
}
}
if (bestColor < RegisterName(6)) {
color[range] = bestColor;
registerAllocator.splitFound = true;
NameLinkedList** splitAround = registerAllocator.splitAround;
if (splitAroundName)
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
NameLinkedList* newNode = new(pool) NameLinkedList();
newNode->name = node->name;
newNode->next = splitAround[range];
splitAround[range] = newNode;
}
else
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
NameLinkedList* newNode = new(pool) NameLinkedList();
RegisterName neighbor = node->name;
newNode->name = range;
newNode->next = splitAround[neighbor];
splitAround[neighbor] = newNode;
}
trespass("Found a split");
return true;
}
return false;
}
template <class RegisterPressure>
void Splits<RegisterPressure>::calculateSplitCosts(RegisterAllocator& registerAllocator)
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
SplitCost* splitCost = new(pool) SplitCost[rangeCount];
memset(splitCost, '\0', rangeCount * sizeof(SplitCost));
SparseSet live(pool, rangeCount);
RegisterPressure::Set* liveIn = registerAllocator.liveness.liveIn;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
double weight = doLog10(node.loopDepth);
live = liveOut[n];
ControlEdge* successorsEnd = node.getSuccessorsEnd();
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++) {
ControlNode& successor = successorsPtr->getTarget();
if (successor.getControlKind() != ckEnd) {
RegisterPressure::Set& successorLiveIn = liveIn[successor.dfsNum];
for (SparseSet::iterator i = live.begin(); !live.done(i); i = live.advance(i)) {
RegisterName name = RegisterName(live.get(i));
if (!successorLiveIn.test(name))
splitCost[name].loads += doLog10(successor.loopDepth);
}
}
}
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
splitCost[name2range[definePtr->getRegisterName()]].stores += weight;
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
if (!live.test(range)) {
if (&instruction != &instructions.last())
splitCost[range].loads += weight;
else {
ControlEdge* successorsEnd = node.getSuccessorsEnd();
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++)
splitCost[range].loads += doLog10(successorsPtr->getTarget().loopDepth);
}
}
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
live.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
live.set(name2range[usePtr->getRegisterName()]);
}
}
NameLinkedList** splitAround = new(pool) NameLinkedList*[rangeCount];
memset(splitAround, '\0', rangeCount * sizeof(NameLinkedList*));
registerAllocator.splitAround = splitAround;
registerAllocator.splitCost = splitCost;
registerAllocator.splitFound = false;
}
#endif // _SPLITS_H_

View File

@@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HashTable.h"
#include "Timer.h"
#include "Pool.h"
static Pool pool; // Pool for the Timer class.
static HashTable<TimerEntry*> timerEntries(pool); // Timers hashtable.
const nTimersInABlock = 128; // Number of timers in a block.
static PRTime *timers = new(pool) PRTime[nTimersInABlock]; // A block of timers.
static Uint8 nextTimer = 0; // nextAvailableTimer.
//
// Calibrate the call to PR_Now().
//
static PRTime calibrate()
{
PRTime t = PR_Now();
PRTime& a = *new(pool) PRTime();
// Call 10 times the PR_Now() function.
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
t = (PR_Now() - t + 9) / 10;
return t;
}
static PRTime adjust = calibrate();
//
// Return the named timer..
//
TimerEntry& Timer::getTimerEntry(const char* name)
{
if (!timerEntries.exists(name)) {
TimerEntry* newEntry = new(pool) TimerEntry();
newEntry->accumulator = 0;
newEntry->running = false;
timerEntries.add(name, newEntry);
}
return *timerEntries[name];
}
//
// Return a reference to a new timer.
//
PRTime& Timer::getNewTimer()
{
if (nextTimer >= nTimersInABlock) {
timers = new(pool) PRTime[nTimersInABlock];
nextTimer = 0;
}
return timers[nextTimer++];
}
static Uint32 timersAreFrozen = 0;
//
// Start the named timer.
//
void Timer::start(const char* name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(!timer.running);
timer.accumulator = 0;
timer.running = true;
timer.done = false;
unfreezeTimers();
}
//
// Stop the named timer.
//
void Timer::stop(const char* name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(timer.running);
timer.running = false;
timer.done = true;
unfreezeTimers();
}
//
// Freeze all the running timers.
//
void Timer::freezeTimers()
{
PRTime when = PR_Now() - adjust;
if (timersAreFrozen == 0) {
Vector<TimerEntry*> entries = timerEntries;
Uint32 count = entries.size();
for (Uint32 i = 0; i < count; i++) {
TimerEntry& entry = *entries[i];
if (entry.running) {
entry.accumulator += (when - *entry.startTime);
}
}
}
timersAreFrozen++;
}
//
// Unfreeze all the running timers.
//
void Timer::unfreezeTimers()
{
PR_ASSERT(timersAreFrozen != 0);
timersAreFrozen--;
if (timersAreFrozen == 0) {
Vector<TimerEntry *> entries = timerEntries;
Uint32 count = entries.size();
PRTime& newStart = getNewTimer();
for (Uint32 i = 0; i < count; i++) {
TimerEntry& entry = *entries[i];
if (entry.running) {
entry.startTime = &newStart;
}
}
newStart = PR_Now();
}
}
//
// Print the named timer in the file f.
//
void Timer::print(FILE* f, const char *name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(timer.done);
PRTime elapsed = timer.accumulator;
if (elapsed >> 32) {
fprintf(f, "[timer %s out of range]\n", name);
} else {
fprintf(f, "[%dus in %s]\n", Uint32(elapsed), name);
}
fflush(f);
unfreezeTimers();
}

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _TIMER_H_
#define _TIMER_H_
#include "Fundamentals.h"
#include "HashTable.h"
#include "prtime.h"
//
// Naming convention:
// As the class Timer contains only static methods, the timer's name should start with the
// module name. Otherwise starting 2 timers with the same name will assert.
//
#ifndef NO_TIMER
struct TimerEntry
{
PRTime *startTime; // Current time when we start the timer.
PRTime accumulator; // Time spent in this timer.
bool running; // True if the timer is running.
bool done; // True if the timer was running and was stopped.
};
class Timer
{
private:
// Return the named timer.
static TimerEntry& getTimerEntry(const char* name);
// Return a reference to a new Timer.
static PRTime& getNewTimer();
public:
// Start the timer.
static void start(const char* name);
// Stop the timer.
static void stop(const char* name);
// Freeze all the running timers.
static void freezeTimers();
// Unfreeze all the running timers.
static void unfreezeTimers();
// Print the timer.
static void print(FILE* f, const char *name);
};
inline void startTimer(const char* name) {Timer::start(name);}
inline void stopTimer(const char* name) {Timer::stop(name); Timer::print(stdout, name);}
#define START_TIMER_SAFE Timer::freezeTimers();
#define END_TIMER_SAFE Timer::unfreezeTimers();
#define TIMER_SAFE(x) START_TIMER_SAFE x; END_TIMER_SAFE
#else /* NO_TIMER */
inline void startTimer(const char* /*name*/) {}
inline void stopTimer(const char* /*name*/) {}
#define START_TIMER_SAFE
#define END_TIMER_SAFE
#define TIMER_SAFE(x) x;
#endif /* NO_TIMER */
#endif /* _TIMER_H_ */

View File

@@ -1,5 +1,5 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
@@ -16,31 +16,25 @@
* Reserved.
*/
#ifndef nsSupportsArrayEnumerator_h___
#define nsSupportsArrayEnumerator_h___
#include "Fundamentals.h"
#include "VirtualRegister.h"
#include "Instruction.h"
#include "nsIEnumerator.h"
//------------------------------------------------------------------------------
// VirtualRegister -
class nsISupportsArray;
#ifdef MANUAL_TEMPLATES
template class IndexedPool<VirtualRegister>;
#endif
class NS_COM nsSupportsArrayEnumerator : public nsIBidirectionalEnumerator {
public:
NS_DECL_ISUPPORTS
nsSupportsArrayEnumerator(nsISupportsArray* array);
virtual ~nsSupportsArrayEnumerator();
// nsIEnumerator methods:
NS_DECL_NSIENUMERATOR
// nsIBidirectionalEnumerator methods:
NS_DECL_NSIBIDIRECTIONALENUMERATOR
protected:
nsISupportsArray* mArray;
PRInt32 mCursor;
};
#endif // __nsSupportsArrayEnumerator_h
// Set the defining instruction.
//
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
{
if (definingInstruction != NULL) {
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
return;
}
definingInstruction = &instruction;
}

View File

@@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _VIRTUAL_REGISTER_H_
#define _VIRTUAL_REGISTER_H_
#include "Fundamentals.h"
#include "IndexedPool.h"
#include <string.h>
#include "RegisterTypes.h"
#include "RegisterClass.h"
//------------------------------------------------------------------------------
// VirtualRegister - 24b
class Instruction;
class VirtualRegister : public IndexedObject<VirtualRegister>
{
public:
Instruction* definingInstruction; // Instruction defining this VR.
// Initialize a VR of the given classKind.
VirtualRegister(RegisterClassKind /*classKind*/) : definingInstruction(NULL) {}
// Return the defining instruction for this VR.
Instruction* getDefiningInstruction() const {return definingInstruction;}
// Set the defining instruction.
void setDefiningInstruction(Instruction& insn);
};
// Return true if the VirtualRegisters are equals. The only way 2 VRs can be equal is if
// they have the same index. If they have the same index then they are at the same
// address in the indexed pool.
//
inline bool operator == (const VirtualRegister& regA, const VirtualRegister& regB) {return &regA == &regB;}
//------------------------------------------------------------------------------
// VirtualRegisterManager -
struct PreColoredRegister
{
RegisterID id;
RegisterName color;
};
class VirtualRegisterManager
{
private:
IndexedPool<VirtualRegister> registerPool;
PreColoredRegister machineRegister[6];
public:
VirtualRegisterManager()
{
for (Uint32 i = 0; i < 6; i++)
machineRegister[i].id = invalidID;
}
// Return the VirtualRegister at the given index.
VirtualRegister& getVirtualRegister(RegisterName name) const {return registerPool.get(name);}
// Return a new VirtualRegister.
RegisterID newVirtualRegister(RegisterClassKind classKind)
{
VirtualRegister& vReg = *new(registerPool) VirtualRegister(classKind);
RegisterID rid;
setName(rid, RegisterName(vReg.getIndex()));
setClass(rid, classKind);
return rid;
}
RegisterID newMachineRegister(RegisterName name, RegisterClassKind classKind)
{
RegisterID rid = machineRegister[name].id;
if (rid == invalidID) {
rid = newVirtualRegister(classKind);
DEBUG_ONLY(setMachineRegister(rid));
machineRegister[name].id = rid;
machineRegister[name].color = name;
}
return rid;
}
PreColoredRegister* getMachineRegistersBegin() const {return (PreColoredRegister*) machineRegister;} // FIX
PreColoredRegister* getMachineRegistersEnd() const {return (PreColoredRegister*) &machineRegister[6];} // FIX
// Return the VirtualRegister universe size.
Uint32 getSize() {return registerPool.getSize();}
void setSize(Uint32 size) {registerPool.setSize(size);}
};
#endif // _VIRTUAL_REGISTER_H_

View File

@@ -1,617 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsAVLTree.h"
enum eLean {eLeft,eNeutral,eRight};
struct NS_COM nsAVLNode {
public:
nsAVLNode(void* aValue) {
mLeft=0;
mRight=0;
mSkew=eNeutral;
mValue=aValue;
}
nsAVLNode* mLeft;
nsAVLNode* mRight;
eLean mSkew;
void* mValue;
};
/************************************************************
Now begin the tree class. Don't forget that the comparison
between nodes must occur via the comparitor function,
otherwise all you're testing is pointer addresses.
************************************************************/
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
nsAVLTree::nsAVLTree(nsAVLNodeComparitor& aComparitor,
nsAVLNodeFunctor* aDeallocator) :
mComparitor(aComparitor), mDeallocator(aDeallocator) {
mRoot=0;
mCount=0;
}
static void
avlDeleteTree(nsAVLNode* aNode){
if (aNode) {
avlDeleteTree(aNode->mLeft);
avlDeleteTree(aNode->mRight);
delete aNode;
}
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
nsAVLTree::~nsAVLTree(){
if (mDeallocator) {
ForEachDepthFirst(*mDeallocator);
}
avlDeleteTree(mRoot);
}
class CDoesntExist: public nsAVLNodeFunctor {
public:
CDoesntExist(const nsAVLTree& anotherTree) : mOtherTree(anotherTree) {
}
virtual void* operator()(void* anItem) {
void* result=mOtherTree.FindItem(anItem);
if(result)
return nsnull;
return anItem;
}
protected:
const nsAVLTree& mOtherTree;
};
/**
* This method compares two trees (members by identity).
* @update gess12/27/98
* @param tree to compare against
* @return true if they are identical (contain same stuff).
*/
PRBool nsAVLTree::operator==(const nsAVLTree& aCopy) const{
CDoesntExist functor(aCopy);
void* theItem=FirstThat(functor);
PRBool result=PRBool(!theItem);
return result;
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
static void
avlRotateRight(nsAVLNode*& aRootNode){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
ptr2=aRootNode->mRight;
if(ptr2->mSkew==eRight) {
aRootNode->mRight=ptr2->mLeft;
ptr2->mLeft=aRootNode;
aRootNode->mSkew=eNeutral;
aRootNode=ptr2;
}
else {
ptr3=ptr2->mLeft;
ptr2->mLeft=ptr3->mRight;
ptr3->mRight=ptr2;
aRootNode->mRight=ptr3->mLeft;
ptr3->mLeft=aRootNode;
if(ptr3->mSkew==eLeft)
ptr2->mSkew=eRight;
else ptr2->mSkew=eNeutral;
if(ptr3->mSkew==eRight)
aRootNode->mSkew=eLeft;
else aRootNode->mSkew=eNeutral;
aRootNode=ptr3;
}
aRootNode->mSkew=eNeutral;
return;
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
static void
avlRotateLeft(nsAVLNode*& aRootNode){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
ptr2=aRootNode->mLeft;
if(ptr2->mSkew==eLeft) {
aRootNode->mLeft=ptr2->mRight;
ptr2->mRight=aRootNode;
aRootNode->mSkew=eNeutral;
aRootNode=ptr2;
}
else {
ptr3=ptr2->mRight;
ptr2->mRight=ptr3->mLeft;
ptr3->mLeft=ptr2;
aRootNode->mLeft=ptr3->mRight;
ptr3->mRight=aRootNode;
if(ptr3->mSkew==eRight)
ptr2->mSkew=eLeft;
else ptr2->mSkew=eNeutral;
if(ptr3->mSkew==eLeft)
aRootNode->mSkew=eRight;
else aRootNode->mSkew=eNeutral;
aRootNode=ptr3;
}
aRootNode->mSkew=eNeutral;
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlInsert(nsAVLNode*& aRootNode, nsAVLNode* aNewNode,
nsAVLNodeComparitor& aComparitor) {
eAVLStatus result=eAVL_unknown;
if(!aRootNode) {
aRootNode = aNewNode;
return eAVL_ok;
}
if(aNewNode==aRootNode->mValue) {
return eAVL_duplicate;
}
PRInt32 theCompareResult=aComparitor(aRootNode->mValue,aNewNode->mValue);
if(0 < theCompareResult) { //if(anItem<aRootNode->mValue)
result=avlInsert(aRootNode->mLeft,aNewNode,aComparitor);
if(eAVL_ok==result) {
switch(aRootNode->mSkew){
case eLeft:
avlRotateLeft(aRootNode);
result=eAVL_fail;
break;
case eRight:
aRootNode->mSkew=eNeutral;
result=eAVL_fail;
break;
case eNeutral:
aRootNode->mSkew=eLeft;
break;
} //switch
}//if
} //if
else {
result=avlInsert(aRootNode->mRight,aNewNode,aComparitor);
if(eAVL_ok==result) {
switch(aRootNode->mSkew){
case eLeft:
aRootNode->mSkew=eNeutral;
result=eAVL_fail;
break;
case eRight:
avlRotateRight(aRootNode);
result=eAVL_fail;
break;
case eNeutral:
aRootNode->mSkew=eRight;
break;
} //switch
}
} //if
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static void
avlBalanceLeft(nsAVLNode*& aRootNode, PRBool& delOk){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
eLean balnc2;
eLean balnc3;
switch(aRootNode->mSkew){
case eLeft:
ptr2=aRootNode->mLeft;
balnc2=ptr2->mSkew;
if(balnc2!=eRight) {
aRootNode->mLeft=ptr2->mRight;
ptr2->mRight=aRootNode;
if(balnc2==eNeutral){
aRootNode->mSkew=eLeft;
ptr2->mSkew=eRight;
delOk=PR_FALSE;
}
else{
aRootNode->mSkew=eNeutral;
ptr2->mSkew=eNeutral;
}
aRootNode=ptr2;
}
else{
ptr3=ptr2->mRight;
balnc3=ptr3->mSkew;
ptr2->mRight=ptr3->mLeft;
ptr3->mLeft=ptr2;
aRootNode->mLeft=ptr3->mRight;
ptr3->mRight=aRootNode;
if(balnc3==eRight) {
ptr2->mSkew=eLeft;
}
else {
ptr2->mSkew=eNeutral;
}
if(balnc3==eLeft) {
aRootNode->mSkew=eRight;
}
else {
aRootNode->mSkew=eNeutral;
}
aRootNode=ptr3;
ptr3->mSkew=eNeutral;
}
break;
case eRight:
aRootNode->mSkew=eNeutral;
break;
case eNeutral:
aRootNode->mSkew=eLeft;
delOk=PR_FALSE;
break;
}//switch
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static void
avlBalanceRight(nsAVLNode*& aRootNode, PRBool& delOk){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
eLean balnc2;
eLean balnc3;
switch(aRootNode->mSkew){
case eLeft:
aRootNode->mSkew=eNeutral;
break;
case eRight:
ptr2=aRootNode->mRight;
balnc2=ptr2->mSkew;
if(balnc2!=eLeft) {
aRootNode->mRight=ptr2->mLeft;
ptr2->mLeft=aRootNode;
if(balnc2==eNeutral){
aRootNode->mSkew=eRight;
ptr2->mSkew=eLeft;
delOk=PR_FALSE;
}
else{
aRootNode->mSkew=eNeutral;
ptr2->mSkew=eNeutral;
}
aRootNode=ptr2;
}
else{
ptr3=ptr2->mLeft;
balnc3=ptr3->mSkew;
ptr2->mLeft=ptr3->mRight;
ptr3->mRight=ptr2;
aRootNode->mRight=ptr3->mLeft;
ptr3->mLeft=aRootNode;
if(balnc3==eLeft) {
ptr2->mSkew=eRight;
}
else {
ptr2->mSkew=eNeutral;
}
if(balnc3==eRight) {
aRootNode->mSkew=eLeft;
}
else {
aRootNode->mSkew=eNeutral;
}
aRootNode=ptr3;
ptr3->mSkew=eNeutral;
}
break;
case eNeutral:
aRootNode->mSkew=eRight;
delOk=PR_FALSE;
break;
}//switch
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlRemoveChildren(nsAVLNode*& aRootNode,nsAVLNode*& anotherNode, PRBool& delOk){
eAVLStatus result=eAVL_ok;
if(!anotherNode->mRight){
aRootNode->mValue=anotherNode->mValue; //swap
anotherNode=anotherNode->mLeft;
delOk=PR_TRUE;
}
else{
avlRemoveChildren(aRootNode,anotherNode->mRight,delOk);
if(delOk)
avlBalanceLeft(anotherNode,delOk);
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlRemove(nsAVLNode*& aRootNode, void* anItem, PRBool& delOk,
nsAVLNodeComparitor& aComparitor){
eAVLStatus result=eAVL_ok;
if(!aRootNode)
delOk=PR_FALSE;
else {
PRInt32 cmp=aComparitor(anItem,aRootNode->mValue);
if(cmp<0){
avlRemove(aRootNode->mLeft,anItem,delOk,aComparitor);
if(delOk)
avlBalanceRight(aRootNode,delOk);
}
else if(cmp>0){
avlRemove(aRootNode->mRight,anItem,delOk,aComparitor);
if(delOk)
avlBalanceLeft(aRootNode,delOk);
}
else{ //they match...
nsAVLNode* temp=aRootNode;
if(!aRootNode->mRight) {
aRootNode=aRootNode->mLeft;
delOk=PR_TRUE;
delete temp;
}
else if(!aRootNode->mLeft) {
aRootNode=aRootNode->mRight;
delOk=PR_TRUE;
delete temp;
}
else {
avlRemoveChildren(aRootNode,aRootNode->mLeft,delOk);
if(delOk)
avlBalanceRight(aRootNode,delOk);
}
}
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
eAVLStatus
nsAVLTree::AddItem(void* anItem){
eAVLStatus result=eAVL_ok;
nsAVLNode* theNewNode=new nsAVLNode(anItem);
result=avlInsert(mRoot,theNewNode,mComparitor);
if(eAVL_duplicate!=result)
mCount++;
else {
delete theNewNode;
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
void* nsAVLTree::FindItem(void* aValue) const{
nsAVLNode* result=mRoot;
PRInt32 count=0;
while(result) {
count++;
PRInt32 cmp=mComparitor(aValue,result->mValue);
if(0==cmp) {
//we matched...
break;
}
else if(0>cmp){
//theNode was greater...
result=result->mLeft;
}
else {
//aValue is greater...
result=result->mRight;
}
}
if(result) {
return result->mValue;
}
return nsnull;
}
/**
*
* @update gess12/30/98
* @param
* @return
*/
eAVLStatus
nsAVLTree::RemoveItem(void* aValue){
PRBool delOk=PR_TRUE;
eAVLStatus result=avlRemove(mRoot,aValue,delOk,mComparitor);
if(eAVL_ok==result)
mCount--;
return result;
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void
avlForEachDepthFirst(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor){
if(aNode) {
avlForEachDepthFirst(aNode->mLeft,aFunctor);
avlForEachDepthFirst(aNode->mRight,aFunctor);
aFunctor(aNode->mValue);
}
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void
nsAVLTree::ForEachDepthFirst(nsAVLNodeFunctor& aFunctor) const{
::avlForEachDepthFirst(mRoot,aFunctor);
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void
avlForEach(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor) {
if(aNode) {
avlForEach(aNode->mLeft,aFunctor);
aFunctor(aNode->mValue);
avlForEach(aNode->mRight,aFunctor);
}
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void
nsAVLTree::ForEach(nsAVLNodeFunctor& aFunctor) const{
::avlForEach(mRoot,aFunctor);
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void*
avlFirstThat(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor) {
void* result=nsnull;
if(aNode) {
result = avlFirstThat(aNode->mLeft,aFunctor);
if (result) {
return result;
}
result = aFunctor(aNode->mValue);
if (result) {
return result;
}
result = avlFirstThat(aNode->mRight,aFunctor);
}
return result;
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void*
nsAVLTree::FirstThat(nsAVLNodeFunctor& aFunctor) const{
return ::avlFirstThat(mRoot,aFunctor);
}

View File

@@ -1,74 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsAVLTree_h___
#define nsAVLTree_h___
#include "nscore.h"
enum eAVLStatus {eAVL_unknown,eAVL_ok,eAVL_fail,eAVL_duplicate};
struct nsAVLNode;
/**
*
* @update gess12/26/98
* @param anObject1 is the first object to be compared
* @param anObject2 is the second object to be compared
* @return -1,0,1 if object1 is less, equal, greater than object2
*/
class NS_COM nsAVLNodeComparitor {
public:
virtual PRInt32 operator()(void* anItem1,void* anItem2)=0;
};
class NS_COM nsAVLNodeFunctor {
public:
virtual void* operator()(void* anItem)=0;
};
class NS_COM nsAVLTree {
public:
nsAVLTree(nsAVLNodeComparitor& aComparitor, nsAVLNodeFunctor* aDeallocator);
~nsAVLTree(void);
PRBool operator==(const nsAVLTree& aOther) const;
PRInt32 GetCount(void) const {return mCount;}
//main functions...
eAVLStatus AddItem(void* anItem);
eAVLStatus RemoveItem(void* anItem);
void* FindItem(void* anItem) const;
void ForEach(nsAVLNodeFunctor& aFunctor) const;
void ForEachDepthFirst(nsAVLNodeFunctor& aFunctor) const;
void* FirstThat(nsAVLNodeFunctor& aFunctor) const;
protected:
nsAVLNode* mRoot;
PRInt32 mCount;
nsAVLNodeComparitor& mComparitor;
nsAVLNodeFunctor* mDeallocator;
};
#endif /* nsAVLTree_h___ */

View File

@@ -1,617 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsAVLTree.h"
enum eLean {eLeft,eNeutral,eRight};
struct NS_COM nsAVLNode {
public:
nsAVLNode(void* aValue) {
mLeft=0;
mRight=0;
mSkew=eNeutral;
mValue=aValue;
}
nsAVLNode* mLeft;
nsAVLNode* mRight;
eLean mSkew;
void* mValue;
};
/************************************************************
Now begin the tree class. Don't forget that the comparison
between nodes must occur via the comparitor function,
otherwise all you're testing is pointer addresses.
************************************************************/
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
nsAVLTree::nsAVLTree(nsAVLNodeComparitor& aComparitor,
nsAVLNodeFunctor* aDeallocator) :
mComparitor(aComparitor), mDeallocator(aDeallocator) {
mRoot=0;
mCount=0;
}
static void
avlDeleteTree(nsAVLNode* aNode){
if (aNode) {
avlDeleteTree(aNode->mLeft);
avlDeleteTree(aNode->mRight);
delete aNode;
}
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
nsAVLTree::~nsAVLTree(){
if (mDeallocator) {
ForEachDepthFirst(*mDeallocator);
}
avlDeleteTree(mRoot);
}
class CDoesntExist: public nsAVLNodeFunctor {
public:
CDoesntExist(const nsAVLTree& anotherTree) : mOtherTree(anotherTree) {
}
virtual void* operator()(void* anItem) {
void* result=mOtherTree.FindItem(anItem);
if(result)
return nsnull;
return anItem;
}
protected:
const nsAVLTree& mOtherTree;
};
/**
* This method compares two trees (members by identity).
* @update gess12/27/98
* @param tree to compare against
* @return true if they are identical (contain same stuff).
*/
PRBool nsAVLTree::operator==(const nsAVLTree& aCopy) const{
CDoesntExist functor(aCopy);
void* theItem=FirstThat(functor);
PRBool result=PRBool(!theItem);
return result;
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
static void
avlRotateRight(nsAVLNode*& aRootNode){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
ptr2=aRootNode->mRight;
if(ptr2->mSkew==eRight) {
aRootNode->mRight=ptr2->mLeft;
ptr2->mLeft=aRootNode;
aRootNode->mSkew=eNeutral;
aRootNode=ptr2;
}
else {
ptr3=ptr2->mLeft;
ptr2->mLeft=ptr3->mRight;
ptr3->mRight=ptr2;
aRootNode->mRight=ptr3->mLeft;
ptr3->mLeft=aRootNode;
if(ptr3->mSkew==eLeft)
ptr2->mSkew=eRight;
else ptr2->mSkew=eNeutral;
if(ptr3->mSkew==eRight)
aRootNode->mSkew=eLeft;
else aRootNode->mSkew=eNeutral;
aRootNode=ptr3;
}
aRootNode->mSkew=eNeutral;
return;
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
static void
avlRotateLeft(nsAVLNode*& aRootNode){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
ptr2=aRootNode->mLeft;
if(ptr2->mSkew==eLeft) {
aRootNode->mLeft=ptr2->mRight;
ptr2->mRight=aRootNode;
aRootNode->mSkew=eNeutral;
aRootNode=ptr2;
}
else {
ptr3=ptr2->mRight;
ptr2->mRight=ptr3->mLeft;
ptr3->mLeft=ptr2;
aRootNode->mLeft=ptr3->mRight;
ptr3->mRight=aRootNode;
if(ptr3->mSkew==eRight)
ptr2->mSkew=eLeft;
else ptr2->mSkew=eNeutral;
if(ptr3->mSkew==eLeft)
aRootNode->mSkew=eRight;
else aRootNode->mSkew=eNeutral;
aRootNode=ptr3;
}
aRootNode->mSkew=eNeutral;
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlInsert(nsAVLNode*& aRootNode, nsAVLNode* aNewNode,
nsAVLNodeComparitor& aComparitor) {
eAVLStatus result=eAVL_unknown;
if(!aRootNode) {
aRootNode = aNewNode;
return eAVL_ok;
}
if(aNewNode==aRootNode->mValue) {
return eAVL_duplicate;
}
PRInt32 theCompareResult=aComparitor(aRootNode->mValue,aNewNode->mValue);
if(0 < theCompareResult) { //if(anItem<aRootNode->mValue)
result=avlInsert(aRootNode->mLeft,aNewNode,aComparitor);
if(eAVL_ok==result) {
switch(aRootNode->mSkew){
case eLeft:
avlRotateLeft(aRootNode);
result=eAVL_fail;
break;
case eRight:
aRootNode->mSkew=eNeutral;
result=eAVL_fail;
break;
case eNeutral:
aRootNode->mSkew=eLeft;
break;
} //switch
}//if
} //if
else {
result=avlInsert(aRootNode->mRight,aNewNode,aComparitor);
if(eAVL_ok==result) {
switch(aRootNode->mSkew){
case eLeft:
aRootNode->mSkew=eNeutral;
result=eAVL_fail;
break;
case eRight:
avlRotateRight(aRootNode);
result=eAVL_fail;
break;
case eNeutral:
aRootNode->mSkew=eRight;
break;
} //switch
}
} //if
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static void
avlBalanceLeft(nsAVLNode*& aRootNode, PRBool& delOk){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
eLean balnc2;
eLean balnc3;
switch(aRootNode->mSkew){
case eLeft:
ptr2=aRootNode->mLeft;
balnc2=ptr2->mSkew;
if(balnc2!=eRight) {
aRootNode->mLeft=ptr2->mRight;
ptr2->mRight=aRootNode;
if(balnc2==eNeutral){
aRootNode->mSkew=eLeft;
ptr2->mSkew=eRight;
delOk=PR_FALSE;
}
else{
aRootNode->mSkew=eNeutral;
ptr2->mSkew=eNeutral;
}
aRootNode=ptr2;
}
else{
ptr3=ptr2->mRight;
balnc3=ptr3->mSkew;
ptr2->mRight=ptr3->mLeft;
ptr3->mLeft=ptr2;
aRootNode->mLeft=ptr3->mRight;
ptr3->mRight=aRootNode;
if(balnc3==eRight) {
ptr2->mSkew=eLeft;
}
else {
ptr2->mSkew=eNeutral;
}
if(balnc3==eLeft) {
aRootNode->mSkew=eRight;
}
else {
aRootNode->mSkew=eNeutral;
}
aRootNode=ptr3;
ptr3->mSkew=eNeutral;
}
break;
case eRight:
aRootNode->mSkew=eNeutral;
break;
case eNeutral:
aRootNode->mSkew=eLeft;
delOk=PR_FALSE;
break;
}//switch
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static void
avlBalanceRight(nsAVLNode*& aRootNode, PRBool& delOk){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
eLean balnc2;
eLean balnc3;
switch(aRootNode->mSkew){
case eLeft:
aRootNode->mSkew=eNeutral;
break;
case eRight:
ptr2=aRootNode->mRight;
balnc2=ptr2->mSkew;
if(balnc2!=eLeft) {
aRootNode->mRight=ptr2->mLeft;
ptr2->mLeft=aRootNode;
if(balnc2==eNeutral){
aRootNode->mSkew=eRight;
ptr2->mSkew=eLeft;
delOk=PR_FALSE;
}
else{
aRootNode->mSkew=eNeutral;
ptr2->mSkew=eNeutral;
}
aRootNode=ptr2;
}
else{
ptr3=ptr2->mLeft;
balnc3=ptr3->mSkew;
ptr2->mLeft=ptr3->mRight;
ptr3->mRight=ptr2;
aRootNode->mRight=ptr3->mLeft;
ptr3->mLeft=aRootNode;
if(balnc3==eLeft) {
ptr2->mSkew=eRight;
}
else {
ptr2->mSkew=eNeutral;
}
if(balnc3==eRight) {
aRootNode->mSkew=eLeft;
}
else {
aRootNode->mSkew=eNeutral;
}
aRootNode=ptr3;
ptr3->mSkew=eNeutral;
}
break;
case eNeutral:
aRootNode->mSkew=eRight;
delOk=PR_FALSE;
break;
}//switch
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlRemoveChildren(nsAVLNode*& aRootNode,nsAVLNode*& anotherNode, PRBool& delOk){
eAVLStatus result=eAVL_ok;
if(!anotherNode->mRight){
aRootNode->mValue=anotherNode->mValue; //swap
anotherNode=anotherNode->mLeft;
delOk=PR_TRUE;
}
else{
avlRemoveChildren(aRootNode,anotherNode->mRight,delOk);
if(delOk)
avlBalanceLeft(anotherNode,delOk);
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlRemove(nsAVLNode*& aRootNode, void* anItem, PRBool& delOk,
nsAVLNodeComparitor& aComparitor){
eAVLStatus result=eAVL_ok;
if(!aRootNode)
delOk=PR_FALSE;
else {
PRInt32 cmp=aComparitor(anItem,aRootNode->mValue);
if(cmp<0){
avlRemove(aRootNode->mLeft,anItem,delOk,aComparitor);
if(delOk)
avlBalanceRight(aRootNode,delOk);
}
else if(cmp>0){
avlRemove(aRootNode->mRight,anItem,delOk,aComparitor);
if(delOk)
avlBalanceLeft(aRootNode,delOk);
}
else{ //they match...
nsAVLNode* temp=aRootNode;
if(!aRootNode->mRight) {
aRootNode=aRootNode->mLeft;
delOk=PR_TRUE;
delete temp;
}
else if(!aRootNode->mLeft) {
aRootNode=aRootNode->mRight;
delOk=PR_TRUE;
delete temp;
}
else {
avlRemoveChildren(aRootNode,aRootNode->mLeft,delOk);
if(delOk)
avlBalanceRight(aRootNode,delOk);
}
}
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
eAVLStatus
nsAVLTree::AddItem(void* anItem){
eAVLStatus result=eAVL_ok;
nsAVLNode* theNewNode=new nsAVLNode(anItem);
result=avlInsert(mRoot,theNewNode,mComparitor);
if(eAVL_duplicate!=result)
mCount++;
else {
delete theNewNode;
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
void* nsAVLTree::FindItem(void* aValue) const{
nsAVLNode* result=mRoot;
PRInt32 count=0;
while(result) {
count++;
PRInt32 cmp=mComparitor(aValue,result->mValue);
if(0==cmp) {
//we matched...
break;
}
else if(0>cmp){
//theNode was greater...
result=result->mLeft;
}
else {
//aValue is greater...
result=result->mRight;
}
}
if(result) {
return result->mValue;
}
return nsnull;
}
/**
*
* @update gess12/30/98
* @param
* @return
*/
eAVLStatus
nsAVLTree::RemoveItem(void* aValue){
PRBool delOk=PR_TRUE;
eAVLStatus result=avlRemove(mRoot,aValue,delOk,mComparitor);
if(eAVL_ok==result)
mCount--;
return result;
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void
avlForEachDepthFirst(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor){
if(aNode) {
avlForEachDepthFirst(aNode->mLeft,aFunctor);
avlForEachDepthFirst(aNode->mRight,aFunctor);
aFunctor(aNode->mValue);
}
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void
nsAVLTree::ForEachDepthFirst(nsAVLNodeFunctor& aFunctor) const{
::avlForEachDepthFirst(mRoot,aFunctor);
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void
avlForEach(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor) {
if(aNode) {
avlForEach(aNode->mLeft,aFunctor);
aFunctor(aNode->mValue);
avlForEach(aNode->mRight,aFunctor);
}
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void
nsAVLTree::ForEach(nsAVLNodeFunctor& aFunctor) const{
::avlForEach(mRoot,aFunctor);
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void*
avlFirstThat(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor) {
void* result=nsnull;
if(aNode) {
result = avlFirstThat(aNode->mLeft,aFunctor);
if (result) {
return result;
}
result = aFunctor(aNode->mValue);
if (result) {
return result;
}
result = avlFirstThat(aNode->mRight,aFunctor);
}
return result;
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void*
nsAVLTree::FirstThat(nsAVLNodeFunctor& aFunctor) const{
return ::avlFirstThat(mRoot,aFunctor);
}

View File

@@ -1,74 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsAVLTree_h___
#define nsAVLTree_h___
#include "nscore.h"
enum eAVLStatus {eAVL_unknown,eAVL_ok,eAVL_fail,eAVL_duplicate};
struct nsAVLNode;
/**
*
* @update gess12/26/98
* @param anObject1 is the first object to be compared
* @param anObject2 is the second object to be compared
* @return -1,0,1 if object1 is less, equal, greater than object2
*/
class NS_COM nsAVLNodeComparitor {
public:
virtual PRInt32 operator()(void* anItem1,void* anItem2)=0;
};
class NS_COM nsAVLNodeFunctor {
public:
virtual void* operator()(void* anItem)=0;
};
class NS_COM nsAVLTree {
public:
nsAVLTree(nsAVLNodeComparitor& aComparitor, nsAVLNodeFunctor* aDeallocator);
~nsAVLTree(void);
PRBool operator==(const nsAVLTree& aOther) const;
PRInt32 GetCount(void) const {return mCount;}
//main functions...
eAVLStatus AddItem(void* anItem);
eAVLStatus RemoveItem(void* anItem);
void* FindItem(void* anItem) const;
void ForEach(nsAVLNodeFunctor& aFunctor) const;
void ForEachDepthFirst(nsAVLNodeFunctor& aFunctor) const;
void* FirstThat(nsAVLNodeFunctor& aFunctor) const;
protected:
nsAVLNode* mRoot;
PRInt32 mCount;
nsAVLNodeComparitor& mComparitor;
nsAVLNodeFunctor* mDeallocator;
};
#endif /* nsAVLTree_h___ */

View File

@@ -1,717 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/******************************************************************************************
MODULE NOTES:
This file contains the nsStr data structure.
This general purpose buffer management class is used as the basis for our strings.
It's benefits include:
1. An efficient set of library style functions for manipulating nsStrs
2. Support for 1 and 2 byte character strings (which can easily be increased to n)
3. Unicode awareness and interoperability.
*******************************************************************************************/
#include "nsStr.h"
#include "bufferRoutines.h"
#include "stdio.h" //only used for printf
#include "nsCRT.h"
#include "nsDeque.h"
//static const char* kCallFindChar = "For better performance, call FindChar() for targets whose length==1.";
//static const char* kCallRFindChar = "For better performance, call RFindChar() for targets whose length==1.";
static const PRUnichar gCommonEmptyBuffer[1] = {0};
/**
* This method initializes all the members of the nsStr structure
*
* @update gess10/30/98
* @param
* @return
*/
void nsStr::Initialize(nsStr& aDest,eCharSize aCharSize) {
aDest.mStr=(char*)gCommonEmptyBuffer;
aDest.mLength=0;
aDest.mCapacity=0;
aDest.mCharSize=aCharSize;
aDest.mOwnsBuffer=0;
}
/**
* This method initializes all the members of the nsStr structure
* @update gess10/30/98
* @param
* @return
*/
void nsStr::Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer){
aDest.mStr=(aCString) ? aCString : (char*)gCommonEmptyBuffer;
aDest.mLength=aLength;
aDest.mCapacity=aCapacity;
aDest.mCharSize=aCharSize;
aDest.mOwnsBuffer=aOwnsBuffer;
}
/**
* This member destroys the memory buffer owned by an nsStr object (if it actually owns it)
* @update gess10/30/98
* @param
* @return
*/
void nsStr::Destroy(nsStr& aDest) {
if((aDest.mStr) && (aDest.mStr!=(char*)gCommonEmptyBuffer)) {
Free(aDest);
}
}
/**
* This method gets called when the internal buffer needs
* to grow to a given size. The original contents are not preserved.
* @update gess 3/30/98
* @param aNewLength -- new capacity of string in charSize units
* @return void
*/
PRBool nsStr::EnsureCapacity(nsStr& aString,PRUint32 aNewLength) {
PRBool result=PR_TRUE;
if(aNewLength>aString.mCapacity) {
result=Realloc(aString,aNewLength);
if(aString.mStr)
AddNullTerminator(aString);
}
return result;
}
/**
* This method gets called when the internal buffer needs
* to grow to a given size. The original contents ARE preserved.
* @update gess 3/30/98
* @param aNewLength -- new capacity of string in charSize units
* @return void
*/
PRBool nsStr::GrowCapacity(nsStr& aDest,PRUint32 aNewLength) {
PRBool result=PR_TRUE;
if(aNewLength>aDest.mCapacity) {
nsStr theTempStr;
nsStr::Initialize(theTempStr,aDest.mCharSize);
result=EnsureCapacity(theTempStr,aNewLength);
if(result) {
if(aDest.mLength) {
Append(theTempStr,aDest,0,aDest.mLength);
}
Free(aDest);
aDest.mStr = theTempStr.mStr;
theTempStr.mStr=0; //make sure to null this out so that you don't lose the buffer you just stole...
aDest.mLength=theTempStr.mLength;
aDest.mCapacity=theTempStr.mCapacity;
aDest.mOwnsBuffer=theTempStr.mOwnsBuffer;
}
}
return result;
}
/**
* Replaces the contents of aDest with aSource, up to aCount of chars.
* @update gess10/30/98
* @param aDest is the nsStr that gets changed.
* @param aSource is where chars are copied from
* @param aCount is the number of chars copied from aSource
*/
void nsStr::Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount){
if(&aDest!=&aSource){
Truncate(aDest,0);
Append(aDest,aSource,anOffset,aCount);
}
}
/**
* This method appends the given nsStr to this one. Note that we have to
* pay attention to the underlying char-size of both structs.
* @update gess10/30/98
* @param aDest is the nsStr to be manipulated
* @param aSource is where char are copied from
* @aCount is the number of bytes to be copied
*/
void nsStr::Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount){
if(anOffset<aSource.mLength){
PRUint32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRUint32 theLength=(anOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-anOffset);
if(0<theLength){
PRBool isBigEnough=PR_TRUE;
if(aDest.mLength+theLength > aDest.mCapacity) {
isBigEnough=GrowCapacity(aDest,aDest.mLength+theLength);
}
if(isBigEnough) {
//now append new chars, starting at offset
(*gCopyChars[aSource.mCharSize][aDest.mCharSize])(aDest.mStr,aDest.mLength,aSource.mStr,anOffset,theLength);
aDest.mLength+=theLength;
AddNullTerminator(aDest);
}
}
}
}
/**
* This method inserts up to "aCount" chars from a source nsStr into a dest nsStr.
* @update gess10/30/98
* @param aDest is the nsStr that gets changed
* @param aDestOffset is where in aDest the insertion is to occur
* @param aSource is where chars are copied from
* @param aSrcOffset is where in aSource chars are copied from
* @param aCount is the number of chars from aSource to be inserted into aDest
*/
void nsStr::Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUint32 aSrcOffset,PRInt32 aCount){
//there are a few cases for insert:
// 1. You're inserting chars into an empty string (assign)
// 2. You're inserting onto the end of a string (append)
// 3. You're inserting onto the 1..n-1 pos of a string (the hard case).
if(0<aSource.mLength){
if(aDest.mLength){
if(aDestOffset<aDest.mLength){
PRInt32 theRealLen=(aCount<0) ? aSource.mLength : MinInt(aCount,aSource.mLength);
PRInt32 theLength=(aSrcOffset+theRealLen<aSource.mLength) ? theRealLen : (aSource.mLength-aSrcOffset);
if(aSrcOffset<aSource.mLength) {
//here's the only new case we have to handle.
//chars are really being inserted into our buffer...
if(aDest.mLength+theLength > aDest.mCapacity) {
nsStr theTempStr;
nsStr::Initialize(theTempStr,aDest.mCharSize);
PRBool isBigEnough=EnsureCapacity(theTempStr,aDest.mLength+theLength); //grow the temp buffer to the right size
if(isBigEnough) {
if(aDestOffset) {
Append(theTempStr,aDest,0,aDestOffset); //first copy leftmost data...
}
Append(theTempStr,aSource,0,aSource.mLength); //next copy inserted (new) data
PRUint32 theRemains=aDest.mLength-aDestOffset;
if(theRemains) {
Append(theTempStr,aDest,aDestOffset,theRemains); //next copy rightmost data
}
Free(aDest);
aDest.mStr = theTempStr.mStr;
theTempStr.mStr=0; //make sure to null this out so that you don't lose the buffer you just stole...
aDest.mCapacity=theTempStr.mCapacity;
aDest.mOwnsBuffer=theTempStr.mOwnsBuffer;
}
}
else {
//shift the chars right by theDelta...
(*gShiftChars[aDest.mCharSize][KSHIFTRIGHT])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
//now insert new chars, starting at offset
(*gCopyChars[aSource.mCharSize][aDest.mCharSize])(aDest.mStr,aDestOffset,aSource.mStr,aSrcOffset,theLength);
}
//finally, make sure to update the string length...
aDest.mLength+=theLength;
AddNullTerminator(aDest);
}//if
//else nothing to do!
}
else Append(aDest,aSource,0,aCount);
}
else Append(aDest,aSource,0,aCount);
}
}
/**
* This method deletes up to aCount chars from aDest
* @update gess10/30/98
* @param aDest is the nsStr to be manipulated
* @param aDestOffset is where in aDest deletion is to occur
* @param aCount is the number of chars to be deleted in aDest
*/
void nsStr::Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount){
if(aDestOffset<aDest.mLength){
PRUint32 theDelta=aDest.mLength-aDestOffset;
PRUint32 theLength=(theDelta<aCount) ? theDelta : aCount;
if(aDestOffset+theLength<aDest.mLength) {
//if you're here, it means we're cutting chars out of the middle of the string...
//so shift the chars left by theLength...
(*gShiftChars[aDest.mCharSize][KSHIFTLEFT])(aDest.mStr,aDest.mLength,aDestOffset,theLength);
aDest.mLength-=theLength;
AddNullTerminator(aDest);
}
else Truncate(aDest,aDestOffset);
}//if
}
/**
* This method truncates the given nsStr at given offset
* @update gess10/30/98
* @param aDest is the nsStr to be truncated
* @param aDestOffset is where in aDest truncation is to occur
*/
void nsStr::Truncate(nsStr& aDest,PRUint32 aDestOffset){
if(aDestOffset<aDest.mLength){
aDest.mLength=aDestOffset;
AddNullTerminator(aDest);
}
}
/**
* This method forces the given string to upper or lowercase
* @update gess1/7/99
* @param aDest is the string you're going to change
* @param aToUpper: if TRUE, then we go uppercase, otherwise we go lowercase
* @return
*/
void nsStr::ChangeCase(nsStr& aDest,PRBool aToUpper) {
// somehow UnicharUtil return failed, fallback to the old ascii only code
gCaseConverters[aDest.mCharSize](aDest.mStr,aDest.mLength,aToUpper);
}
/**
*
* @update gess1/7/99
* @param
* @return
*/
void nsStr::Trim(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing){
if((aDest.mLength>0) && aSet){
PRInt32 theIndex=-1;
PRInt32 theMax=aDest.mLength;
PRInt32 theSetLen=nsCRT::strlen(aSet);
if(aEliminateLeading) {
while(++theIndex<=theMax) {
PRUnichar theChar=GetCharAt(aDest,theIndex);
PRInt32 thePos=gFindChars[eOneByte](aSet,theSetLen,0,theChar,PR_FALSE);
if(kNotFound==thePos)
break;
}
if(0<theIndex) {
if(theIndex<theMax) {
Delete(aDest,0,theIndex);
}
else Truncate(aDest,0);
}
}
if(aEliminateTrailing) {
theIndex=aDest.mLength;
PRInt32 theNewLen=theIndex;
while(--theIndex>0) {
PRUnichar theChar=GetCharAt(aDest,theIndex); //read at end now...
PRInt32 thePos=gFindChars[eOneByte](aSet,theSetLen,0,theChar,PR_FALSE);
if(kNotFound<thePos)
theNewLen=theIndex;
else break;
}
if(theNewLen<theMax) {
Truncate(aDest,theNewLen);
}
}
}
}
/**
*
* @update gess1/7/99
* @param
* @return
*/
void nsStr::CompressSet(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing){
Trim(aDest,aSet,aEliminateLeading,aEliminateTrailing);
PRUint32 aNewLen=gCompressChars[aDest.mCharSize](aDest.mStr,aDest.mLength,aSet);
aDest.mLength=aNewLen;
}
/**
*
* @update gess1/7/99
* @param
* @return
*/
void nsStr::StripChars(nsStr& aDest,const char* aSet){
if((0<aDest.mLength) && (aSet)) {
PRUint32 aNewLen=gStripChars[aDest.mCharSize](aDest.mStr,aDest.mLength,aSet);
aDest.mLength=aNewLen;
}
}
/**************************************************************
Searching methods...
**************************************************************/
/**
* This searches aDest for a given substring
*
* @update gess 3/25/98
* @param aDest string to search
* @param aTarget is the substring you're trying to find.
* @param aIgnorecase indicates case sensitivity of search
* @param anOffset tells us where to start the search
* @return index in aDest where member of aSet occurs, or -1 if not found
*/
PRInt32 nsStr::FindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRInt32 anOffset) {
// NS_PRECONDITION(aTarget.mLength!=1,kCallFindChar);
PRInt32 result=kNotFound;
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
PRInt32 theMax=aDest.mLength-aTarget.mLength;
PRInt32 index=(0<=anOffset) ? anOffset : 0;
if((aDest.mLength>=aTarget.mLength) && (aTarget.mLength>0) && (index>=0)){
PRInt32 theTargetMax=aTarget.mLength;
while(index<=theMax) {
PRInt32 theSubIndex=-1;
PRBool matches=PR_TRUE;
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theChar=(aIgnoreCase) ? nsCRT::ToLower(GetCharAt(aDest,index+theSubIndex)) : GetCharAt(aDest,index+theSubIndex);
PRUnichar theTargetChar=(aIgnoreCase) ? nsCRT::ToLower(GetCharAt(aTarget,theSubIndex)) : GetCharAt(aTarget,theSubIndex);
matches=PRBool(theChar==theTargetChar);
}
if(matches) {
result=index;
break;
}
index++;
} //while
}//if
}//if
return result;
}
/**
* This searches aDest for a given character
*
* @update gess 3/25/98
* @param aDest string to search
* @param char is the character you're trying to find.
* @param aIgnorecase indicates case sensitivity of search
* @param anOffset tells us where to start the search
* @return index in aDest where member of aSet occurs, or -1 if not found
*/
PRInt32 nsStr::FindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset) {
PRInt32 result=kNotFound;
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
PRUint32 index=(0<=anOffset) ? (PRUint32)anOffset : 0;
result=gFindChars[aDest.mCharSize](aDest.mStr,aDest.mLength,index,aChar,aIgnoreCase);
}
return result;
}
/**
* This searches aDest for a character found in aSet.
*
* @update gess 3/25/98
* @param aDest string to search
* @param aSet contains a list of chars to be searched for
* @param aIgnorecase indicates case sensitivity of search
* @param anOffset tells us where to start the search
* @return index in aDest where member of aSet occurs, or -1 if not found
*/
PRInt32 nsStr::FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset) {
//NS_PRECONDITION(aSet.mLength!=1,kCallFindChar);
PRInt32 index=(0<=anOffset) ? anOffset-1 : -1;
PRInt32 thePos;
//Note that the search is inverted here. We're scanning aDest, one char at a time
//but doing the search against the given set. That's why we use 0 as the offset below.
if((0<aDest.mLength) && (0<aSet.mLength)){
while(++index<(PRInt32)aDest.mLength) {
PRUnichar theChar=GetCharAt(aDest,index);
thePos=gFindChars[aSet.mCharSize](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
if(kNotFound!=thePos)
return index;
} //while
}
return kNotFound;
}
/**************************************************************
Reverse Searching methods...
**************************************************************/
/**
* This searches aDest (in reverse) for a given substring
*
* @update gess 3/25/98
* @param aDest string to search
* @param aTarget is the substring you're trying to find.
* @param aIgnorecase indicates case sensitivity of search
* @param anOffset tells us where to start the search (counting from left)
* @return index in aDest where member of aSet occurs, or -1 if not found
*/
PRInt32 nsStr::RFindSubstr(const nsStr& aDest,const nsStr& aTarget, PRBool aIgnoreCase,PRInt32 anOffset) {
//NS_PRECONDITION(aTarget.mLength!=1,kCallRFindChar);
PRInt32 result=kNotFound;
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
PRInt32 index=(0<=anOffset) ? anOffset : aDest.mLength-1;
if((aDest.mLength>=aTarget.mLength) && (aTarget.mLength>0) && (index>=0)){
nsStr theCopy;
nsStr::Initialize(theCopy,eOneByte);
nsStr::Assign(theCopy,aTarget,0,aTarget.mLength);
if(aIgnoreCase){
nsStr::ChangeCase(theCopy,PR_FALSE); //force to lowercase
}
PRInt32 theTargetMax=theCopy.mLength;
while(index>=0) {
PRInt32 theSubIndex=-1;
PRBool matches=PR_FALSE;
if(index+theCopy.mLength<=aDest.mLength) {
matches=PR_TRUE;
while((++theSubIndex<theTargetMax) && (matches)){
PRUnichar theDestChar=(aIgnoreCase) ? nsCRT::ToLower(GetCharAt(aDest,index+theSubIndex)) : GetCharAt(aDest,index+theSubIndex);
PRUnichar theTargetChar=GetCharAt(theCopy,theSubIndex);
matches=PRBool(theDestChar==theTargetChar);
} //while
} //if
if(matches) {
result=index;
break;
}
index--;
} //while
nsStr::Destroy(theCopy);
}//if
}//if
return result;
}
/**
* This searches aDest (in reverse) for a given character
*
* @update gess 3/25/98
* @param aDest string to search
* @param char is the character you're trying to find.
* @param aIgnorecase indicates case sensitivity of search
* @param anOffset tells us where to start the search
* @return index in aDest where member of aSet occurs, or -1 if not found
*/
PRInt32 nsStr::RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset) {
PRInt32 result=kNotFound;
if((0<aDest.mLength) && (anOffset<(PRInt32)aDest.mLength)) {
PRUint32 index=(0<=anOffset) ? anOffset : aDest.mLength-1;
result=gRFindChars[aDest.mCharSize](aDest.mStr,aDest.mLength,index,aChar,aIgnoreCase);
}
return result;
}
/**
* This searches aDest (in reverese) for a character found in aSet.
*
* @update gess 3/25/98
* @param aDest string to search
* @param aSet contains a list of chars to be searched for
* @param aIgnorecase indicates case sensitivity of search
* @param anOffset tells us where to start the search
* @return index in aDest where member of aSet occurs, or -1 if not found
*/
PRInt32 nsStr::RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset) {
//NS_PRECONDITION(aSet.mLength!=1,kCallRFindChar);
PRInt32 index=(0<=anOffset) ? anOffset : aDest.mLength;
PRInt32 thePos;
//note that the search is inverted here. We're scanning aDest, one char at a time
//but doing the search against the given set. That's why we use 0 as the offset below.
if(0<aDest.mLength) {
while(--index>=0) {
PRUnichar theChar=GetCharAt(aDest,index);
thePos=gFindChars[aSet.mCharSize](aSet.mStr,aSet.mLength,0,theChar,aIgnoreCase);
if(kNotFound!=thePos)
return index;
} //while
}
return kNotFound;
}
/**
* Compare source and dest strings, up to an (optional max) number of chars
* @param aDest is the first str to compare
* @param aSource is the second str to compare
* @param aCount -- if (-1), then we use length of longer string; if (0<aCount) then it gives the max # of chars to compare
* @param aIgnorecase tells us whether to search with case sensitivity
* @return aDest<aSource=-1;aDest==aSource==0;aDest>aSource=1
*/
PRInt32 nsStr::Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase) {
PRInt32 result=0;
if(aCount) {
PRInt32 minlen=(aSource.mLength<aDest.mLength) ? aSource.mLength : aDest.mLength;
if(0==minlen) {
if ((aDest.mLength == 0) && (aSource.mLength == 0))
return 0;
if (aDest.mLength == 0)
return -1;
return 1;
}
PRInt32 maxlen=(aSource.mLength<aDest.mLength) ? aDest.mLength : aSource.mLength;
aCount = (aCount<0) ? maxlen : MinInt(aCount,maxlen);
result=(*gCompare[aDest.mCharSize][aSource.mCharSize])(aDest.mStr,aSource.mStr,aCount,aIgnoreCase);
}
return result;
}
//----------------------------------------------------------------------------------------
PRBool nsStr::Alloc(nsStr& aDest,PRUint32 aCount) {
static int mAllocCount=0;
mAllocCount++;
//we're given the acount value in charunits; now scale up to next multiple.
PRUint32 theNewCapacity=kDefaultStringSize;
while(theNewCapacity<aCount){
theNewCapacity<<=1;
}
aDest.mCapacity=theNewCapacity++;
PRUint32 theSize=(theNewCapacity<<aDest.mCharSize);
aDest.mStr = (char*)nsAllocator::Alloc(theSize);
PRBool result=PR_FALSE;
if(aDest.mStr) {
aDest.mOwnsBuffer=1;
result=PR_TRUE;
}
return result;
}
PRBool nsStr::Free(nsStr& aDest){
if(aDest.mStr){
if(aDest.mOwnsBuffer){
nsAllocator::Free(aDest.mStr);
}
aDest.mStr=0;
aDest.mOwnsBuffer=0;
return PR_TRUE;
}
return PR_FALSE;
}
PRBool nsStr::Realloc(nsStr& aDest,PRUint32 aCount){
nsStr temp;
memcpy(&temp,&aDest,sizeof(aDest));
PRBool result=Alloc(temp,aCount);
if(result) {
Free(aDest);
aDest.mStr=temp.mStr;
aDest.mCapacity=temp.mCapacity;
aDest.mOwnsBuffer=temp.mOwnsBuffer;
}
return result;
}
//----------------------------------------------------------------------------------------
CBufDescriptor::CBufDescriptor(char* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) {
mBuffer=aString;
mCharSize=eOneByte;
mStackBased=aStackBased;
mIsConst=PR_FALSE;
mLength=mCapacity=0;
if(aString && aCapacity>1) {
mCapacity=aCapacity-1;
mLength=(-1==aLength) ? strlen(aString) : aLength;
if(mLength>PRInt32(mCapacity))
mLength=mCapacity;
}
}
CBufDescriptor::CBufDescriptor(const char* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) {
mBuffer=(char*)aString;
mCharSize=eOneByte;
mStackBased=aStackBased;
mIsConst=PR_TRUE;
mLength=mCapacity=0;
if(aString && aCapacity>1) {
mCapacity=aCapacity-1;
mLength=(-1==aLength) ? strlen(aString) : aLength;
if(mLength>PRInt32(mCapacity))
mLength=mCapacity;
}
}
CBufDescriptor::CBufDescriptor(PRUnichar* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) {
mBuffer=(char*)aString;
mCharSize=eTwoByte;
mStackBased=aStackBased;
mLength=mCapacity=0;
mIsConst=PR_FALSE;
if(aString && aCapacity>1) {
mCapacity=aCapacity-1;
mLength=(-1==aLength) ? nsCRT::strlen(aString) : aLength;
if(mLength>PRInt32(mCapacity))
mLength=mCapacity;
}
}
CBufDescriptor::CBufDescriptor(const PRUnichar* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength) {
mBuffer=(char*)aString;
mCharSize=eTwoByte;
mStackBased=aStackBased;
mLength=mCapacity=0;
mIsConst=PR_TRUE;
if(aString && aCapacity>1) {
mCapacity=aCapacity-1;
mLength=(-1==aLength) ? nsCRT::strlen(aString) : aLength;
if(mLength>PRInt32(mCapacity))
mLength=mCapacity;
}
}
//----------------------------------------------------------------------------------------

View File

@@ -1,450 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/***********************************************************************
MODULE NOTES:
1. There are two philosophies to building string classes:
A. Hide the underlying buffer & offer API's allow indirect iteration
B. Reveal underlying buffer, risk corruption, but gain performance
We chose the option B for performance reasons.
2 Our internal buffer always holds capacity+1 bytes.
The nsStr struct is a simple structure (no methods) that contains
the necessary info to be described as a string. This simple struct
is manipulated by the static methods provided in this class.
(Which effectively makes this a library that works on structs).
There are also object-based versions called nsString and nsAutoString
which use nsStr but makes it look at feel like an object.
***********************************************************************/
/***********************************************************************
ASSUMPTIONS:
1. nsStrings and nsAutoString are always null terminated.
2. If you try to set a null char (via SetChar()) a new length is set
3. nsCStrings can be upsampled into nsString without data loss
4. Char searching is faster than string searching. Use char interfaces
if your needs will allow it.
5. It's easy to use the stack for nsAutostring buffer storage (fast too!).
See the CBufDescriptor class in this file.
6. It's ONLY ok to provide non-null-terminated buffers to Append() and Insert()
provided you specify a 0<n value for the optional count argument.
7. Downsampling from nsString to nsCString is lossy -- avoid it if possible!
8. Calls to ToNewCString() and ToNewUnicode() should be matched with calls to Recycle().
***********************************************************************/
/**********************************************************************************
AND NOW FOR SOME GENERAL DOCUMENTATION ON STRING USAGE...
The fundamental datatype in the string library is nsStr. It's a structure that
provides the buffer storage and meta-info. It also provides a C-style library
of functions for direct manipulation (for those of you who prefer K&R to Bjarne).
Here's a diagram of the class hierarchy:
nsStr
|___nsString
| |
| ------nsAutoString
|
|___nsCString
|
------nsCAutoString
Why so many string classes? The 4 variants give you the control you need to
determine the best class for your purpose. There are 2 dimensions to this
flexibility: 1) stack vs. heap; and 2) 1-byte chars vs. 2-byte chars.
Note: While nsAutoString and nsCAutoString begin life using stack-based storage,
they may not stay that way. Like all nsString classes, autostrings will
automatically grow to contain the data you provide. When autostrings
grow beyond their intrinsic buffer, they switch to heap based allocations.
(We avoid alloca to avoid considerable platform difficulties; see the
GNU documentation for more details).
I should also briefly mention that all the string classes use a "memory agent"
object to perform memory operations. This class proxies the standard nsAllocator
for actual memory calls, but knows the structure of nsStr making heap operations
more localized.
CHOOSING A STRING CLASS:
In order to choose a string class for you purpose, use this handy table:
heap-based stack-based
-----------------------------------
ascii data | nsCString nsCAutoString |
|----------------------------------
unicode data | nsString nsAutoString |
-----------------------------------
Note: The i18n folks will stenuously object if we get too carried away with the
use of nsCString's that pass interface boundaries. Try to limit your
use of these to external interfaces that demand them, or for your own
private purposes in cases where they'll never be seen by humans.
PERFORMANCE CONSIDERATIONS:
Here are a few tricks to know in order to get better string performance:
1) Try to limit conversions between ascii and unicode; By sticking with nsString
wherever possible your code will be i18n-compliant.
2) Preallocating your string buffer cuts down trips to the allocator. So if you
have need for an arbitrarily large buffer, pre-size it like this:
{
nsString mBuffer;
mBuffer.SetCapacity(aReasonableSize);
}
3) Allocating nsAutoString or nsCAutoString on the heap is memory inefficient
(after all, the whole point is to avoid a heap allocation of the buffer).
4) Consider using an autoString to write into your arbitrarily-sized stack buffers, rather
than it's own buffers.
For example, let's say you're going to call printf() to emit pretty-printed debug output
of your object. You know from experience that the pretty-printed version of your object
exceeds the capacity of an autostring. Ignoring memory considerations, you could simply
use nsCString, appending the stringized version of each of your class's data members.
This will probably result in calls to the heap manager.
But there's a way to do this without necessarily having to call the heap manager.
All you do is declare a stack based buffer and instruct nsCString to use that instead
of it's own internal buffer by using the CBufDescriptor class:
{
char theBuffer[256];
CBufDescritor theBufDecriptor( theBuffer, PR_TRUE, sizeof(theBuffer), 0);
nsCAutoString s3( theBufDescriptor );
s3="HELLO, my name is inigo montoya, you killed my father, prepare to die!.";
}
The assignment statment to s3 will cause the given string to be written to your
stack-based buffer via the normal nsString/nsCString interfaces. Cool, huh?
Note however that just like any other nsStringXXX use, if you write more data
than will fit in the buffer, a visit to the heap manager will be in order.
**********************************************************************************/
#ifndef _nsStr
#define _nsStr
#include "nscore.h"
#include "nsIAllocator.h"
#include <string.h>
//----------------------------------------------------------------------------------------
enum eCharSize {eOneByte=0,eTwoByte=1};
#define kDefaultCharSize eTwoByte
#define kRadix10 (10)
#define kRadix16 (16)
#define kAutoDetect (100)
#define kRadixUnknown (kAutoDetect+1)
const PRInt32 kDefaultStringSize = 64;
const PRInt32 kNotFound = -1;
//----------------------------------------------------------------------------------------
class NS_COM CBufDescriptor {
public:
CBufDescriptor(char* aString, PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength=-1);
CBufDescriptor(const char* aString, PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength=-1);
CBufDescriptor(PRUnichar* aString, PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength=-1);
CBufDescriptor(const PRUnichar* aString,PRBool aStackBased,PRUint32 aCapacity,PRInt32 aLength=-1);
char* mBuffer;
eCharSize mCharSize;
PRUint32 mCapacity;
PRInt32 mLength;
PRBool mStackBased;
PRBool mIsConst;
};
//----------------------------------------------------------------------------------------
struct NS_COM nsStr {
//----------------------------------------------------------------------------------------
nsStr() {
MOZ_COUNT_CTOR(nsStr);
}
~nsStr() {
MOZ_COUNT_DTOR(nsStr);
}
/**
* This method initializes an nsStr for use
*
* @update gess 01/04/99
* @param aString is the nsStr to be initialized
* @param aCharSize tells us the requested char size (1 or 2 bytes)
*/
static void Initialize(nsStr& aDest,eCharSize aCharSize);
/**
* This method initializes an nsStr for use
*
* @update gess 01/04/99
* @param aString is the nsStr to be initialized
* @param aCharSize tells us the requested char size (1 or 2 bytes)
*/
static void Initialize(nsStr& aDest,char* aCString,PRUint32 aCapacity,PRUint32 aLength,eCharSize aCharSize,PRBool aOwnsBuffer);
/**
* This method destroys the given nsStr, and *MAY*
* deallocate it's memory depending on the setting
* of the internal mOwnsBUffer flag.
*
* @update gess 01/04/99
* @param aString is the nsStr to be manipulated
* @param anAgent is the allocator to be used to the nsStr
*/
static void Destroy(nsStr& aDest);
/**
* These methods are where memory allocation/reallocation occur.
*
* @update gess 01/04/99
* @param aString is the nsStr to be manipulated
* @param anAgent is the allocator to be used on the nsStr
* @return
*/
static PRBool EnsureCapacity(nsStr& aString,PRUint32 aNewLength);
static PRBool GrowCapacity(nsStr& aString,PRUint32 aNewLength);
/**
* These methods are used to append content to the given nsStr
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param aSource is the buffer to be copied from
* @param anOffset tells us where in source to start copying
* @param aCount tells us the (max) # of chars to copy
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Append(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount);
/**
* These methods are used to assign contents of a source string to dest string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param aSource is the buffer to be copied from
* @param anOffset tells us where in source to start copying
* @param aCount tells us the (max) # of chars to copy
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Assign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount);
/**
* These methods are used to insert content from source string to the dest nsStr
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param aDestOffset tells us where in dest to start insertion
* @param aSource is the buffer to be copied from
* @param aSrcOffset tells us where in source to start copying
* @param aCount tells us the (max) # of chars to insert
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Insert( nsStr& aDest,PRUint32 aDestOffset,const nsStr& aSource,PRUint32 aSrcOffset,PRInt32 aCount);
/**
* This method deletes chars from the given str.
* The given allocator may choose to resize the str as well.
*
* @update gess 01/04/99
* @param aDest is the nsStr to be deleted from
* @param aDestOffset tells us where in dest to start deleting
* @param aCount tells us the (max) # of chars to delete
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Delete(nsStr& aDest,PRUint32 aDestOffset,PRUint32 aCount);
/**
* This method is used to truncate the given string.
* The given allocator may choose to resize the str as well (but it's not likely).
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param aDestOffset tells us where in dest to start insertion
* @param aSource is the buffer to be copied from
* @param aSrcOffset tells us where in source to start copying
* @param anAgent is the allocator to be used for alloc/free operations
*/
static void Truncate(nsStr& aDest,PRUint32 aDestOffset);
/**
* This method is used to perform a case conversion on the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be case shifted
* @param toUpper tells us to go upper vs. lower
*/
static void ChangeCase(nsStr& aDest,PRBool aToUpper);
/**
* This method trims chars (given in aSet) from the edges of given buffer
*
* @update gess 01/04/99
* @param aDest is the buffer to be manipulated
* @param aSet tells us which chars to remove from given buffer
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
*/
static void Trim(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing);
/**
* This method compresses duplicate runs of a given char from the given buffer
*
* @update gess 01/04/99
* @param aDest is the buffer to be manipulated
* @param aSet tells us which chars to compress from given buffer
* @param aChar is the replacement char
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
*/
static void CompressSet(nsStr& aDest,const char* aSet,PRBool aEliminateLeading,PRBool aEliminateTrailing);
/**
* This method removes all occurances of chars in given set from aDest
*
* @update gess 01/04/99
* @param aDest is the buffer to be manipulated
* @param aSet tells us which chars to compress from given buffer
* @param aChar is the replacement char
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
*/
static void StripChars(nsStr& aDest,const char* aSet);
/**
* This method compares the data bewteen two nsStr's
*
* @update gess 01/04/99
* @param aStr1 is the first buffer to be compared
* @param aStr2 is the 2nd buffer to be compared
* @param aCount is the number of chars to compare
* @param aIgnorecase tells us whether to use a case-sensitive comparison
* @return -1,0,1 depending on <,==,>
*/
static PRInt32 Compare(const nsStr& aDest,const nsStr& aSource,PRInt32 aCount,PRBool aIgnoreCase);
/**
* These methods scan the given string for 1 or more chars in a given direction
*
* @update gess 01/04/99
* @param aDest is the nsStr to be searched to
* @param aSource (or aChar) is the substr we're looking to find
* @param aIgnoreCase tells us whether to search in a case-sensitive manner
* @param anOffset tells us where in the dest string to start searching
* @return the index of the source (substr) in dest, or -1 (kNotFound) if not found.
*/
static PRInt32 FindSubstr(const nsStr& aDest,const nsStr& aSource, PRBool aIgnoreCase,PRInt32 anOffset);
static PRInt32 FindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset);
static PRInt32 FindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset);
static PRInt32 RFindSubstr(const nsStr& aDest,const nsStr& aSource, PRBool aIgnoreCase,PRInt32 anOffset);
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset);
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset);
PRUint32 mLength;
PRUint32 mCapacity;
eCharSize mCharSize;
PRBool mOwnsBuffer;
union {
char* mStr;
PRUnichar* mUStr;
};
private:
static PRBool Alloc(nsStr& aString,PRUint32 aCount);
static PRBool Realloc(nsStr& aString,PRUint32 aCount);
static PRBool Free(nsStr& aString);
};
/**************************************************************
A couple of tiny helper methods used in the string classes.
**************************************************************/
inline PRInt32 MinInt(PRInt32 anInt1,PRInt32 anInt2){
return (anInt1<anInt2) ? anInt1 : anInt2;
}
inline PRInt32 MaxInt(PRInt32 anInt1,PRInt32 anInt2){
return (anInt1<anInt2) ? anInt2 : anInt1;
}
inline void AddNullTerminator(nsStr& aDest) {
if(eTwoByte==aDest.mCharSize)
aDest.mUStr[aDest.mLength]=0;
else aDest.mStr[aDest.mLength]=0;
}
/**
* Return the given buffer to the heap manager. Calls allocator::Free()
* @return string length
*/
inline void Recycle( char* aBuffer) { nsAllocator::Free(aBuffer); }
inline void Recycle( PRUnichar* aBuffer) { nsAllocator::Free(aBuffer); }
/**
* This method is used to access a given char in the given string
*
* @update gess 01/04/99
* @param aDest is the nsStr to be appended to
* @param anIndex tells us where in dest to get the char from
* @return the given char, or 0 if anIndex is out of range
*/
inline PRUnichar GetCharAt(const nsStr& aDest,PRUint32 anIndex){
if(anIndex<aDest.mLength) {
return (eTwoByte==aDest.mCharSize) ? aDest.mUStr[anIndex] : aDest.mStr[anIndex];
}//if
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,747 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/***********************************************************************
MODULE NOTES:
See nsStr.h for a more general description of string classes.
This version of the nsString class offers many improvements over the
original version:
1. Wide and narrow chars
2. Allocators
3. Much smarter autostrings
4. Subsumable strings
***********************************************************************/
#ifndef _nsCString_
#define _nsCString_
#include "nsString2.h"
#include "prtypes.h"
#include "nscore.h"
#include <stdio.h>
#include "nsStr.h"
#include "nsIAtom.h"
class NS_COM nsSubsumeCStr;
class NS_COM nsCString : public nsStr {
public:
/**
* Default constructor.
*/
nsCString();
/**
* This constructor accepts an isolatin string
* @param aCString is a ptr to a 1-byte cstr
*/
nsCString(const char* aCString,PRInt32 aLength=-1);
/**
* This constructor accepts a unichar string
* @param aCString is a ptr to a 2-byte cstr
*/
nsCString(const PRUnichar* aString,PRInt32 aLength=-1);
/**
* This is a copy constructor that accepts an nsStr
* @param reference to another nsCString
*/
nsCString(const nsStr&);
/**
* This is our copy constructor
* @param reference to another nsCString
*/
nsCString(const nsCString& aString);
/**
* This constructor takes a subsumestr
* @param reference to subsumestr
*/
nsCString(nsSubsumeCStr& aSubsumeStr);
/**
* Destructor
*
*/
virtual ~nsCString();
/**
* Retrieve the length of this string
* @return string length
*/
inline PRInt32 Length() const { return (PRInt32)mLength; }
/**
* Retrieve the size of this string
* @return string length
*/
virtual void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
/**
* Call this method if you want to force a different string capacity
* @update gess7/30/98
* @param aLength -- contains new length for mStr
* @return
*/
void SetLength(PRUint32 aLength) {
Truncate(aLength);
}
/**
* Sets the new length of the string.
* @param aLength is new string length.
* @return nada
*/
void SetCapacity(PRUint32 aLength);
/**
* This method truncates this string to given length.
*
* @param anIndex -- new length of string
* @return nada
*/
void Truncate(PRInt32 anIndex=0);
/**
* Determine whether or not the characters in this
* string are in sorted order.
*
* @return TRUE if ordered.
*/
PRBool IsOrdered(void) const;
/**
* Determine whether or not this string has a length of 0
*
* @return TRUE if empty.
*/
PRBool IsEmpty(void) const {
return PRBool(0==mLength);
}
/**********************************************************************
Accessor methods...
*********************************************************************/
/**
* Retrieve const ptr to internal buffer; DO NOT TRY TO FREE IT!
*/
const char* GetBuffer(void) const;
/**
* Get nth character.
*/
PRUnichar operator[](PRUint32 anIndex) const;
PRUnichar CharAt(PRUint32 anIndex) const;
PRUnichar First(void) const;
PRUnichar Last(void) const;
PRBool SetCharAt(PRUnichar aChar,PRUint32 anIndex);
/**********************************************************************
String creation methods...
*********************************************************************/
/**
* Create a new string by appending given string to this
* @param aString -- 2nd string to be appended
* @return new string
*/
nsSubsumeCStr operator+(const nsCString& aString);
/**
* create a new string by adding this to the given char*.
* @param aCString is a ptr to cstring to be added to this
* @return newly created string
*/
nsSubsumeCStr operator+(const char* aCString);
/**
* create a new string by adding this to the given char.
* @param aChar is a char to be added to this
* @return newly created string
*/
nsSubsumeCStr operator+(PRUnichar aChar);
nsSubsumeCStr operator+(char aChar);
/**********************************************************************
Lexomorphic transforms...
*********************************************************************/
/**
* Converts chars in this to lowercase
* @update gess 7/27/98
*/
void ToLowerCase();
/**
* Converts chars in this to lowercase, and
* stores them in aOut
* @update gess 7/27/98
* @param aOut is a string to contain result
*/
void ToLowerCase(nsCString& aString) const;
/**
* Converts chars in this to uppercase
* @update gess 7/27/98
*/
void ToUpperCase();
/**
* Converts chars in this to lowercase, and
* stores them in a given output string
* @update gess 7/27/98
* @param aOut is a string to contain result
*/
void ToUpperCase(nsCString& aString) const;
/**
* This method is used to remove all occurances of the
* characters found in aSet from this string.
*
* @param aSet -- characters to be cut from this
* @return *this
*/
nsCString& StripChars(const char* aSet);
nsCString& StripChar(char aChar);
/**
* This method strips whitespace throughout the string
*
* @return this
*/
nsCString& StripWhitespace();
/**
* swaps occurence of 1 string for another
*
* @return this
*/
nsCString& ReplaceChar(PRUnichar aOldChar,PRUnichar aNewChar);
nsCString& ReplaceChar(const char* aSet,PRUnichar aNewChar);
PRInt32 CountChar(PRUnichar aChar);
/**
* This method trims characters found in aTrimSet from
* either end of the underlying string.
*
* @param aTrimSet -- contains chars to be trimmed from
* both ends
* @return this
*/
nsCString& Trim(const char* aSet,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
/**
* This method strips whitespace from string.
* You can control whether whitespace is yanked from
* start and end of string as well.
*
* @param aEliminateLeading controls stripping of leading ws
* @param aEliminateTrailing controls stripping of trailing ws
* @return this
*/
nsCString& CompressSet(const char* aSet, PRUnichar aChar,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
/**
* This method strips whitespace from string.
* You can control whether whitespace is yanked from
* start and end of string as well.
*
* @param aEliminateLeading controls stripping of leading ws
* @param aEliminateTrailing controls stripping of trailing ws
* @return this
*/
nsCString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
/**********************************************************************
string conversion methods...
*********************************************************************/
operator char*() {return mStr;}
operator const char*() const {return (const char*)mStr;}
/**
* This method constructs a new nsCString that is a clone
* of this string.
*
*/
nsCString* ToNewString() const;
/**
* Creates an ISOLatin1 clone of this string
* Note that calls to this method should be matched with calls to Recycle().
* @return ptr to new isolatin1 string
*/
char* ToNewCString() const;
/**
* Creates a unicode clone of this string
* Note that calls to this method should be matched with calls to Recycle().
* @return ptr to new unicode string
*/
PRUnichar* ToNewUnicode() const;
/**
* Copies data from internal buffer onto given char* buffer
* NOTE: This only copies as many chars as will fit in given buffer (clips)
* @param aBuf is the buffer where data is stored
* @param aBuflength is the max # of chars to move to buffer
* @return ptr to given buffer
*/
char* ToCString(char* aBuf,PRUint32 aBufLength,PRUint32 anOffset=0) const;
/**
* Perform string to float conversion.
* @param aErrorCode will contain error if one occurs
* @return float rep of string value
*/
float ToFloat(PRInt32* aErrorCode) const;
/**
* Try to derive the radix from the value contained in this string
* @return kRadix10, kRadix16 or kAutoDetect (meaning unknown)
*/
PRUint32 DetermineRadix(void);
/**
* Perform string to int conversion.
* @param aErrorCode will contain error if one occurs
* @return int rep of string value
*/
PRInt32 ToInteger(PRInt32* aErrorCode,PRUint32 aRadix=kRadix10) const;
/**********************************************************************
String manipulation methods...
*********************************************************************/
/**
* Functionally equivalent to assign or operator=
*
*/
nsCString& SetString(const char* aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
nsCString& SetString(const nsStr& aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
/**
* assign given string to this string
* @param aStr: buffer to be assigned to this
* @param alength is the length of the given str (or -1)
if you want me to determine its length
* @return this
*/
nsCString& Assign(const nsStr& aString,PRInt32 aCount=-1);
nsCString& Assign(const char* aString,PRInt32 aCount=-1);
nsCString& Assign(const PRUnichar* aString,PRInt32 aCount=-1);
nsCString& Assign(PRUnichar aChar);
nsCString& Assign(char aChar);
/**
* here come a bunch of assignment operators...
* @param aString: string to be added to this
* @return this
*/
nsCString& operator=(const nsCString& aString) {return Assign(aString);}
nsCString& operator=(const nsStr& aString) {return Assign(aString);}
nsCString& operator=(PRUnichar aChar) {return Assign(aChar);}
nsCString& operator=(char aChar) {return Assign(aChar);}
nsCString& operator=(const char* aCString) {return Assign(aCString);}
nsCString& operator=(const PRUnichar* aString) {return Assign(aString);}
#ifdef AIX
nsCString& operator=(const nsSubsumeCStr& aSubsumeString); // AIX requires a const here
#else
nsCString& operator=(nsSubsumeCStr& aSubsumeString);
#endif
/**
* Here's a bunch of methods that append varying types...
* @param various...
* @return this
*/
nsCString& operator+=(const nsCString& aString){return Append(aString,aString.mLength);}
nsCString& operator+=(const char* aCString) {return Append(aCString);}
nsCString& operator+=(PRUnichar aChar){return Append(aChar);}
nsCString& operator+=(char aChar){return Append(aChar);}
/*
* Appends n characters from given string to this,
* This version computes the length of your given string
*
* @param aString is the source to be appended to this
* @return number of chars copied
*/
nsCString& Append(const nsCString& aString) {return Append(aString,aString.mLength);}
/*
* Appends n characters from given string to this,
*
* @param aString is the source to be appended to this
* @param aCount -- number of chars to copy; -1 tells us to compute the strlen for you
* @return number of chars copied
*/
nsCString& Append(const nsCString& aString,PRInt32 aCount);
nsCString& Append(const nsStr& aString,PRInt32 aCount=-1);
nsCString& Append(const char* aString,PRInt32 aCount=-1);
nsCString& Append(PRUnichar aChar);
nsCString& Append(char aChar);
nsCString& Append(PRInt32 aInteger,PRInt32 aRadix=10); //radix=8,10 or 16
nsCString& Append(float aFloat);
/*
* Copies n characters from this string to given string,
* starting at the leftmost offset.
*
*
* @param aCopy -- Receiving string
* @param aCount -- number of chars to copy
* @return number of chars copied
*/
PRUint32 Left(nsCString& aCopy,PRInt32 aCount) const;
/*
* Copies n characters from this string to given string,
* starting at the given offset.
*
*
* @param aCopy -- Receiving string
* @param aCount -- number of chars to copy
* @param anOffset -- position where copying begins
* @return number of chars copied
*/
PRUint32 Mid(nsCString& aCopy,PRUint32 anOffset,PRInt32 aCount) const;
/*
* Copies n characters from this string to given string,
* starting at rightmost char.
*
*
* @param aCopy -- Receiving string
* @param aCount -- number of chars to copy
* @return number of chars copied
*/
PRUint32 Right(nsCString& aCopy,PRInt32 aCount) const;
/*
* This method inserts n chars from given string into this
* string at str[anOffset].
*
* @param aCopy -- String to be inserted into this
* @param anOffset -- insertion position within this str
* @param aCount -- number of chars to be copied from aCopy
* @return number of chars inserted into this.
*/
nsCString& Insert(const nsCString& aCopy,PRUint32 anOffset,PRInt32 aCount=-1);
/**
* Insert a given string into this string at
* a specified offset.
*
* @param aString* to be inserted into this string
* @param anOffset is insert pos in str
* @return the number of chars inserted into this string
*/
nsCString& Insert(const char* aChar,PRUint32 anOffset,PRInt32 aCount=-1);
/**
* Insert a single char into this string at
* a specified offset.
*
* @param character to be inserted into this string
* @param anOffset is insert pos in str
* @return the number of chars inserted into this string
*/
nsCString& Insert(PRUnichar aChar,PRUint32 anOffset);
nsCString& Insert(char aChar,PRUint32 anOffset);
/*
* This method is used to cut characters in this string
* starting at anOffset, continuing for aCount chars.
*
* @param anOffset -- start pos for cut operation
* @param aCount -- number of chars to be cut
* @return *this
*/
nsCString& Cut(PRUint32 anOffset,PRInt32 aCount);
/**********************************************************************
Searching methods...
*********************************************************************/
/**
* Search for given character within this string.
* This method does so by using a binary search,
* so your string HAD BETTER BE ORDERED!
*
* @param aChar is the unicode char to be found
* @return offset in string, or -1 (kNotFound)
*/
PRInt32 BinarySearch(PRUnichar aChar) const;
/**
* Search for given substring within this string
*
* @param aString is substring to be sought in this
* @param aIgnoreCase selects case sensitivity
* @param anOffset tells us where in this strig to start searching
* @return offset in string, or -1 (kNotFound)
*/
PRInt32 Find(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 Find(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 Find(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* Search for given char within this string
*
* @param aString is substring to be sought in this
* @param anOffset tells us where in this strig to start searching
* @param aIgnoreCase selects case sensitivity
* @return find pos in string, or -1 (kNotFound)
*/
PRInt32 FindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* This method searches this string for the first character
* found in the given charset
* @param aString contains set of chars to be found
* @param anOffset tells us where to start searching in this
* @return -1 if not found, else the offset in this
*/
PRInt32 FindCharInSet(const char* aString,PRInt32 anOffset=-1) const;
PRInt32 FindCharInSet(const PRUnichar* aString,PRInt32 anOffset=-1) const;
PRInt32 FindCharInSet(const nsStr& aString,PRInt32 anOffset=-1) const;
/**
* This methods scans the string backwards, looking for the given string
* @param aString is substring to be sought in this
* @param aIgnoreCase tells us whether or not to do caseless compare
* @return offset in string, or -1 (kNotFound)
*/
PRInt32 RFind(const char* aCString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 RFind(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* Search for given char within this string
*
* @param aString is substring to be sought in this
* @param anOffset tells us where in this strig to start searching
* @param aIgnoreCase selects case sensitivity
* @return find pos in string, or -1 (kNotFound)
*/
PRInt32 RFindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* This method searches this string for the last character
* found in the given string
* @param aString contains set of chars to be found
* @param anOffset tells us where to start searching in this
* @return -1 if not found, else the offset in this
*/
PRInt32 RFindCharInSet(const char* aString,PRInt32 anOffset=-1) const;
PRInt32 RFindCharInSet(const PRUnichar* aString,PRInt32 anOffset=-1) const;
PRInt32 RFindCharInSet(const nsStr& aString,PRInt32 anOffset=-1) const;
/**********************************************************************
Comparison methods...
*********************************************************************/
/**
* Compares a given string type to this string.
* @update gess 7/27/98
* @param S is the string to be compared
* @param aIgnoreCase tells us how to treat case
* @param aCount tells us how many chars to compare
* @return -1,0,1
*/
virtual PRInt32 Compare(const nsStr &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
virtual PRInt32 Compare(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
virtual PRInt32 Compare(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
/**
* These methods compare a given string type to this one
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator==(const nsStr &aString) const;
PRBool operator==(const char* aString) const;
PRBool operator==(const PRUnichar* aString) const;
/**
* These methods perform a !compare of a given string type to this
* @param aString is the string to be compared to this
* @return TRUE
*/
PRBool operator!=(const nsStr &aString) const;
PRBool operator!=(const char* aString) const;
PRBool operator!=(const PRUnichar* aString) const;
/**
* These methods test if a given string is < than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator<(const nsStr &aString) const;
PRBool operator<(const char* aString) const;
PRBool operator<(const PRUnichar* aString) const;
/**
* These methods test if a given string is > than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator>(const nsStr &S) const;
PRBool operator>(const char* aString) const;
PRBool operator>(const PRUnichar* aString) const;
/**
* These methods test if a given string is <= than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator<=(const nsStr &S) const;
PRBool operator<=(const char* aString) const;
PRBool operator<=(const PRUnichar* aString) const;
/**
* These methods test if a given string is >= than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator>=(const nsStr &S) const;
PRBool operator>=(const char* aString) const;
PRBool operator>=(const PRUnichar* aString) const;
/**
* Compare this to given string; note that we compare full strings here.
* The optional length argument just lets us know how long the given string is.
* If you provide a length, it is compared to length of this string as an
* optimization.
*
* @param aString -- the string to compare to this
* @param aCount -- number of chars in given string you want to compare
* @return TRUE if equal
*/
PRBool Equals(const nsString &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool EqualsIgnoreCase(const nsStr& aString) const;
PRBool EqualsIgnoreCase(const char* aString,PRInt32 aCount=-1) const;
PRBool EqualsIgnoreCase(const PRUnichar* aString,PRInt32 aCount=-1) const;
static void Recycle(nsCString* aString);
static nsCString* CreateString(void);
};
extern NS_COM int fputs(const nsCString& aString, FILE* out);
//ostream& operator<<(ostream& aStream,const nsCString& aString);
//virtual void DebugDump(ostream& aStream) const;
/**************************************************************
Here comes the AutoString class which uses internal memory
(typically found on the stack) for its default buffer.
If the buffer needs to grow, it gets reallocated on the heap.
**************************************************************/
class NS_COM nsCAutoString : public nsCString {
public:
nsCAutoString();
nsCAutoString(const char* aString,PRInt32 aLength=-1);
nsCAutoString(const CBufDescriptor& aBuffer);
nsCAutoString(const PRUnichar* aString,PRInt32 aLength=-1);
nsCAutoString(const nsStr& aString);
nsCAutoString(const nsCAutoString& aString);
#ifdef AIX
nsCAutoString(const nsSubsumeCStr& aSubsumeStr); // AIX requires a const
#else
nsCAutoString(nsSubsumeCStr& aSubsumeStr);
#endif // AIX
nsCAutoString(PRUnichar aChar);
virtual ~nsCAutoString();
nsCAutoString& operator=(const nsCString& aString) {nsCString::Assign(aString); return *this;}
nsCAutoString& operator=(const char* aCString) {nsCString::Assign(aCString); return *this;}
nsCAutoString& operator=(PRUnichar aChar) {nsCString::Assign(aChar); return *this;}
nsCAutoString& operator=(char aChar) {nsCString::Assign(aChar); return *this;}
/**
* Retrieve the size of this string
* @return string length
*/
virtual void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
char mBuffer[kDefaultStringSize];
};
/***************************************************************
The subsumestr class is very unusual.
It differs from a normal string in that it doesn't use normal
copy semantics when another string is assign to this.
Instead, it "steals" the contents of the source string.
This is very handy for returning nsString classes as part of
an operator+(...) for example, in that it cuts down the number
of copy operations that must occur.
You should probably not use this class unless you really know
what you're doing.
***************************************************************/
class NS_COM nsSubsumeCStr : public nsCString {
public:
nsSubsumeCStr(nsStr& aString);
nsSubsumeCStr(PRUnichar* aString,PRBool assumeOwnership,PRInt32 aLength=-1);
nsSubsumeCStr(char* aString,PRBool assumeOwnership,PRInt32 aLength=-1);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,840 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/***********************************************************************
MODULE NOTES:
See nsStr.h for a more general description of string classes.
This version of the nsString class offers many improvements over the
original version:
1. Wide and narrow chars
2. Allocators
3. Much smarter autostrings
4. Subsumable strings
***********************************************************************/
#ifndef _nsString_
#define _nsString_
#include "prtypes.h"
#include "nscore.h"
#include <stdio.h>
#include "nsString.h"
#include "nsIAtom.h"
#include "nsStr.h"
#include "nsCRT.h"
class nsISizeOfHandler;
#define nsString2 nsString
#define nsAutoString2 nsAutoString
class NS_COM nsSubsumeStr;
class NS_COM nsString : public nsStr {
public:
/**
* Default constructor.
*/
nsString();
/**
* This constructor accepts an isolatin string
* @param aCString is a ptr to a 1-byte cstr
*/
nsString(const char* aCString);
/**
* This constructor accepts a unichar string
* @param aCString is a ptr to a 2-byte cstr
*/
nsString(const PRUnichar* aString);
/**
* This is a copy constructor that accepts an nsStr
* @param reference to another nsString
*/
nsString(const nsStr&);
/**
* This is our copy constructor
* @param reference to another nsString
*/
nsString(const nsString& aString);
/**
* This constructor takes a subsumestr
* @param reference to subsumestr
*/
nsString(nsSubsumeStr& aSubsumeStr);
/**
* Destructor
*
*/
virtual ~nsString();
/**
* Retrieve the length of this string
* @return string length
*/
inline PRInt32 Length() const { return (PRInt32)mLength; }
/**
* Retrieve the size of this string
* @return string length
*/
virtual void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
/**
* Call this method if you want to force a different string length
* @update gess7/30/98
* @param aLength -- contains new length for mStr
* @return
*/
void SetLength(PRUint32 aLength) {
Truncate(aLength);
}
/**
* Sets the new length of the string.
* @param aLength is new string length.
* @return nada
*/
void SetCapacity(PRUint32 aLength);
/**
* This method truncates this string to given length.
*
* @param anIndex -- new length of string
* @return nada
*/
void Truncate(PRInt32 anIndex=0);
/**
* Determine whether or not the characters in this
* string are in sorted order.
*
* @return TRUE if ordered.
*/
PRBool IsOrdered(void) const;
/**
* Determine whether or not the characters in this
* string are in store as 1 or 2 byte (unicode) strings.
*
* @return TRUE if ordered.
*/
PRBool IsUnicode(void) const {
PRBool result=PRBool(mCharSize==eTwoByte);
return result;
}
/**
* Determine whether or not this string has a length of 0
*
* @return TRUE if empty.
*/
PRBool IsEmpty(void) const {
return PRBool(0==mLength);
}
/**********************************************************************
Getters/Setters...
*********************************************************************/
/**
* Retrieve const ptr to internal buffer; DO NOT TRY TO FREE IT!
*/
const char* GetBuffer(void) const;
const PRUnichar* GetUnicode(void) const;
/**
* Get nth character.
*/
PRUnichar operator[](PRUint32 anIndex) const;
PRUnichar CharAt(PRUint32 anIndex) const;
PRUnichar First(void) const;
PRUnichar Last(void) const;
/**
* Set nth character.
*/
PRBool SetCharAt(PRUnichar aChar,PRUint32 anIndex);
/**********************************************************************
String concatenation methods...
*********************************************************************/
/**
* Create a new string by appending given string to this
* @param aString -- 2nd string to be appended
* @return new subsumable string
*/
nsSubsumeStr operator+(const nsStr& aString);
nsSubsumeStr operator+(const nsString& aString);
/**
* create a new string by adding this to the given cstring
* @param aCString is a ptr to cstring to be added to this
* @return newly created string
*/
nsSubsumeStr operator+(const char* aCString);
/**
* create a new string by adding this to the given prunichar*.
* @param aString is a ptr to UC-string to be added to this
* @return newly created string
*/
nsSubsumeStr operator+(const PRUnichar* aString);
/**
* create a new string by adding this to the given char.
* @param aChar is a char to be added to this
* @return newly created string
*/
nsSubsumeStr operator+(char aChar);
/**
* create a new string by adding this to the given char.
* @param aChar is a unichar to be added to this
* @return newly created string
*/
nsSubsumeStr operator+(PRUnichar aChar);
/**********************************************************************
Lexomorphic transforms...
*********************************************************************/
/**
* Converts chars in this to lowercase
* @update gess 7/27/98
*/
void ToLowerCase();
/**
* Converts chars in this to lowercase, and
* stores them in aOut
* @update gess 7/27/98
* @param aOut is a string to contain result
*/
void ToLowerCase(nsString& aString) const;
/**
* Converts chars in this to uppercase
* @update gess 7/27/98
*/
void ToUpperCase();
/**
* Converts chars in this to lowercase, and
* stores them in a given output string
* @update gess 7/27/98
* @param aOut is a string to contain result
*/
void ToUpperCase(nsString& aString) const;
/**
* This method is used to remove all occurances of the
* characters found in aSet from this string.
*
* @param aSet -- characters to be cut from this
* @return *this
*/
nsString& StripChars(const char* aSet);
nsString& StripChar(char aChar);
/**
* This method strips whitespace throughout the string
*
* @return this
*/
nsString& StripWhitespace();
/**
* swaps occurence of 1 string for another
*
* @return this
*/
nsString& ReplaceChar(PRUnichar anOldChar,PRUnichar aNewChar);
nsString& ReplaceChar(const char* aSet,PRUnichar aNewChar);
PRInt32 CountChar(PRUnichar aChar);
/**
* This method trims characters found in aTrimSet from
* either end of the underlying string.
*
* @param aTrimSet -- contains chars to be trimmed from
* both ends
* @return this
*/
nsString& Trim(const char* aSet,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
/**
* This method strips whitespace from string.
* You can control whether whitespace is yanked from
* start and end of string as well.
*
* @param aEliminateLeading controls stripping of leading ws
* @param aEliminateTrailing controls stripping of trailing ws
* @return this
*/
nsString& CompressSet(const char* aSet, PRUnichar aChar,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
/**
* This method strips whitespace from string.
* You can control whether whitespace is yanked from
* start and end of string as well.
*
* @param aEliminateLeading controls stripping of leading ws
* @param aEliminateTrailing controls stripping of trailing ws
* @return this
*/
nsString& CompressWhitespace( PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
/**********************************************************************
string conversion methods...
*********************************************************************/
/**
* This method constructs a new nsString is a clone of this string.
*
*/
nsString* ToNewString() const;
/**
* Creates an ISOLatin1 clone of this string
* Note that calls to this method should be matched with calls to Recycle().
* @return ptr to new isolatin1 string
*/
char* ToNewCString() const;
/**
* Creates an UTF8 clone of this string
* Note that calls to this method should be matched with calls to Recycle().
* @return ptr to new isolatin1 string
*/
char* ToNewUTF8String() const;
/**
* Creates a unicode clone of this string
* Note that calls to this method should be matched with calls to Recycle().
* @return ptr to new unicode string
*/
PRUnichar* ToNewUnicode() const;
/**
* Copies data from internal buffer onto given char* buffer
* NOTE: This only copies as many chars as will fit in given buffer (clips)
* @param aBuf is the buffer where data is stored
* @param aBuflength is the max # of chars to move to buffer
* @return ptr to given buffer
*/
char* ToCString(char* aBuf,PRUint32 aBufLength,PRUint32 anOffset=0) const;
/**
* Perform string to float conversion.
* @param aErrorCode will contain error if one occurs
* @return float rep of string value
*/
float ToFloat(PRInt32* aErrorCode) const;
/**
* Try to derive the radix from the value contained in this string
* @return kRadix10, kRadix16 or kAutoDetect (meaning unknown)
*/
PRUint32 DetermineRadix(void);
/**
* Perform string to int conversion.
* @param aErrorCode will contain error if one occurs
* @return int rep of string value
*/
PRInt32 ToInteger(PRInt32* aErrorCode,PRUint32 aRadix=kRadix10) const;
/**********************************************************************
String manipulation methods...
*********************************************************************/
/**
* Functionally equivalent to assign or operator=
*
*/
nsString& SetString(const char* aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
nsString& SetString(const PRUnichar* aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
nsString& SetString(const nsString& aString,PRInt32 aLength=-1) {return Assign(aString,aLength);}
/**
* assign given string to this string
* @param aStr: buffer to be assigned to this
* @param alength is the length of the given str (or -1)
if you want me to determine its length
* @return this
*/
nsString& Assign(const nsStr& aString,PRInt32 aCount=-1);
nsString& Assign(const char* aString,PRInt32 aCount=-1);
nsString& Assign(const PRUnichar* aString,PRInt32 aCount=-1);
nsString& Assign(char aChar);
nsString& Assign(PRUnichar aChar);
/**
* here come a bunch of assignment operators...
* @param aString: string to be added to this
* @return this
*/
nsString& operator=(const nsString& aString) {return Assign(aString);}
nsString& operator=(const nsStr& aString) {return Assign(aString);}
nsString& operator=(char aChar) {return Assign(aChar);}
nsString& operator=(PRUnichar aChar) {return Assign(aChar);}
nsString& operator=(const char* aCString) {return Assign(aCString);}
nsString& operator=(const PRUnichar* aString) {return Assign(aString);}
#ifdef AIX
nsString& operator=(const nsSubsumeStr& aSubsumeString); // AIX requires a const here
#else
nsString& operator=(nsSubsumeStr& aSubsumeString);
#endif
/**
* Here's a bunch of methods that append varying types...
* @param various...
* @return this
*/
nsString& operator+=(const nsStr& aString){return Append(aString,aString.mLength);}
nsString& operator+=(const nsString& aString){return Append(aString,aString.mLength);}
nsString& operator+=(const char* aCString) {return Append(aCString);}
//nsString& operator+=(char aChar){return Append(aChar);}
nsString& operator+=(const PRUnichar* aUCString) {return Append(aUCString);}
nsString& operator+=(PRUnichar aChar){return Append(aChar);}
/*
* Appends n characters from given string to this,
* This version computes the length of your given string
*
* @param aString is the source to be appended to this
* @return number of chars copied
*/
nsString& Append(const nsStr& aString) {return Append(aString,aString.mLength);}
nsString& Append(const nsString& aString) {return Append(aString,aString.mLength);}
/*
* Appends n characters from given string to this,
*
* @param aString is the source to be appended to this
* @param aCount -- number of chars to copy; -1 tells us to compute the strlen for you
* @return number of chars copied
*/
nsString& Append(const nsStr& aString,PRInt32 aCount);
nsString& Append(const nsString& aString,PRInt32 aCount);
nsString& Append(const char* aString,PRInt32 aCount=-1);
nsString& Append(const PRUnichar* aString,PRInt32 aCount=-1);
nsString& Append(char aChar);
nsString& Append(PRUnichar aChar);
nsString& Append(PRInt32 aInteger,PRInt32 aRadix=10); //radix=8,10 or 16
nsString& Append(float aFloat);
/*
* Copies n characters from this string to given string,
* starting at the leftmost offset.
*
*
* @param aCopy -- Receiving string
* @param aCount -- number of chars to copy
* @return number of chars copied
*/
PRUint32 Left(nsString& aCopy,PRInt32 aCount) const;
/*
* Copies n characters from this string to given string,
* starting at the given offset.
*
*
* @param aCopy -- Receiving string
* @param aCount -- number of chars to copy
* @param anOffset -- position where copying begins
* @return number of chars copied
*/
PRUint32 Mid(nsString& aCopy,PRUint32 anOffset,PRInt32 aCount) const;
/*
* Copies n characters from this string to given string,
* starting at rightmost char.
*
*
* @param aCopy -- Receiving string
* @param aCount -- number of chars to copy
* @return number of chars copied
*/
PRUint32 Right(nsString& aCopy,PRInt32 aCount) const;
/*
* This method inserts n chars from given string into this
* string at str[anOffset].
*
* @param aCopy -- String to be inserted into this
* @param anOffset -- insertion position within this str
* @param aCount -- number of chars to be copied from aCopy
* @return number of chars inserted into this.
*/
nsString& Insert(const nsString& aCopy,PRUint32 anOffset,PRInt32 aCount=-1);
/**
* Insert a given string into this string at
* a specified offset.
*
* @param aString* to be inserted into this string
* @param anOffset is insert pos in str
* @return the number of chars inserted into this string
*/
nsString& Insert(const char* aChar,PRUint32 anOffset,PRInt32 aCount=-1);
nsString& Insert(const PRUnichar* aChar,PRUint32 anOffset,PRInt32 aCount=-1);
/**
* Insert a single char into this string at
* a specified offset.
*
* @param character to be inserted into this string
* @param anOffset is insert pos in str
* @return the number of chars inserted into this string
*/
//nsString& Insert(char aChar,PRUint32 anOffset);
nsString& Insert(PRUnichar aChar,PRUint32 anOffset);
/*
* This method is used to cut characters in this string
* starting at anOffset, continuing for aCount chars.
*
* @param anOffset -- start pos for cut operation
* @param aCount -- number of chars to be cut
* @return *this
*/
nsString& Cut(PRUint32 anOffset,PRInt32 aCount);
/**********************************************************************
Searching methods...
*********************************************************************/
/**
* Search for given character within this string.
* This method does so by using a binary search,
* so your string HAD BETTER BE ORDERED!
*
* @param aChar is the unicode char to be found
* @return offset in string, or -1 (kNotFound)
*/
PRInt32 BinarySearch(PRUnichar aChar) const;
/**
* Search for given substring within this string
*
* @param aString is substring to be sought in this
* @param aIgnoreCase selects case sensitivity
* @param anOffset tells us where in this strig to start searching
* @return offset in string, or -1 (kNotFound)
*/
PRInt32 Find(const nsString& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 Find(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 Find(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 Find(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* Search for given char within this string
*
* @param aString is substring to be sought in this
* @param anOffset tells us where in this strig to start searching
* @param aIgnoreCase selects case sensitivity
* @return find pos in string, or -1 (kNotFound)
*/
//PRInt32 Find(PRUnichar aChar,PRInt32 offset=-1,PRBool aIgnoreCase=PR_FALSE) const;
PRInt32 FindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* This method searches this string for the first character
* found in the given charset
* @param aString contains set of chars to be found
* @param anOffset tells us where to start searching in this
* @return -1 if not found, else the offset in this
*/
PRInt32 FindCharInSet(const char* aString,PRInt32 anOffset=-1) const;
PRInt32 FindCharInSet(const PRUnichar* aString,PRInt32 anOffset=-1) const;
PRInt32 FindCharInSet(const nsStr& aString,PRInt32 anOffset=-1) const;
/**
* This methods scans the string backwards, looking for the given string
* @param aString is substring to be sought in this
* @param aIgnoreCase tells us whether or not to do caseless compare
* @param anOffset tells us where in this strig to start searching (counting from left)
*/
PRInt32 RFind(const char* aCString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 RFind(const nsString& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 RFind(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* Search for given char within this string
*
* @param aString is substring to be sought in this
* @param anOffset tells us where in this strig to start searching (counting from left)
* @param aIgnoreCase selects case sensitivity
* @return find pos in string, or -1 (kNotFound)
*/
//PRInt32 RFind(PRUnichar aChar,PRInt32 offset=-1,PRBool aIgnoreCase=PR_FALSE) const;
PRInt32 RFindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1) const;
/**
* This method searches this string for the last character
* found in the given string
* @param aString contains set of chars to be found
* @param anOffset tells us where in this strig to start searching (counting from left)
* @return -1 if not found, else the offset in this
*/
PRInt32 RFindCharInSet(const char* aString,PRInt32 anOffset=-1) const;
PRInt32 RFindCharInSet(const PRUnichar* aString,PRInt32 anOffset=-1) const;
PRInt32 RFindCharInSet(const nsStr& aString,PRInt32 anOffset=-1) const;
/**********************************************************************
Comparison methods...
*********************************************************************/
/**
* Compares a given string type to this string.
* @update gess 7/27/98
* @param S is the string to be compared
* @param aIgnoreCase tells us how to treat case
* @param aCount tells us how many chars to compare
* @return -1,0,1
*/
virtual PRInt32 Compare(const nsString& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
virtual PRInt32 Compare(const nsStr &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
virtual PRInt32 Compare(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
virtual PRInt32 Compare(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
/**
* These methods compare a given string type to this one
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator==(const nsString &aString) const;
PRBool operator==(const nsStr &aString) const;
PRBool operator==(const char *aString) const;
PRBool operator==(const PRUnichar* aString) const;
/**
* These methods perform a !compare of a given string type to this
* @param aString is the string to be compared to this
* @return TRUE
*/
PRBool operator!=(const nsString &aString) const;
PRBool operator!=(const nsStr &aString) const;
PRBool operator!=(const char* aString) const;
PRBool operator!=(const PRUnichar* aString) const;
/**
* These methods test if a given string is < than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator<(const nsString &aString) const;
PRBool operator<(const nsStr &aString) const;
PRBool operator<(const char* aString) const;
PRBool operator<(const PRUnichar* aString) const;
/**
* These methods test if a given string is > than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator>(const nsString &aString) const;
PRBool operator>(const nsStr &S) const;
PRBool operator>(const char* aString) const;
PRBool operator>(const PRUnichar* aString) const;
/**
* These methods test if a given string is <= than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator<=(const nsString &aString) const;
PRBool operator<=(const nsStr &S) const;
PRBool operator<=(const char* aString) const;
PRBool operator<=(const PRUnichar* aString) const;
/**
* These methods test if a given string is >= than this
* @param aString is the string to be compared to this
* @return TRUE or FALSE
*/
PRBool operator>=(const nsString &aString) const;
PRBool operator>=(const nsStr &S) const;
PRBool operator>=(const char* aString) const;
PRBool operator>=(const PRUnichar* aString) const;
/**
* Compare this to given string; note that we compare full strings here.
* The optional length argument just lets us know how long the given string is.
* If you provide a length, it is compared to length of this string as an
* optimization.
*
* @param aString -- the string to compare to this
* @param aCount -- number of chars to be compared.
* @return TRUE if equal
*/
PRBool Equals(const nsString &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
PRBool Equals(/*FIX: const */nsIAtom* anAtom,PRBool aIgnoreCase) const;
PRBool Equals(const PRUnichar* s1, const PRUnichar* s2,PRBool aIgnoreCase=PR_FALSE) const;
PRBool EqualsIgnoreCase(const nsString& aString) const;
PRBool EqualsIgnoreCase(const char* aString,PRInt32 aCount=-1) const;
PRBool EqualsIgnoreCase(/*FIX: const */nsIAtom *aAtom) const;
PRBool EqualsIgnoreCase(const PRUnichar* s1, const PRUnichar* s2) const;
/**
* Determine if given buffer is plain ascii
*
* @param aBuffer -- if null, then we test *this, otherwise we test given buffer
* @return TRUE if is all ascii chars or if strlen==0
*/
PRBool IsASCII(const PRUnichar* aBuffer=0);
/**
* Determine if given char is a valid space character
*
* @param aChar is character to be tested
* @return TRUE if is valid space char
*/
static PRBool IsSpace(PRUnichar ch);
/**
* Determine if given char in valid alpha range
*
* @param aChar is character to be tested
* @return TRUE if in alpha range
*/
static PRBool IsAlpha(PRUnichar ch);
/**
* Determine if given char is valid digit
*
* @param aChar is character to be tested
* @return TRUE if char is a valid digit
*/
static PRBool IsDigit(PRUnichar ch);
static void Recycle(nsString* aString);
static nsString* CreateString(void);
};
extern NS_COM int fputs(const nsString& aString, FILE* out);
//ostream& operator<<(ostream& aStream,const nsString& aString);
//virtual void DebugDump(ostream& aStream) const;
/**************************************************************
Here comes the AutoString class which uses internal memory
(typically found on the stack) for its default buffer.
If the buffer needs to grow, it gets reallocated on the heap.
**************************************************************/
class NS_COM nsAutoString : public nsString {
public:
nsAutoString();
nsAutoString(const char* aCString,PRInt32 aLength=-1);
nsAutoString(const PRUnichar* aString,PRInt32 aLength=-1);
nsAutoString(const CBufDescriptor& aBuffer);
nsAutoString(const nsStr& aString);
nsAutoString(const nsAutoString& aString);
#ifdef AIX
nsAutoString(const nsSubsumeStr& aSubsumeStr); // AIX requires a const
#else
nsAutoString(nsSubsumeStr& aSubsumeStr);
#endif // AIX
nsAutoString(PRUnichar aChar);
virtual ~nsAutoString();
nsAutoString& operator=(const nsStr& aString) {nsString::Assign(aString); return *this;}
nsAutoString& operator=(const nsAutoString& aString) {nsString::Assign(aString); return *this;}
nsAutoString& operator=(const char* aCString) {nsString::Assign(aCString); return *this;}
nsAutoString& operator=(char aChar) {nsString::Assign(aChar); return *this;}
nsAutoString& operator=(const PRUnichar* aBuffer) {nsString::Assign(aBuffer); return *this;}
nsAutoString& operator=(PRUnichar aChar) {nsString::Assign(aChar); return *this;}
/**
* Retrieve the size of this string
* @return string length
*/
virtual void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
char mBuffer[kDefaultStringSize<<eTwoByte];
};
/***************************************************************
The subsumestr class is very unusual.
It differs from a normal string in that it doesn't use normal
copy semantics when another string is assign to this.
Instead, it "steals" the contents of the source string.
This is very handy for returning nsString classes as part of
an operator+(...) for example, in that it cuts down the number
of copy operations that must occur.
You should probably not use this class unless you really know
what you're doing.
***************************************************************/
class NS_COM nsSubsumeStr : public nsString {
public:
nsSubsumeStr(nsStr& aString);
nsSubsumeStr(PRUnichar* aString,PRBool assumeOwnership,PRInt32 aLength=-1);
nsSubsumeStr(char* aString,PRBool assumeOwnership,PRInt32 aLength=-1);
};
#endif

View File

@@ -1,179 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsDebug.h"
#include "nsIAllocator.h"
#include "nsXPIDLString.h"
#include "plstr.h"
// If the allocator changes, fix it here.
#define XPIDL_STRING_ALLOC(__len) ((PRUnichar*) nsAllocator::Alloc((__len) * sizeof(PRUnichar)))
#define XPIDL_CSTRING_ALLOC(__len) ((char*) nsAllocator::Alloc((__len) * sizeof(char)))
#define XPIDL_FREE(__ptr) (nsAllocator::Free(__ptr))
////////////////////////////////////////////////////////////////////////
// nsXPIDLString
nsXPIDLString::nsXPIDLString()
: mBuf(0),
mBufOwner(PR_FALSE)
{
}
nsXPIDLString::~nsXPIDLString()
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
}
nsXPIDLString::operator const PRUnichar*()
{
return mBuf;
}
PRUnichar*
nsXPIDLString::Copy(const PRUnichar* aString)
{
NS_ASSERTION(aString, "null ptr");
if (! aString)
return 0;
PRInt32 len = 0;
{
const PRUnichar* p = aString;
while (*p++)
len++;
}
PRUnichar* result = XPIDL_STRING_ALLOC(len + 1);
if (result) {
PRUnichar* q = result;
while (*aString) {
*q = *aString;
q++;
aString++;
}
*q = '\0';
}
return result;
}
PRUnichar**
nsXPIDLString::StartAssignmentByValue()
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
mBuf = 0;
mBufOwner = PR_TRUE;
return &mBuf;
}
const PRUnichar**
nsXPIDLString::StartAssignmentByReference()
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
mBuf = 0;
mBufOwner = PR_FALSE;
return (const PRUnichar**) &mBuf;
}
////////////////////////////////////////////////////////////////////////
// nsXPIDLCString
nsXPIDLCString::nsXPIDLCString()
: mBuf(0),
mBufOwner(PR_FALSE)
{
}
nsXPIDLCString::~nsXPIDLCString()
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
}
nsXPIDLCString& nsXPIDLCString::operator =(const char* aCString)
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
mBuf = Copy(aCString);
mBufOwner = PR_TRUE;
return *this;
}
nsXPIDLCString::operator const char*()
{
return mBuf;
}
char*
nsXPIDLCString::Copy(const char* aCString)
{
NS_ASSERTION(aCString, "null ptr");
if (! aCString)
return 0;
PRInt32 len = PL_strlen(aCString);
char* result = XPIDL_CSTRING_ALLOC(len + 1);
if (result)
PL_strcpy(result, aCString);
return result;
}
char**
nsXPIDLCString::StartAssignmentByValue()
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
mBuf = 0;
mBufOwner = PR_TRUE;
return &mBuf;
}
const char**
nsXPIDLCString::StartAssignmentByReference()
{
if (mBufOwner && mBuf)
XPIDL_FREE(mBuf);
mBuf = 0;
mBufOwner = PR_FALSE;
return (const char**) &mBuf;
}

View File

@@ -1,302 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
A set of string wrapper classes that ease transition to use of XPIDL
interfaces. nsXPIDLString and nsXPIDLCString are to XPIDL `wstring'
and `string' out params as nsCOMPtr is to generic XPCOM interface
pointers. They help you deal with object ownership.
Consider the following interface:
interface nsIFoo {
attribute string Bar;
};
This will generate the following C++ header file:
class nsIFoo {
NS_IMETHOD SetBar(const PRUnichar* aValue);
NS_IMETHOD GetBar(PRUnichar* *aValue);
};
The GetBar() method will allocate a copy of the nsIFoo object's
"bar" attribute, and leave you to deal with freeing it:
nsIFoo* aFoo; // assume we get this somehow
PRUnichar* bar;
aFoo->GetFoo(&bar);
// Use bar here...
printf("bar is %s!\n", bar);
nsAllocator::Free(bar);
This makes your life harder, because you need to convolute your code
to ensure that you don't leak `bar'.
Enter nsXPIDLString, which manages the ownership of the allocated
string, and automatically destroys it when the nsXPIDLString goes
out of scope:
nsIFoo* aFoo;
nsXPIDLString bar;
aFoo->GetFoo( getter_Copies(bar) );
// Use bar here...
printf("bar is %s!\n", (const char*) bar);
// no need to remember to nsAllocator::Free().
Like nsCOMPtr, nsXPIDLString uses some syntactic sugar to make it
painfully clear exactly what the code expects. You need to wrap an
nsXPIDLString object with either `getter_Copies()' or
`getter_Shares()' before passing it to a getter: these tell the
nsXPIDLString how ownership is being handled.
In the case of `getter_Copies()', the callee is allocating a copy
(which is usually the case). In the case of `getter_Shares()', the
callee is returning a const reference to `the real deal' (this can
be done using the [shared] attribute in XPIDL).
*/
#ifndef nsXPIDLString_h__
#define nsXPIDLString_h__
#include "nsCom.h"
#include "prtypes.h"
#ifndef __PRUNICHAR__
#define __PRUNICHAR__
typedef PRUint16 PRUnichar;
#endif /* __PRUNICHAR__ */
////////////////////////////////////////////////////////////////////////
// nsXPIDLString
//
// A wrapper for Unicode strings. With the |getter_Copies()| and
// |getter_Shares()| helper functions, this can be used instead of
// the "naked" |PRUnichar*| interface for |wstring| parameters in
// XPIDL interfaces.
//
class NS_COM nsXPIDLString {
private:
PRUnichar* mBuf;
PRBool mBufOwner;
PRUnichar** StartAssignmentByValue();
const PRUnichar** StartAssignmentByReference();
public:
/**
* Construct a new, uninitialized wrapper for a Unicode string.
*/
nsXPIDLString();
virtual ~nsXPIDLString();
/**
* Return a reference to the immutable Unicode string.
*/
operator const PRUnichar*();
/**
* Make a copy of the Unicode string. Use this function in the
* callee to ensure that the correct memory allocator is used.
*/
static PRUnichar* Copy(const PRUnichar* aString);
// A helper class for assignment-by-value. This class is an
// implementation detail and should not be considered part of the
// public interface.
class NS_COM GetterCopies {
private:
nsXPIDLString& mXPIDLString;
public:
GetterCopies(nsXPIDLString& aXPIDLString)
: mXPIDLString(aXPIDLString) {}
operator PRUnichar**() {
return mXPIDLString.StartAssignmentByValue();
}
friend GetterCopies getter_Copies(nsXPIDLString& aXPIDLString);
};
friend class GetterCopies;
// A helper class for assignment-by-reference. This class is an
// implementation detail and should not be considered part of the
// public interface.
class NS_COM GetterShares {
private:
nsXPIDLString& mXPIDLString;
public:
GetterShares(nsXPIDLString& aXPIDLString)
: mXPIDLString(aXPIDLString) {}
operator const PRUnichar**() {
return mXPIDLString.StartAssignmentByReference();
}
friend GetterShares getter_Shares(nsXPIDLString& aXPIDLString);
};
friend class GetterShares;
private:
// not to be implemented
nsXPIDLString(nsXPIDLString& /* aXPIDLString */) {}
nsXPIDLString& operator =(nsXPIDLString& /* aXPIDLString */) { return *this; }
};
/**
* Use this function to "wrap" the nsXPIDLString object that is to
* receive an |out| value.
*/
inline nsXPIDLString::GetterCopies
getter_Copies(nsXPIDLString& aXPIDLString)
{
return nsXPIDLString::GetterCopies(aXPIDLString);
}
/**
* Use this function to "wrap" the nsXPIDLString object that is to
* receive a |[shared] out| value.
*/
inline nsXPIDLString::GetterShares
getter_Shares(nsXPIDLString& aXPIDLString)
{
return nsXPIDLString::GetterShares(aXPIDLString);
}
////////////////////////////////////////////////////////////////////////
// nsXPIDLCString
//
// A wrapper for Unicode strings. With the |getter_Copies()| and
// |getter_Shares()| helper functions, this can be used instead of
// the "naked" |char*| interface for |string| parameters in XPIDL
// interfaces.
//
class NS_COM nsXPIDLCString {
private:
char* mBuf;
PRBool mBufOwner;
char** StartAssignmentByValue();
const char** StartAssignmentByReference();
public:
/**
* Construct a new, uninitialized wrapper for a single-byte string.
*/
nsXPIDLCString();
virtual ~nsXPIDLCString();
/**
* Assign a single-byte string to this wrapper. Copies and owns the result.
*/
nsXPIDLCString& operator =(const char* aString);
/**
* Return a reference to the immutable single-byte string.
*/
operator const char*();
/**
* Make a copy of the single-byte string. Use this function in the
* callee to ensure that the correct memory allocator is used.
*/
static char* Copy(const char* aString);
// A helper class for assignment-by-value. This class is an
// implementation detail and should not be considered part of the
// public interface.
class NS_COM GetterCopies {
private:
nsXPIDLCString& mXPIDLString;
public:
GetterCopies(nsXPIDLCString& aXPIDLString)
: mXPIDLString(aXPIDLString) {}
operator char**() {
return mXPIDLString.StartAssignmentByValue();
}
friend GetterCopies getter_Copies(nsXPIDLCString& aXPIDLString);
};
friend class GetterCopies;
// A helper class for assignment-by-reference. This class is an
// implementation detail and should not be considered part of the
// public interface.
class NS_COM GetterShares {
private:
nsXPIDLCString& mXPIDLString;
public:
GetterShares(nsXPIDLCString& aXPIDLString)
: mXPIDLString(aXPIDLString) {}
operator const char**() {
return mXPIDLString.StartAssignmentByReference();
}
friend GetterShares getter_Shares(nsXPIDLCString& aXPIDLString);
};
friend class GetterShares;
private:
// not to be implemented
nsXPIDLCString(nsXPIDLCString& /* aXPIDLString */) {}
nsXPIDLCString& operator =(nsXPIDLCString& /* aXPIDLCString */) { return *this; }
};
/**
* Use this function to "wrap" the nsXPIDLCString object that is to
* receive an |out| value.
*/
inline nsXPIDLCString::GetterCopies
getter_Copies(nsXPIDLCString& aXPIDLString)
{
return nsXPIDLCString::GetterCopies(aXPIDLString);
}
/**
* Use this function to "wrap" the nsXPIDLCString object that is to
* receive a |[shared] out| value.
*/
inline nsXPIDLCString::GetterShares
getter_Shares(nsXPIDLCString& aXPIDLString)
{
return nsXPIDLCString::GetterShares(aXPIDLString);
}
#endif // nsXPIDLString_h__

View File

@@ -1,30 +0,0 @@
nsAVLTree.h
nsCppSharedAllocator.h
nsCRT.h
nsDeque.h
nsEnumeratorUtils.h
nsHashtable.h
nsHashtableEnumerator.h
nsIArena.h
nsIBuffer.h
nsIByteBuffer.h
nsIObserverList.h
nsIPageManager.h
nsIProperties.h
nsISimpleEnumerator.h
nsISizeOfHandler.h
nsIUnicharBuffer.h
nsIVariant.h
nsInt64.h
nsQuickSort.h
nsStr.h
nsString.h
nsString2.h
nsSupportsPrimitives.h
nsTime.h
nsUnitConversion.h
nsVector.h
nsVoidArray.h
nsXPIDLString.h
plvector.h
nsTextFormater.h

View File

@@ -1,6 +0,0 @@
nsIAtom.idl
nsICollection.idl
nsIEnumerator.idl
nsIObserver.idl
nsIObserverService.idl
nsISupportsArray.idl

View File

@@ -1,113 +0,0 @@
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = xpcom
XPIDL_MODULE = xpcom_ds
LIBRARY_NAME = xpcomds_s
REQUIRES = xpcom uconv unicharutil
CPPSRCS = \
nsArena.cpp \
nsAtomTable.cpp \
nsAVLTree.cpp \
nsByteBuffer.cpp \
nsCRT.cpp \
nsConjoiningEnumerator.cpp \
nsDeque.cpp \
nsEmptyEnumerator.cpp \
nsEnumeratorUtils.cpp \
nsHashtable.cpp \
nsHashtableEnumerator.cpp \
nsObserver.cpp \
nsObserverList.cpp \
nsObserverService.cpp \
nsProperties.cpp \
nsQuickSort.cpp \
nsSizeOfHandler.cpp \
nsStr.cpp \
nsString.cpp \
nsString2.cpp \
nsSupportsArray.cpp \
nsSupportsArrayEnumerator.cpp \
nsSupportsPrimitives.cpp \
nsUnicharBuffer.cpp \
nsVariant.cpp \
nsVoidArray.cpp \
nsXPIDLString.cpp \
plvector.cpp \
nsTextFormater.cpp \
$(NULL)
EXPORTS = \
nsAVLTree.h \
nsCppSharedAllocator.h \
nsCRT.h \
nsDeque.h \
nsEnumeratorUtils.h \
nsHashtable.h \
nsHashtableEnumerator.h \
nsIArena.h \
nsIByteBuffer.h \
nsIObserverList.h \
nsIProperties.h \
nsISimpleEnumerator.h \
nsISizeOfHandler.h \
nsIUnicharBuffer.h \
nsIVariant.h \
nsInt64.h \
nsQuickSort.h \
nsStr.h \
nsString.h \
nsString2.h \
nsSupportsPrimitives.h \
nsTime.h \
nsUnitConversion.h \
nsVector.h \
nsVoidArray.h \
nsXPIDLString.h \
plvector.h \
nsTextFormater.h \
$(NULL)
XPIDLSRCS = \
nsIAtom.idl \
nsICollection.idl \
nsIEnumerator.idl \
nsIObserver.idl \
nsIObserverService.idl \
nsISupportsArray.idl \
nsISupportsPrimitives.idl \
$(NULL)
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
# we don't want the shared lib, but we want to force the creation of a static lib.
override NO_SHARED_LIB=1
override NO_STATIC_LIB=
include $(topsrcdir)/config/rules.mk
DEFINES += -D_IMPL_NS_COM -D_IMPL_NS_BASE

View File

@@ -1,758 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/******************************************************************************************
MODULE NOTES:
This file contains the workhorse copy and shift functions used in nsStrStruct.
Ultimately, I plan to make the function pointers in this system available for
use by external modules. They'll be able to install their own "handlers".
Not so, today though.
*******************************************************************************************/
#ifndef _BUFFERROUTINES_H
#define _BUFFERROUTINES_H
#include "nsCRT.h"
#ifndef RICKG_TESTBED
#include "nsUnicharUtilCIID.h"
#include "nsIServiceManager.h"
#include "nsICaseConversion.h"
#endif
#define KSHIFTLEFT (0)
#define KSHIFTRIGHT (1)
inline PRUnichar GetUnicharAt(const char* aString,PRUint32 anIndex) {
return ((PRUnichar*)aString)[anIndex];
}
inline PRUnichar GetCharAt(const char* aString,PRUint32 anIndex) {
return (PRUnichar)aString[anIndex];
}
//----------------------------------------------------------------------------------------
//
// This set of methods is used to shift the contents of a char buffer.
// The functions are differentiated by shift direction and the underlying charsize.
//
/**
* This method shifts single byte characters left by a given amount from an given offset.
* @update gess 01/04/99
* @param aDest is a ptr to a cstring where left-shift is to be performed
* @param aLength is the known length of aDest
* @param anOffset is the index into aDest where shifting shall begin
* @param aCount is the number of chars to be "cut"
*/
void ShiftCharsLeft(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
char* dst = aDest+anOffset;
char* src = aDest+anOffset+aCount;
memmove(dst,src,aLength-(aCount+anOffset));
}
/**
* This method shifts single byte characters right by a given amount from an given offset.
* @update gess 01/04/99
* @param aDest is a ptr to a cstring where the shift is to be performed
* @param aLength is the known length of aDest
* @param anOffset is the index into aDest where shifting shall begin
* @param aCount is the number of chars to be "inserted"
*/
void ShiftCharsRight(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
char* src = aDest+anOffset;
char* dst = aDest+anOffset+aCount;
memmove(dst,src,aLength-anOffset);
}
/**
* This method shifts unicode characters by a given amount from an given offset.
* @update gess 01/04/99
* @param aDest is a ptr to a cstring where the shift is to be performed
* @param aLength is the known length of aDest
* @param anOffset is the index into aDest where shifting shall begin
* @param aCount is the number of chars to be "cut"
*/
void ShiftDoubleCharsLeft(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
PRUnichar* root=(PRUnichar*)aDest;
PRUnichar* dst = root+anOffset;
PRUnichar* src = root+anOffset+aCount;
memmove(dst,src,(aLength-(aCount+anOffset))*sizeof(PRUnichar));
}
/**
* This method shifts unicode characters by a given amount from an given offset.
* @update gess 01/04/99
* @param aDest is a ptr to a cstring where the shift is to be performed
* @param aLength is the known length of aDest
* @param anOffset is the index into aDest where shifting shall begin
* @param aCount is the number of chars to be "inserted"
*/
void ShiftDoubleCharsRight(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount) {
PRUnichar* root=(PRUnichar*)aDest;
PRUnichar* src = root+anOffset;
PRUnichar* dst = root+anOffset+aCount;
memmove(dst,src,sizeof(PRUnichar)*(aLength-anOffset));
}
typedef void (*ShiftChars)(char* aDest,PRUint32 aLength,PRUint32 anOffset,PRUint32 aCount);
ShiftChars gShiftChars[2][2]= {
{&ShiftCharsLeft,&ShiftCharsRight},
{&ShiftDoubleCharsLeft,&ShiftDoubleCharsRight}
};
//----------------------------------------------------------------------------------------
//
// This set of methods is used to copy one buffer onto another.
// The functions are differentiated by the size of source and dest character sizes.
// WARNING: Your destination buffer MUST be big enough to hold all the source bytes.
// We don't validate these ranges here (this should be done in higher level routines).
//
/**
* Going 1 to 1 is easy, since we assume ascii. No conversions are necessary.
* @update gess 01/04/99
* @param aDest is the destination buffer
* @param aDestOffset is the pos to start copy to in the dest buffer
* @param aSource is the source buffer
* @param anOffset is the offset to start copying from in the source buffer
* @param aCount is the (max) number of chars to copy
*/
void CopyChars1To1(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
char* dst = aDest+anDestOffset;
char* src = (char*)aSource+anOffset;
memcpy(dst,src,aCount);
}
/**
* Going 1 to 2 requires a conversion from ascii to unicode. This can be expensive.
* @param aDest is the destination buffer
* @param aDestOffset is the pos to start copy to in the dest buffer
* @param aSource is the source buffer
* @param anOffset is the offset to start copying from in the source buffer
* @param aCount is the (max) number of chars to copy
*/
void CopyChars1To2(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
PRUnichar* theDest=(PRUnichar*)aDest;
PRUnichar* to = theDest+anDestOffset;
const unsigned char* first= (const unsigned char*)aSource+anOffset;
const unsigned char* last = first+aCount;
//now loop over characters, shifting them left...
while(first<last) {
*to=(PRUnichar)(*first);
to++;
first++;
}
}
/**
* Going 2 to 1 requires a conversion from unicode down to ascii. This can be lossy.
* @update gess 01/04/99
* @param aDest is the destination buffer
* @param aDestOffset is the pos to start copy to in the dest buffer
* @param aSource is the source buffer
* @param anOffset is the offset to start copying from in the source buffer
* @param aCount is the (max) number of chars to copy
*/
void CopyChars2To1(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
char* to = aDest+anDestOffset;
PRUnichar* theSource=(PRUnichar*)aSource;
const PRUnichar* first= theSource+anOffset;
const PRUnichar* last = first+aCount;
//now loop over characters, shifting them left...
while(first<last) {
if(*first<256)
*to=(char)*first;
else *to='.';
to++;
first++;
}
}
/**
* Going 2 to 2 is fast and efficient.
* @update gess 01/04/99
* @param aDest is the destination buffer
* @param aDestOffset is the pos to start copy to in the dest buffer
* @param aSource is the source buffer
* @param anOffset is the offset to start copying from in the source buffer
* @param aCount is the (max) number of chars to copy
*/
void CopyChars2To2(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount) {
PRUnichar* theDest=(PRUnichar*)aDest;
PRUnichar* to = theDest+anDestOffset;
PRUnichar* theSource=(PRUnichar*)aSource;
PRUnichar* from= theSource+anOffset;
memcpy((void*)to,(void*)from,aCount*sizeof(PRUnichar));
}
//--------------------------------------------------------------------------------------
typedef void (*CopyChars)(char* aDest,PRInt32 anDestOffset,const char* aSource,PRUint32 anOffset,PRUint32 aCount);
CopyChars gCopyChars[2][2]={
{&CopyChars1To1,&CopyChars1To2},
{&CopyChars2To1,&CopyChars2To2}
};
//----------------------------------------------------------------------------------------
//
// This set of methods is used to search a buffer looking for a char.
//
/**
* This methods cans the given buffer for the given char
*
* @update gess 3/25/98
* @param aDest is the buffer to be searched
* @param aLength is the size (in char-units, not bytes) of the buffer
* @param anOffset is the start pos to begin searching
* @param aChar is the target character we're looking for
* @param aIgnorecase tells us whether to use a case sensitive search
* @return index of pos if found, else -1 (kNotFound)
*/
inline PRInt32 FindChar1(const char* aDest,PRUint32 aLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
if(aIgnoreCase) {
char theChar=(char)nsCRT::ToUpper(aChar);
const char* ptr=aDest+(anOffset-1);
const char* last=aDest+aLength;
while(++ptr<last){
if(nsCRT::ToUpper(*ptr)==theChar)
return ptr-aDest;
}
}
else {
const char* ptr = aDest+anOffset;
char theChar=(char)aChar;
const char* result=(const char*)memchr(ptr, theChar,aLength-anOffset);
if(result) {
return result-aDest;
}
}
return kNotFound;
}
/**
* This methods cans the given buffer for the given char
*
* @update gess 3/25/98
* @param aDest is the buffer to be searched
* @param aLength is the size (in char-units, not bytes) of the buffer
* @param anOffset is the start pos to begin searching
* @param aChar is the target character we're looking for
* @param aIgnorecase tells us whether to use a case sensitive search
* @return index of pos if found, else -1 (kNotFound)
*/
inline PRInt32 FindChar2(const char* aDest,PRUint32 aLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
const PRUnichar* root=(PRUnichar*)aDest;
const PRUnichar* ptr=root+(anOffset-1);
const PRUnichar* last=root+aLength;
if(aIgnoreCase) {
PRUnichar theChar=nsCRT::ToUpper(aChar);
while(++ptr<last){
if(nsCRT::ToUpper(*ptr)==theChar)
return ptr-root;
}
}
else {
while(++ptr<last){
if(*ptr==aChar)
return (ptr-root);
}
}
return kNotFound;
}
/**
* This methods cans the given buffer (in reverse) for the given char
*
* @update gess 3/25/98
* @param aDest is the buffer to be searched
* @param aLength is the size (in char-units, not bytes) of the buffer
* @param anOffset is the start pos to begin searching
* @param aChar is the target character we're looking for
* @param aIgnorecase tells us whether to use a case sensitive search
* @return index of pos if found, else -1 (kNotFound)
*/
inline PRInt32 RFindChar1(const char* aDest,PRUint32 aDestLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
PRInt32 theIndex=0;
if(aIgnoreCase) {
PRUnichar theChar=nsCRT::ToUpper(aChar);
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
if(nsCRT::ToUpper(aDest[theIndex])==theChar)
return theIndex;
}
}
else {
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
if(aDest[theIndex]==aChar)
return theIndex;
}
}
return kNotFound;
}
/**
* This methods cans the given buffer for the given char
*
* @update gess 3/25/98
* @param aDest is the buffer to be searched
* @param aLength is the size (in char-units, not bytes) of the buffer
* @param anOffset is the start pos to begin searching
* @param aChar is the target character we're looking for
* @param aIgnorecase tells us whether to use a case sensitive search
* @return index of pos if found, else -1 (kNotFound)
*/
inline PRInt32 RFindChar2(const char* aDest,PRUint32 aDestLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase) {
PRInt32 theIndex=0;
PRUnichar* theBuf=(PRUnichar*)aDest;
if(aIgnoreCase) {
PRUnichar theChar=nsCRT::ToUpper(aChar);
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
if(nsCRT::ToUpper(theBuf[theIndex])==theChar)
return theIndex;
}
}
else {
for(theIndex=(PRInt32)anOffset;theIndex>=0;theIndex--){
if(theBuf[theIndex]==aChar)
return theIndex;
}
}
return kNotFound;
}
typedef PRInt32 (*FindChars)(const char* aDest,PRUint32 aDestLength,PRUint32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase);
FindChars gFindChars[]={&FindChar1,&FindChar2};
FindChars gRFindChars[]={&RFindChar1,&RFindChar2};
//----------------------------------------------------------------------------------------
//
// This set of methods is used to compare one buffer onto another.
// The functions are differentiated by the size of source and dest character sizes.
// WARNING: Your destination buffer MUST be big enough to hold all the source bytes.
// We don't validate these ranges here (this should be done in higher level routines).
//
/**
* This method compares the data in one buffer with another
* @update gess 01/04/99
* @param aStr1 is the first buffer to be compared
* @param aStr2 is the 2nd buffer to be compared
* @param aCount is the number of chars to compare
* @param aIgnorecase tells us whether to use a case-sensitive comparison
* @return -1,0,1 depending on <,==,>
*/
PRInt32 Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
PRInt32 result=0;
if(aIgnoreCase)
result=nsCRT::strncasecmp(aStr1,aStr2,aCount);
else result=strncmp(aStr1,aStr2,aCount);
return result;
}
/**
* This method compares the data in one buffer with another
* @update gess 01/04/99
* @param aStr1 is the first buffer to be compared
* @param aStr2 is the 2nd buffer to be compared
* @param aCount is the number of chars to compare
* @param aIgnorecase tells us whether to use a case-sensitive comparison
* @return -1,0,1 depending on <,==,>
*/
PRInt32 Compare2To2(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
PRInt32 result=0;
if(aIgnoreCase)
result=nsCRT::strncasecmp((PRUnichar*)aStr1,(PRUnichar*)aStr2,aCount);
else result=nsCRT::strncmp((PRUnichar*)aStr1,(PRUnichar*)aStr2,aCount);
return result;
}
/**
* This method compares the data in one buffer with another
* @update gess 01/04/99
* @param aStr1 is the first buffer to be compared
* @param aStr2 is the 2nd buffer to be compared
* @param aCount is the number of chars to compare
* @param aIgnorecase tells us whether to use a case-sensitive comparison
* @return -1,0,1 depending on <,==,>
*/
PRInt32 Compare2To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
PRInt32 result;
if(aIgnoreCase)
result=nsCRT::strncasecmp((PRUnichar*)aStr1,aStr2,aCount);
else result=nsCRT::strncmp((PRUnichar*)aStr1,aStr2,aCount);
return result;
}
/**
* This method compares the data in one buffer with another
* @update gess 01/04/99
* @param aStr1 is the first buffer to be compared
* @param aStr2 is the 2nd buffer to be compared
* @param aCount is the number of chars to compare
* @param aIgnorecase tells us whether to use a case-sensitive comparison
* @return -1,0,1 depending on <,==,>
*/
PRInt32 Compare1To2(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
PRInt32 result;
if(aIgnoreCase)
result=nsCRT::strncasecmp((PRUnichar*)aStr2,aStr1,aCount)*-1;
else result=nsCRT::strncmp((PRUnichar*)aStr2,aStr1,aCount)*-1;
return result;
}
typedef PRInt32 (*CompareChars)(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase);
CompareChars gCompare[2][2]={
{&Compare1To1,&Compare1To2},
{&Compare2To1,&Compare2To2},
};
//----------------------------------------------------------------------------------------
//
// This set of methods is used to convert the case of strings...
//
/**
* This method performs a case conversion the data in the given buffer
*
* @update gess 01/04/99
* @param aString is the buffer to be case shifted
* @param aCount is the number of chars to compare
* @param aToUpper tells us whether to convert to upper or lower
* @return 0
*/
PRInt32 ConvertCase1(char* aString,PRUint32 aCount,PRBool aToUpper){
PRInt32 result=0;
typedef char chartype;
chartype* cp = (chartype*)aString;
chartype* end = cp + aCount-1;
while (cp <= end) {
chartype ch = *cp;
if(aToUpper) {
if ((ch >= 'a') && (ch <= 'z')) {
*cp = 'A' + (ch - 'a');
}
}
else {
if ((ch >= 'A') && (ch <= 'Z')) {
*cp = 'a' + (ch - 'A');
}
}
cp++;
}
return result;
}
//----------------------------------------------------------------------------------------
#ifndef RICKG_TESTBED
class HandleCaseConversionShutdown3 : public nsIShutdownListener {
public :
NS_IMETHOD OnShutdown(const nsCID& cid, nsISupports* service);
HandleCaseConversionShutdown3(void) { NS_INIT_REFCNT(); }
virtual ~HandleCaseConversionShutdown3(void) {}
NS_DECL_ISUPPORTS
};
static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
static NS_DEFINE_IID(kICaseConversionIID, NS_ICASECONVERSION_IID);
static NS_DEFINE_IID(kIShutdownListenerIID, NS_ISHUTDOWNLISTENER_IID);
static nsICaseConversion * gCaseConv = 0;
NS_IMPL_ISUPPORTS(HandleCaseConversionShutdown3, kIShutdownListenerIID);
nsresult HandleCaseConversionShutdown3::OnShutdown(const nsCID& cid, nsISupports* service) {
if (cid.Equals(kUnicharUtilCID)) {
NS_ASSERTION(service == gCaseConv, "wrong service!");
if(gCaseConv){
gCaseConv->Release();
gCaseConv = 0;
}
}
return NS_OK;
}
class CCaseConversionServiceInitializer {
public:
CCaseConversionServiceInitializer(){
mListener = new HandleCaseConversionShutdown3();
if(mListener){
mListener->AddRef();
nsServiceManager::GetService(kUnicharUtilCID, kICaseConversionIID,(nsISupports**) &gCaseConv, mListener);
}
}
protected:
HandleCaseConversionShutdown3* mListener;
};
#endif
//----------------------------------------------------------------------------------------
/**
* This method performs a case conversion the data in the given buffer
*
* @update gess 01/04/99
* @param aString is the buffer to be case shifted
* @param aCount is the number of chars to compare
* @param aToUpper tells us whether to convert to upper or lower
* @return 0
*/
PRInt32 ConvertCase2(char* aString,PRUint32 aCount,PRBool aToUpper){
PRUnichar* cp = (PRUnichar*)aString;
PRUnichar* end = cp + aCount-1;
PRInt32 result=0;
#ifndef RICKG_TESTBED
static CCaseConversionServiceInitializer gCaseConversionServiceInitializer;
// I18N code begin
if(gCaseConv) {
nsresult err=(aToUpper) ? gCaseConv->ToUpper(cp, cp, aCount) : gCaseConv->ToLower(cp, cp, aCount);
if(NS_SUCCEEDED(err))
return 0;
}
// I18N code end
#endif
while (cp <= end) {
PRUnichar ch = *cp;
if(aToUpper) {
if ((ch >= 'a') && (ch <= 'z')) {
*cp = 'A' + (ch - 'a');
}
}
else {
if ((ch >= 'A') && (ch <= 'Z')) {
*cp = 'a' + (ch - 'A');
}
}
cp++;
}
return result;
}
typedef PRInt32 (*CaseConverters)(char*,PRUint32,PRBool);
CaseConverters gCaseConverters[]={&ConvertCase1,&ConvertCase2};
//----------------------------------------------------------------------------------------
//
// This set of methods is used compress char sequences in a buffer...
//
/**
* This method compresses duplicate runs of a given char from the given buffer
*
* @update gess 01/04/99
* @param aString is the buffer to be manipulated
* @param aLength is the length of the buffer
* @param aSet tells us which chars to compress from given buffer
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
* @return the new length of the given buffer
*/
PRInt32 CompressChars1(char* aString,PRUint32 aLength,const char* aSet){
typedef char chartype;
chartype* from = aString;
chartype* end = aString + aLength-1;
chartype* to = from;
//this code converts /n, /t, /r into normal space ' ';
//it also compresses runs of whitespace down to a single char...
if(aSet && aString && (0 < aLength)){
PRUint32 aSetLen=strlen(aSet);
while (from <= end) {
chartype theChar = *from++;
if(kNotFound!=FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
*to++=theChar;
while (from <= end) {
theChar = *from++;
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
*to++ = theChar;
break;
}
}
} else {
*to++ = theChar;
}
}
*to = 0;
}
return to - (chartype*)aString;
}
/**
* This method compresses duplicate runs of a given char from the given buffer
*
* @update gess 01/04/99
* @param aString is the buffer to be manipulated
* @param aLength is the length of the buffer
* @param aSet tells us which chars to compress from given buffer
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
* @return the new length of the given buffer
*/
PRInt32 CompressChars2(char* aString,PRUint32 aLength,const char* aSet){
typedef PRUnichar chartype;
chartype* from = (chartype*)aString;
chartype* end = from + aLength-1;
chartype* to = from;
//this code converts /n, /t, /r into normal space ' ';
//it also compresses runs of whitespace down to a single char...
if(aSet && aString && (0 < aLength)){
PRUint32 aSetLen=strlen(aSet);
while (from <= end) {
chartype theChar = *from++;
if(kNotFound!=FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
*to++=theChar;
while (from <= end) {
theChar = *from++;
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
*to++ = theChar;
break;
}
}
} else {
*to++ = theChar;
}
}
*to = 0;
}
return to - (chartype*)aString;
}
typedef PRInt32 (*CompressChars)(char* aString,PRUint32 aCount,const char* aSet);
CompressChars gCompressChars[]={&CompressChars1,&CompressChars2};
/**
* This method strips chars in a given set from the given buffer
*
* @update gess 01/04/99
* @param aString is the buffer to be manipulated
* @param aLength is the length of the buffer
* @param aSet tells us which chars to compress from given buffer
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
* @return the new length of the given buffer
*/
PRInt32 StripChars1(char* aString,PRUint32 aLength,const char* aSet){
typedef char chartype;
chartype* to = aString;
chartype* from = aString-1;
chartype* end = aString + aLength;
if(aSet && aString && (0 < aLength)){
PRUint32 aSetLen=strlen(aSet);
while (++from < end) {
chartype theChar = *from;
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
*to++ = theChar;
}
}
*to = 0;
}
return to - (chartype*)aString;
}
/**
* This method strips chars in a given set from the given buffer
*
* @update gess 01/04/99
* @param aString is the buffer to be manipulated
* @param aLength is the length of the buffer
* @param aSet tells us which chars to compress from given buffer
* @param aEliminateLeading tells us whether to strip chars from the start of the buffer
* @param aEliminateTrailing tells us whether to strip chars from the start of the buffer
* @return the new length of the given buffer
*/
PRInt32 StripChars2(char* aString,PRUint32 aLength,const char* aSet){
typedef PRUnichar chartype;
chartype* to = (chartype*)aString;
chartype* from = (chartype*)aString-1;
chartype* end = to + aLength;
if(aSet && aString && (0 < aLength)){
PRUint32 aSetLen=strlen(aSet);
while (++from < end) {
chartype theChar = *from;
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE)){
*to++ = theChar;
}
}
*to = 0;
}
return to - (chartype*)aString;
}
typedef PRInt32 (*StripChars)(char* aString,PRUint32 aCount,const char* aSet);
StripChars gStripChars[]={&StripChars1,&StripChars2};
#endif

View File

@@ -1,120 +0,0 @@
#!nmake
#
# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL. You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All Rights
# Reserved.
DEPTH=..\..
MODULE = xpcom
################################################################################
## exports
EXPORTS = \
nsTextFormater.h \
nsAVLTree.h \
nsCppSharedAllocator.h \
nsCRT.h \
nsDeque.h \
nsEnumeratorUtils.h \
nsHashtable.h \
nsHashtableEnumerator.h \
nsIArena.h \
nsIByteBuffer.h \
nsIObserverList.h \
nsIProperties.h \
nsISimpleEnumerator.h \
nsISizeOfHandler.h \
nsIUnicharBuffer.h \
nsIVariant.h \
nsInt64.h \
nsQuickSort.h \
nsStr.h \
nsString.h \
nsString2.h \
nsSupportsPrimitives.h \
nsTime.h \
nsUnitConversion.h \
nsVector.h \
nsVoidArray.h \
nsXPIDLString.h \
plvector.h \
$(NULL)
XPIDL_MODULE = xpcom_ds
XPIDLSRCS = \
.\nsIAtom.idl \
.\nsICollection.idl \
.\nsIEnumerator.idl \
.\nsIObserver.idl \
.\nsIObserverService.idl \
.\nsISupportsArray.idl \
.\nsISupportsPrimitives.idl \
$(NULL)
################################################################################
## library
LIBRARY_NAME=xpcomds_s
LINCS = \
-I$(PUBLIC)\xpcom \
-I$(PUBLIC)\uconv \
-I$(PUBLIC)\unicharutil \
$(NULL)
LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN
CPP_OBJS = \
.\$(OBJDIR)\nsTextFormater.obj \
.\$(OBJDIR)\nsArena.obj \
.\$(OBJDIR)\nsAtomTable.obj \
.\$(OBJDIR)\nsAVLTree.obj \
.\$(OBJDIR)\nsByteBuffer.obj \
.\$(OBJDIR)\nsCRT.obj \
.\$(OBJDIR)\nsConjoiningEnumerator.obj \
.\$(OBJDIR)\nsDeque.obj \
.\$(OBJDIR)\nsEmptyEnumerator.obj \
.\$(OBJDIR)\nsEnumeratorUtils.obj \
.\$(OBJDIR)\nsHashtable.obj \
.\$(OBJDIR)\nsHashtableEnumerator.obj \
.\$(OBJDIR)\nsObserver.obj \
.\$(OBJDIR)\nsObserverList.obj \
.\$(OBJDIR)\nsObserverService.obj \
.\$(OBJDIR)\nsProperties.obj \
.\$(OBJDIR)\nsQuickSort.obj \
.\$(OBJDIR)\nsSizeOfHandler.obj \
.\$(OBJDIR)\nsStr.obj \
.\$(OBJDIR)\nsString.obj \
.\$(OBJDIR)\nsString2.obj \
.\$(OBJDIR)\nsSupportsArray.obj \
.\$(OBJDIR)\nsSupportsArrayEnumerator.obj \
.\$(OBJDIR)\nsSupportsPrimitives.obj \
.\$(OBJDIR)\nsUnicharBuffer.obj \
.\$(OBJDIR)\nsVariant.obj \
.\$(OBJDIR)\nsVoidArray.obj \
.\$(OBJDIR)\nsXPIDLString.obj \
.\$(OBJDIR)\plvector.obj \
$(NULL)
include <$(DEPTH)\config\rules.mak>
libs:: $(LIBRARY)
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
clobber::
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib

View File

@@ -1,617 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsAVLTree.h"
enum eLean {eLeft,eNeutral,eRight};
struct NS_COM nsAVLNode {
public:
nsAVLNode(void* aValue) {
mLeft=0;
mRight=0;
mSkew=eNeutral;
mValue=aValue;
}
nsAVLNode* mLeft;
nsAVLNode* mRight;
eLean mSkew;
void* mValue;
};
/************************************************************
Now begin the tree class. Don't forget that the comparison
between nodes must occur via the comparitor function,
otherwise all you're testing is pointer addresses.
************************************************************/
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
nsAVLTree::nsAVLTree(nsAVLNodeComparitor& aComparitor,
nsAVLNodeFunctor* aDeallocator) :
mComparitor(aComparitor), mDeallocator(aDeallocator) {
mRoot=0;
mCount=0;
}
static void
avlDeleteTree(nsAVLNode* aNode){
if (aNode) {
avlDeleteTree(aNode->mLeft);
avlDeleteTree(aNode->mRight);
delete aNode;
}
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
nsAVLTree::~nsAVLTree(){
if (mDeallocator) {
ForEachDepthFirst(*mDeallocator);
}
avlDeleteTree(mRoot);
}
class CDoesntExist: public nsAVLNodeFunctor {
public:
CDoesntExist(const nsAVLTree& anotherTree) : mOtherTree(anotherTree) {
}
virtual void* operator()(void* anItem) {
void* result=mOtherTree.FindItem(anItem);
if(result)
return nsnull;
return anItem;
}
protected:
const nsAVLTree& mOtherTree;
};
/**
* This method compares two trees (members by identity).
* @update gess12/27/98
* @param tree to compare against
* @return true if they are identical (contain same stuff).
*/
PRBool nsAVLTree::operator==(const nsAVLTree& aCopy) const{
CDoesntExist functor(aCopy);
void* theItem=FirstThat(functor);
PRBool result=PRBool(!theItem);
return result;
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
static void
avlRotateRight(nsAVLNode*& aRootNode){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
ptr2=aRootNode->mRight;
if(ptr2->mSkew==eRight) {
aRootNode->mRight=ptr2->mLeft;
ptr2->mLeft=aRootNode;
aRootNode->mSkew=eNeutral;
aRootNode=ptr2;
}
else {
ptr3=ptr2->mLeft;
ptr2->mLeft=ptr3->mRight;
ptr3->mRight=ptr2;
aRootNode->mRight=ptr3->mLeft;
ptr3->mLeft=aRootNode;
if(ptr3->mSkew==eLeft)
ptr2->mSkew=eRight;
else ptr2->mSkew=eNeutral;
if(ptr3->mSkew==eRight)
aRootNode->mSkew=eLeft;
else aRootNode->mSkew=eNeutral;
aRootNode=ptr3;
}
aRootNode->mSkew=eNeutral;
return;
}
/**
*
* @update gess12/27/98
* @param
* @return
*/
static void
avlRotateLeft(nsAVLNode*& aRootNode){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
ptr2=aRootNode->mLeft;
if(ptr2->mSkew==eLeft) {
aRootNode->mLeft=ptr2->mRight;
ptr2->mRight=aRootNode;
aRootNode->mSkew=eNeutral;
aRootNode=ptr2;
}
else {
ptr3=ptr2->mRight;
ptr2->mRight=ptr3->mLeft;
ptr3->mLeft=ptr2;
aRootNode->mLeft=ptr3->mRight;
ptr3->mRight=aRootNode;
if(ptr3->mSkew==eRight)
ptr2->mSkew=eLeft;
else ptr2->mSkew=eNeutral;
if(ptr3->mSkew==eLeft)
aRootNode->mSkew=eRight;
else aRootNode->mSkew=eNeutral;
aRootNode=ptr3;
}
aRootNode->mSkew=eNeutral;
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlInsert(nsAVLNode*& aRootNode, nsAVLNode* aNewNode,
nsAVLNodeComparitor& aComparitor) {
eAVLStatus result=eAVL_unknown;
if(!aRootNode) {
aRootNode = aNewNode;
return eAVL_ok;
}
if(aNewNode==aRootNode->mValue) {
return eAVL_duplicate;
}
PRInt32 theCompareResult=aComparitor(aRootNode->mValue,aNewNode->mValue);
if(0 < theCompareResult) { //if(anItem<aRootNode->mValue)
result=avlInsert(aRootNode->mLeft,aNewNode,aComparitor);
if(eAVL_ok==result) {
switch(aRootNode->mSkew){
case eLeft:
avlRotateLeft(aRootNode);
result=eAVL_fail;
break;
case eRight:
aRootNode->mSkew=eNeutral;
result=eAVL_fail;
break;
case eNeutral:
aRootNode->mSkew=eLeft;
break;
} //switch
}//if
} //if
else {
result=avlInsert(aRootNode->mRight,aNewNode,aComparitor);
if(eAVL_ok==result) {
switch(aRootNode->mSkew){
case eLeft:
aRootNode->mSkew=eNeutral;
result=eAVL_fail;
break;
case eRight:
avlRotateRight(aRootNode);
result=eAVL_fail;
break;
case eNeutral:
aRootNode->mSkew=eRight;
break;
} //switch
}
} //if
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static void
avlBalanceLeft(nsAVLNode*& aRootNode, PRBool& delOk){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
eLean balnc2;
eLean balnc3;
switch(aRootNode->mSkew){
case eLeft:
ptr2=aRootNode->mLeft;
balnc2=ptr2->mSkew;
if(balnc2!=eRight) {
aRootNode->mLeft=ptr2->mRight;
ptr2->mRight=aRootNode;
if(balnc2==eNeutral){
aRootNode->mSkew=eLeft;
ptr2->mSkew=eRight;
delOk=PR_FALSE;
}
else{
aRootNode->mSkew=eNeutral;
ptr2->mSkew=eNeutral;
}
aRootNode=ptr2;
}
else{
ptr3=ptr2->mRight;
balnc3=ptr3->mSkew;
ptr2->mRight=ptr3->mLeft;
ptr3->mLeft=ptr2;
aRootNode->mLeft=ptr3->mRight;
ptr3->mRight=aRootNode;
if(balnc3==eRight) {
ptr2->mSkew=eLeft;
}
else {
ptr2->mSkew=eNeutral;
}
if(balnc3==eLeft) {
aRootNode->mSkew=eRight;
}
else {
aRootNode->mSkew=eNeutral;
}
aRootNode=ptr3;
ptr3->mSkew=eNeutral;
}
break;
case eRight:
aRootNode->mSkew=eNeutral;
break;
case eNeutral:
aRootNode->mSkew=eLeft;
delOk=PR_FALSE;
break;
}//switch
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static void
avlBalanceRight(nsAVLNode*& aRootNode, PRBool& delOk){
nsAVLNode* ptr2;
nsAVLNode* ptr3;
eLean balnc2;
eLean balnc3;
switch(aRootNode->mSkew){
case eLeft:
aRootNode->mSkew=eNeutral;
break;
case eRight:
ptr2=aRootNode->mRight;
balnc2=ptr2->mSkew;
if(balnc2!=eLeft) {
aRootNode->mRight=ptr2->mLeft;
ptr2->mLeft=aRootNode;
if(balnc2==eNeutral){
aRootNode->mSkew=eRight;
ptr2->mSkew=eLeft;
delOk=PR_FALSE;
}
else{
aRootNode->mSkew=eNeutral;
ptr2->mSkew=eNeutral;
}
aRootNode=ptr2;
}
else{
ptr3=ptr2->mLeft;
balnc3=ptr3->mSkew;
ptr2->mLeft=ptr3->mRight;
ptr3->mRight=ptr2;
aRootNode->mRight=ptr3->mLeft;
ptr3->mLeft=aRootNode;
if(balnc3==eLeft) {
ptr2->mSkew=eRight;
}
else {
ptr2->mSkew=eNeutral;
}
if(balnc3==eRight) {
aRootNode->mSkew=eLeft;
}
else {
aRootNode->mSkew=eNeutral;
}
aRootNode=ptr3;
ptr3->mSkew=eNeutral;
}
break;
case eNeutral:
aRootNode->mSkew=eRight;
delOk=PR_FALSE;
break;
}//switch
return;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlRemoveChildren(nsAVLNode*& aRootNode,nsAVLNode*& anotherNode, PRBool& delOk){
eAVLStatus result=eAVL_ok;
if(!anotherNode->mRight){
aRootNode->mValue=anotherNode->mValue; //swap
anotherNode=anotherNode->mLeft;
delOk=PR_TRUE;
}
else{
avlRemoveChildren(aRootNode,anotherNode->mRight,delOk);
if(delOk)
avlBalanceLeft(anotherNode,delOk);
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
static eAVLStatus
avlRemove(nsAVLNode*& aRootNode, void* anItem, PRBool& delOk,
nsAVLNodeComparitor& aComparitor){
eAVLStatus result=eAVL_ok;
if(!aRootNode)
delOk=PR_FALSE;
else {
PRInt32 cmp=aComparitor(anItem,aRootNode->mValue);
if(cmp<0){
avlRemove(aRootNode->mLeft,anItem,delOk,aComparitor);
if(delOk)
avlBalanceRight(aRootNode,delOk);
}
else if(cmp>0){
avlRemove(aRootNode->mRight,anItem,delOk,aComparitor);
if(delOk)
avlBalanceLeft(aRootNode,delOk);
}
else{ //they match...
nsAVLNode* temp=aRootNode;
if(!aRootNode->mRight) {
aRootNode=aRootNode->mLeft;
delOk=PR_TRUE;
delete temp;
}
else if(!aRootNode->mLeft) {
aRootNode=aRootNode->mRight;
delOk=PR_TRUE;
delete temp;
}
else {
avlRemoveChildren(aRootNode,aRootNode->mLeft,delOk);
if(delOk)
avlBalanceRight(aRootNode,delOk);
}
}
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
eAVLStatus
nsAVLTree::AddItem(void* anItem){
eAVLStatus result=eAVL_ok;
nsAVLNode* theNewNode=new nsAVLNode(anItem);
result=avlInsert(mRoot,theNewNode,mComparitor);
if(eAVL_duplicate!=result)
mCount++;
else {
delete theNewNode;
}
return result;
}
/** ------------------------------------------------
*
*
* @update gess 4/22/98
* @param
* @return
*/ //----------------------------------------------
void* nsAVLTree::FindItem(void* aValue) const{
nsAVLNode* result=mRoot;
PRInt32 count=0;
while(result) {
count++;
PRInt32 cmp=mComparitor(aValue,result->mValue);
if(0==cmp) {
//we matched...
break;
}
else if(0>cmp){
//theNode was greater...
result=result->mLeft;
}
else {
//aValue is greater...
result=result->mRight;
}
}
if(result) {
return result->mValue;
}
return nsnull;
}
/**
*
* @update gess12/30/98
* @param
* @return
*/
eAVLStatus
nsAVLTree::RemoveItem(void* aValue){
PRBool delOk=PR_TRUE;
eAVLStatus result=avlRemove(mRoot,aValue,delOk,mComparitor);
if(eAVL_ok==result)
mCount--;
return result;
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void
avlForEachDepthFirst(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor){
if(aNode) {
avlForEachDepthFirst(aNode->mLeft,aFunctor);
avlForEachDepthFirst(aNode->mRight,aFunctor);
aFunctor(aNode->mValue);
}
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void
nsAVLTree::ForEachDepthFirst(nsAVLNodeFunctor& aFunctor) const{
::avlForEachDepthFirst(mRoot,aFunctor);
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void
avlForEach(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor) {
if(aNode) {
avlForEach(aNode->mLeft,aFunctor);
aFunctor(aNode->mValue);
avlForEach(aNode->mRight,aFunctor);
}
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void
nsAVLTree::ForEach(nsAVLNodeFunctor& aFunctor) const{
::avlForEach(mRoot,aFunctor);
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
static void*
avlFirstThat(nsAVLNode* aNode, nsAVLNodeFunctor& aFunctor) {
void* result=nsnull;
if(aNode) {
result = avlFirstThat(aNode->mLeft,aFunctor);
if (result) {
return result;
}
result = aFunctor(aNode->mValue);
if (result) {
return result;
}
result = avlFirstThat(aNode->mRight,aFunctor);
}
return result;
}
/**
*
* @update gess9/11/98
* @param
* @return
*/
void*
nsAVLTree::FirstThat(nsAVLNodeFunctor& aFunctor) const{
return ::avlFirstThat(mRoot,aFunctor);
}

View File

@@ -1,74 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsAVLTree_h___
#define nsAVLTree_h___
#include "nscore.h"
enum eAVLStatus {eAVL_unknown,eAVL_ok,eAVL_fail,eAVL_duplicate};
struct nsAVLNode;
/**
*
* @update gess12/26/98
* @param anObject1 is the first object to be compared
* @param anObject2 is the second object to be compared
* @return -1,0,1 if object1 is less, equal, greater than object2
*/
class NS_COM nsAVLNodeComparitor {
public:
virtual PRInt32 operator()(void* anItem1,void* anItem2)=0;
};
class NS_COM nsAVLNodeFunctor {
public:
virtual void* operator()(void* anItem)=0;
};
class NS_COM nsAVLTree {
public:
nsAVLTree(nsAVLNodeComparitor& aComparitor, nsAVLNodeFunctor* aDeallocator);
~nsAVLTree(void);
PRBool operator==(const nsAVLTree& aOther) const;
PRInt32 GetCount(void) const {return mCount;}
//main functions...
eAVLStatus AddItem(void* anItem);
eAVLStatus RemoveItem(void* anItem);
void* FindItem(void* anItem) const;
void ForEach(nsAVLNodeFunctor& aFunctor) const;
void ForEachDepthFirst(nsAVLNodeFunctor& aFunctor) const;
void* FirstThat(nsAVLNodeFunctor& aFunctor) const;
protected:
nsAVLNode* mRoot;
PRInt32 mCount;
nsAVLNodeComparitor& mComparitor;
nsAVLNodeFunctor* mDeallocator;
};
#endif /* nsAVLTree_h___ */

View File

@@ -1,97 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsArena.h"
#include "nsCRT.h"
ArenaImpl::ArenaImpl(void)
: mInitialized(PR_FALSE)
{
NS_INIT_REFCNT();
nsCRT::memset(&mPool, 0, sizeof(PLArenaPool));
}
NS_IMETHODIMP
ArenaImpl::Init(PRUint32 aBlockSize)
{
if (aBlockSize < NS_MIN_ARENA_BLOCK_SIZE) {
aBlockSize = NS_DEFAULT_ARENA_BLOCK_SIZE;
}
PL_INIT_ARENA_POOL(&mPool, "nsIArena", aBlockSize);
mBlockSize = aBlockSize;
mInitialized = PR_TRUE;
return NS_OK;
}
NS_IMPL_ISUPPORTS1(ArenaImpl, nsIArena)
ArenaImpl::~ArenaImpl()
{
if (mInitialized)
PL_FinishArenaPool(&mPool);
mInitialized = PR_FALSE;
}
NS_IMETHODIMP_(void*)
ArenaImpl::Alloc(PRUint32 size)
{
// Adjust size so that it's a multiple of sizeof(double)
PRUint32 align = size & (sizeof(double) - 1);
if (0 != align) {
size += sizeof(double) - align;
}
void* p;
PL_ARENA_ALLOCATE(p, &mPool, size);
return p;
}
NS_METHOD
ArenaImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
ArenaImpl* it = new ArenaImpl();
if (nsnull == it)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(it);
nsresult rv = it->QueryInterface(aIID, aResult);
NS_RELEASE(it);
return rv;
}
NS_COM nsresult NS_NewHeapArena(nsIArena** aInstancePtrResult,
PRUint32 aArenaBlockSize)
{
nsresult rv;
nsIArena* arena;
rv = ArenaImpl::Create(NULL, nsIArena::GetIID(), (void**)&arena);
if (NS_FAILED(rv)) return rv;
rv = arena->Init(aArenaBlockSize);
if (NS_FAILED(rv)) {
NS_RELEASE(arena);
return rv;
}
*aInstancePtrResult = arena;
return rv;
}

View File

@@ -1,50 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsArena_h__
#define nsArena_h__
#include "nsIArena.h"
#define PL_ARENA_CONST_ALIGN_MASK 7
#include "plarena.h"
// Simple arena implementation layered on plarena
class ArenaImpl : public nsIArena {
public:
ArenaImpl(void);
virtual ~ArenaImpl();
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
NS_IMETHOD Init(PRUint32 arenaBlockSize);
NS_IMETHOD_(void*) Alloc(PRUint32 size);
protected:
PLArenaPool mPool;
PRUint32 mBlockSize;
private:
PRBool mInitialized;
};
#endif // nsArena_h__

View File

@@ -1,172 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsAtomTable.h"
#include "nsString.h"
#include "nsCRT.h"
#include "plhash.h"
#include "nsISizeOfHandler.h"
/**
* The shared hash table for atom lookups.
*/
static nsrefcnt gAtoms;
static struct PLHashTable* gAtomHashTable;
#if defined(DEBUG) && (defined(XP_UNIX) || defined(XP_PC))
static PRIntn
DumpAtomLeaks(PLHashEntry *he, PRIntn index, void *arg)
{
AtomImpl* atom = (AtomImpl*) he->value;
if (atom) {
nsAutoString tmp;
atom->ToString(tmp);
fputs(tmp, stdout);
fputs("\n", stdout);
}
return HT_ENUMERATE_NEXT;
}
#endif
NS_COM void NS_PurgeAtomTable(void)
{
if (gAtomHashTable) {
#if defined(DEBUG) && (defined(XP_UNIX) || defined(XP_PC))
if (gAtoms) {
if (getenv("MOZ_DUMP_ATOM_LEAKS")) {
printf("*** leaking %d atoms\n", gAtoms);
PL_HashTableEnumerateEntries(gAtomHashTable, DumpAtomLeaks, 0);
}
}
#endif
PL_HashTableDestroy(gAtomHashTable);
gAtomHashTable = nsnull;
}
}
AtomImpl::AtomImpl()
{
NS_INIT_REFCNT();
// Every live atom holds a reference on the atom hashtable
gAtoms++;
}
AtomImpl::~AtomImpl()
{
NS_PRECONDITION(nsnull != gAtomHashTable, "null atom hashtable");
if (nsnull != gAtomHashTable) {
PL_HashTableRemove(gAtomHashTable, mString);
nsrefcnt cnt = --gAtoms;
if (0 == cnt) {
// When the last atom is destroyed, the atom arena is destroyed
NS_ASSERTION(0 == gAtomHashTable->nentries, "bad atom table");
PL_HashTableDestroy(gAtomHashTable);
gAtomHashTable = nsnull;
}
}
}
NS_IMPL_ISUPPORTS1(AtomImpl, nsIAtom)
void* AtomImpl::operator new(size_t size, const PRUnichar* us, PRInt32 uslen)
{
size = size + uslen * sizeof(PRUnichar);
AtomImpl* ii = (AtomImpl*) ::operator new(size);
nsCRT::memcpy(ii->mString, us, uslen * sizeof(PRUnichar));
ii->mString[uslen] = 0;
return ii;
}
NS_IMETHODIMP
AtomImpl::ToString(nsString& aBuf) /*FIX: const */
{
aBuf.SetLength(0);
aBuf.Append(mString, nsCRT::strlen(mString));
return NS_OK;
}
NS_IMETHODIMP
AtomImpl::GetUnicode(const PRUnichar **aResult) /*FIX: const */
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = mString;
return NS_OK;
}
NS_IMETHODIMP
AtomImpl::SizeOf(nsISizeOfHandler* aHandler, PRUint32* _retval) /*FIX: const */
{
NS_ENSURE_ARG_POINTER(_retval);
PRUint32 sum = sizeof(*this) + nsCRT::strlen(mString) * sizeof(PRUnichar);
*_retval = sum;
return NS_OK;
}
//----------------------------------------------------------------------
static PLHashNumber HashKey(const PRUnichar* k)
{
return (PLHashNumber) nsCRT::HashValue(k);
}
static PRIntn CompareKeys(const PRUnichar* k1, const PRUnichar* k2)
{
return nsCRT::strcmp(k1, k2) == 0;
}
NS_COM nsIAtom* NS_NewAtom(const char* isolatin1)
{
nsAutoString tmp(isolatin1);
return NS_NewAtom(tmp.GetUnicode());
}
NS_COM nsIAtom* NS_NewAtom(const nsString& aString)
{
return NS_NewAtom(aString.GetUnicode());
}
NS_COM nsIAtom* NS_NewAtom(const PRUnichar* us)
{
if (nsnull == gAtomHashTable) {
gAtomHashTable = PL_NewHashTable(8, (PLHashFunction) HashKey,
(PLHashComparator) CompareKeys,
(PLHashComparator) nsnull,
nsnull, nsnull);
}
PRUint32 uslen;
PRUint32 hashCode = nsCRT::HashValue(us, &uslen);
PLHashEntry** hep = PL_HashTableRawLookup(gAtomHashTable, hashCode, us);
PLHashEntry* he = *hep;
if (nsnull != he) {
nsIAtom* id = (nsIAtom*) he->value;
NS_ADDREF(id);
return id;
}
AtomImpl* id = new(us, uslen) AtomImpl();
PL_HashTableRawAdd(gAtomHashTable, hep, hashCode, id->mString, id);
NS_ADDREF(id);
return id;
}
NS_COM nsrefcnt NS_GetNumberOfAtoms(void)
{
if (nsnull != gAtomHashTable) {
NS_PRECONDITION(nsrefcnt(gAtomHashTable->nentries) == gAtoms, "bad atom table");
}
return gAtoms;
}

View File

@@ -1,723 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsBuffer.h"
#include "nsAutoLock.h"
#include "nsCRT.h"
#include "nsIInputStream.h"
#include "nsIServiceManager.h"
#include "nsIPageManager.h"
////////////////////////////////////////////////////////////////////////////////
nsBuffer::nsBuffer()
: mGrowBySize(0),
mMaxSize(0),
mAllocator(nsnull),
mObserver(nsnull),
mBufferSize(0),
mReadSegment(nsnull),
mReadCursor(0),
mWriteSegment(nsnull),
mWriteCursor(0),
mReaderClosed(PR_FALSE),
mCondition(NS_OK)
{
NS_INIT_REFCNT();
PR_INIT_CLIST(&mSegments);
}
NS_IMETHODIMP
nsBuffer::Init(PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer, nsIAllocator* allocator)
{
NS_ASSERTION(sizeof(PRCList) <= SEGMENT_OVERHEAD,
"need to change SEGMENT_OVERHEAD size");
NS_ASSERTION(growBySize > SEGMENT_OVERHEAD, "bad growBySize");
mGrowBySize = growBySize;
mMaxSize = maxSize;
mObserver = observer;
NS_IF_ADDREF(mObserver);
mAllocator = allocator;
NS_ADDREF(mAllocator);
return NS_OK;
}
nsBuffer::~nsBuffer()
{
// Free any allocated pages...
while (!PR_CLIST_IS_EMPTY(&mSegments)) {
PRCList* header = (PRCList*)mSegments.next;
char* segment = (char*)header;
PR_REMOVE_LINK(header); // unlink from mSegments
(void) mAllocator->Free(segment);
}
NS_IF_RELEASE(mObserver);
NS_IF_RELEASE(mAllocator);
}
NS_IMPL_ISUPPORTS1(nsBuffer, nsIBuffer)
NS_METHOD
nsBuffer::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsBuffer* buf = new nsBuffer();
if (buf == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(buf);
nsresult rv = buf->QueryInterface(aIID, aResult);
NS_RELEASE(buf);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
nsresult
nsBuffer::PushWriteSegment()
{
nsAutoCMonitor mon(this); // protect mSegments
if (mBufferSize >= mMaxSize) {
if (mObserver) {
nsresult rv = mObserver->OnFull(this);
if (NS_FAILED(rv)) return rv;
}
return NS_BASE_STREAM_WOULD_BLOCK;
}
// allocate a new segment to write into
PRCList* header;
header = (PRCList*)mAllocator->Alloc(mGrowBySize);
if (header == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
mBufferSize += mGrowBySize;
PR_INSERT_BEFORE(header, &mSegments); // insert at end
// initialize the write segment
mWriteSegment = header;
mWriteSegmentEnd = (char*)mWriteSegment + mGrowBySize;
mWriteCursor = (char*)mWriteSegment + sizeof(PRCList);
return NS_OK;
}
nsresult
nsBuffer::PopReadSegment()
{
nsresult rv;
nsAutoCMonitor mon(this); // protect mSegments
PRCList* header = (PRCList*)mSegments.next;
char* segment = (char*)header;
NS_ASSERTION(mReadSegment == header, "wrong segment");
// make sure that the writer isn't still in this segment (that the
// reader is removing)
NS_ASSERTION(!(segment <= mWriteCursor && mWriteCursor < segment + mGrowBySize),
"removing writer's segment");
PR_REMOVE_LINK(header); // unlink from mSegments
mBufferSize -= mGrowBySize;
rv = mAllocator->Free(segment);
if (NS_FAILED(rv)) return rv;
// initialize the read segment
if (PR_CLIST_IS_EMPTY(&mSegments)) {
mReadSegment = nsnull;
mReadSegmentEnd = nsnull;
mReadCursor = nsnull;
if (mObserver) {
rv = mObserver->OnEmpty(this);
if (NS_FAILED(rv)) return rv;
}
return NS_BASE_STREAM_WOULD_BLOCK;
}
else {
mReadSegment = mSegments.next;
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
}
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIBuffer methods:
NS_IMETHODIMP
nsBuffer::ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
PRUint32 *readCount)
{
NS_ASSERTION(!mReaderClosed, "state change error");
nsAutoCMonitor mon(this);
nsresult rv = NS_OK;
PRUint32 readBufferLen;
const char* readBuffer;
*readCount = 0;
while (count > 0) {
rv = GetReadSegment(0, &readBuffer, &readBufferLen);
if (NS_FAILED(rv) || readBufferLen == 0) {
return *readCount == 0 ? rv : NS_OK;
}
readBufferLen = PR_MIN(readBufferLen, count);
while (readBufferLen > 0) {
PRUint32 writeCount;
rv = writer(closure, readBuffer, *readCount, readBufferLen, &writeCount);
NS_ASSERTION(rv != NS_BASE_STREAM_EOF, "Write should not return EOF");
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv) || writeCount == 0) {
// if we failed to write just report what we were
// able to read so far
return *readCount == 0 ? rv : NS_OK;
}
NS_ASSERTION(writeCount <= readBufferLen, "writer returned bad writeCount");
readBuffer += writeCount;
readBufferLen -= writeCount;
*readCount += writeCount;
count -= writeCount;
if (mReadCursor + writeCount == mReadSegmentEnd) {
rv = PopReadSegment();
if (NS_FAILED(rv)) {
return *readCount == 0 ? rv : NS_OK;
}
}
else {
mReadCursor += writeCount;
}
}
}
return NS_OK;
}
static NS_METHOD
nsWriteToRawBuffer(void* closure,
const char* fromRawSegment,
PRUint32 offset,
PRUint32 count,
PRUint32 *writeCount)
{
char* toBuf = (char*)closure;
nsCRT::memcpy(&toBuf[offset], fromRawSegment, count);
*writeCount = count;
return NS_OK;
}
NS_IMETHODIMP
nsBuffer::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount)
{
return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount);
}
NS_IMETHODIMP
nsBuffer::GetReadSegment(PRUint32 segmentLogicalOffset,
const char* *resultSegment,
PRUint32 *resultSegmentLen)
{
nsAutoCMonitor mon(this);
// set the read segment and cursor if not already set
if (mReadSegment == nsnull) {
if (PR_CLIST_IS_EMPTY(&mSegments)) {
*resultSegmentLen = 0;
*resultSegment = nsnull;
return mCondition;
}
else {
mReadSegment = mSegments.next;
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
}
}
// now search for the segment starting from segmentLogicalOffset and return it
PRCList* curSeg = mReadSegment;
char* curSegStart = mReadCursor;
char* curSegEnd = mReadSegmentEnd;
PRInt32 amt;
PRInt32 offset = (PRInt32)segmentLogicalOffset;
while (offset >= 0) {
// snapshot the write cursor into a local variable -- this allows
// a writer to freely change it while we're reading while avoiding
// using a lock
char* snapshotWriteCursor = mWriteCursor; // atomic
// next check if the write cursor is in our segment
if (curSegStart <= snapshotWriteCursor &&
snapshotWriteCursor < curSegEnd) {
// same segment -- read up to the snapshotWriteCursor
curSegEnd = snapshotWriteCursor;
amt = curSegEnd - curSegStart;
if (offset < amt) {
// segmentLogicalOffset is in this segment, so read up to its end
*resultSegmentLen = amt - offset;
*resultSegment = curSegStart + offset;
return NS_OK;
}
else {
// don't continue past the write segment
*resultSegmentLen = 0;
*resultSegment = nsnull;
return mCondition;
}
}
else {
amt = curSegEnd - curSegStart;
if (offset < amt) {
// segmentLogicalOffset is in this segment, so read up to its end
*resultSegmentLen = amt - offset;
*resultSegment = curSegStart + offset;
return NS_OK;
}
else {
curSeg = PR_NEXT_LINK(curSeg);
if (curSeg == mReadSegment) {
// been all the way around
*resultSegmentLen = 0;
*resultSegment = nsnull;
return mCondition;
}
curSegEnd = (char*)curSeg + mGrowBySize;
curSegStart = (char*)curSeg + sizeof(PRCList);
offset -= amt;
}
}
}
NS_NOTREACHED("nsBuffer::GetReadSegment failed");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsBuffer::GetReadableAmount(PRUint32 *result)
{
NS_ASSERTION(!mReaderClosed, "state change error");
nsAutoCMonitor mon(this);
*result = 0;
// first set the read segment and cursor if not already set
if (mReadSegment == nsnull) {
if (PR_CLIST_IS_EMPTY(&mSegments)) {
return NS_OK;
}
else {
mReadSegment = mSegments.next;
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
}
}
// now search for the segment starting from segmentLogicalOffset and return it
PRCList* curSeg = mReadSegment;
char* curSegStart = mReadCursor;
char* curSegEnd = mReadSegmentEnd;
PRInt32 amt;
while (PR_TRUE) {
// snapshot the write cursor into a local variable -- this allows
// a writer to freely change it while we're reading while avoiding
// using a lock
char* snapshotWriteCursor = mWriteCursor; // atomic
// next check if the write cursor is in our segment
if (curSegStart <= snapshotWriteCursor &&
snapshotWriteCursor < curSegEnd) {
// same segment -- read up to the snapshotWriteCursor
curSegEnd = snapshotWriteCursor;
amt = curSegEnd - curSegStart;
*result += amt;
return NS_OK;
}
else {
amt = curSegEnd - curSegStart;
*result += amt;
curSeg = PR_NEXT_LINK(curSeg);
if (curSeg == mReadSegment) {
// been all the way around
return NS_OK;
}
curSegEnd = (char*)curSeg + mGrowBySize;
curSegStart = (char*)curSeg + sizeof(PRCList);
}
}
return NS_ERROR_FAILURE;
}
#define COMPARE(s1, s2, i) ignoreCase ? nsCRT::strncasecmp((const char *)s1, (const char *)s2, (PRUint32)i) : nsCRT::strncmp((const char *)s1, (const char *)s2, (PRUint32)i)
NS_IMETHODIMP
nsBuffer::Search(const char* string, PRBool ignoreCase,
PRBool *found, PRUint32 *offsetSearchedTo)
{
NS_ASSERTION(!mReaderClosed, "state change error");
nsresult rv;
const char* bufSeg1;
PRUint32 bufSegLen1;
PRUint32 segmentPos = 0;
PRUint32 strLen = nsCRT::strlen(string);
rv = GetReadSegment(segmentPos, &bufSeg1, &bufSegLen1);
if (NS_FAILED(rv) || bufSegLen1 == 0) {
*found = PR_FALSE;
*offsetSearchedTo = segmentPos;
return NS_OK;
}
while (PR_TRUE) {
PRUint32 i;
// check if the string is in the buffer segment
for (i = 0; i < bufSegLen1 - strLen + 1; i++) {
if (COMPARE(&bufSeg1[i], string, strLen) == 0) {
*found = PR_TRUE;
*offsetSearchedTo = segmentPos + i;
return NS_OK;
}
}
// get the next segment
const char* bufSeg2;
PRUint32 bufSegLen2;
segmentPos += bufSegLen1;
rv = GetReadSegment(segmentPos, &bufSeg2, &bufSegLen2);
if (NS_FAILED(rv) || bufSegLen2 == 0) {
*found = PR_FALSE;
if (mCondition != NS_OK) // XXX NS_FAILED?
*offsetSearchedTo = segmentPos - bufSegLen1;
else
*offsetSearchedTo = segmentPos - bufSegLen1 - strLen + 1;
return NS_OK;
}
// check if the string is straddling the next buffer segment
PRUint32 limit = PR_MIN(strLen, bufSegLen2 + 1);
for (i = 0; i < limit; i++) {
PRUint32 strPart1Len = strLen - i - 1;
PRUint32 strPart2Len = strLen - strPart1Len;
const char* strPart2 = &string[strLen - strPart2Len];
PRUint32 bufSeg1Offset = bufSegLen1 - strPart1Len;
if (COMPARE(&bufSeg1[bufSeg1Offset], string, strPart1Len) == 0 &&
COMPARE(bufSeg2, strPart2, strPart2Len) == 0) {
*found = PR_TRUE;
*offsetSearchedTo = segmentPos - strPart1Len;
return NS_OK;
}
}
// finally continue with the next buffer
bufSeg1 = bufSeg2;
bufSegLen1 = bufSegLen2;
}
NS_NOTREACHED("can't get here");
return NS_ERROR_FAILURE; // keep compiler happy
}
NS_IMETHODIMP
nsBuffer::ReaderClosed()
{
nsresult rv = NS_OK;
nsAutoCMonitor mon(this); // protect mSegments
// first prevent any more writing
mReaderClosed = PR_TRUE;
// then free any unread segments...
// first set the read segment and cursor if not already set
if (mReadSegment == nsnull) {
if (!PR_CLIST_IS_EMPTY(&mSegments)) {
mReadSegment = mSegments.next;
mReadSegmentEnd = (char*)mReadSegment + mGrowBySize;
mReadCursor = (char*)mReadSegment + sizeof(PRCList);
}
}
while (mReadSegment) {
// snapshot the write cursor into a local variable -- this allows
// a writer to freely change it while we're reading while avoiding
// using a lock
char* snapshotWriteCursor = mWriteCursor; // atomic
// next check if the write cursor is in our segment
if (mReadCursor <= snapshotWriteCursor &&
snapshotWriteCursor < mReadSegmentEnd) {
// same segment -- we've discarded all the unread segments we
// can, so just updatethe read cursor
mReadCursor = mWriteCursor;
break;
}
// else advance to the next segment, freeing this one
rv = PopReadSegment();
if (NS_FAILED(rv)) break;
}
#ifdef DEBUG
PRUint32 amt;
const char* buf;
rv = GetReadSegment(0, &buf, &amt);
NS_ASSERTION(rv == NS_BASE_STREAM_EOF ||
(NS_SUCCEEDED(rv) && amt == 0), "ReaderClosed failed");
#endif
return rv;
}
NS_IMETHODIMP
nsBuffer::GetCondition(nsresult *result)
{
*result = mCondition;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsBuffer::WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
PRUint32 *writeCount)
{
nsresult rv = NS_OK;
nsAutoCMonitor mon(this);
*writeCount = 0;
if (mReaderClosed) {
rv = NS_BASE_STREAM_CLOSED;
goto done;
}
if (NS_FAILED(mCondition)) {
rv = mCondition;
goto done;
}
while (count > 0) {
PRUint32 writeBufLen;
char* writeBuf;
rv = GetWriteSegment(&writeBuf, &writeBufLen);
if (NS_FAILED(rv) || writeBufLen == 0) {
// if we failed to allocate a new segment, we're probably out
// of memory, but we don't care -- just report what we were
// able to write so far
rv = (*writeCount == 0) ? rv : NS_OK;
goto done;
}
writeBufLen = PR_MIN(writeBufLen, count);
while (writeBufLen > 0) {
PRUint32 readCount = 0;
rv = reader(closure, writeBuf, *writeCount, writeBufLen, &readCount);
if (rv == NS_BASE_STREAM_WOULD_BLOCK || readCount == 0) {
// if the place we're putting the data would block (probably ran
// out of room) just return what we were able to write so far
rv = (*writeCount == 0) ? rv : NS_OK;
goto done;
}
if (NS_FAILED(rv)) {
// save the failure condition so that we can get it again later
nsresult rv2 = SetCondition(rv);
NS_ASSERTION(NS_SUCCEEDED(rv2), "SetCondition failed");
// if we failed to read just report what we were
// able to write so far
rv = (*writeCount == 0) ? rv : NS_OK;
goto done;
}
NS_ASSERTION(readCount <= writeBufLen, "reader returned bad readCount");
writeBuf += readCount;
writeBufLen -= readCount;
*writeCount += readCount;
count -= readCount;
// set the write cursor after the data is valid
if (mWriteCursor + readCount == mWriteSegmentEnd) {
mWriteSegment = nsnull; // allocate a new segment next time around
mWriteSegmentEnd = nsnull;
mWriteCursor = nsnull;
}
else
mWriteCursor += readCount;
}
}
done:
if (mObserver && *writeCount) {
mObserver->OnWrite(this, *writeCount);
}
return rv;
}
static NS_METHOD
nsReadFromRawBuffer(void* closure,
char* toRawSegment,
PRUint32 offset,
PRUint32 count,
PRUint32 *readCount)
{
const char* fromBuf = (const char*)closure;
nsCRT::memcpy(toRawSegment, &fromBuf[offset], count);
*readCount = count;
return NS_OK;
}
NS_IMETHODIMP
nsBuffer::Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount)
{
return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount);
}
static NS_METHOD
nsReadFromInputStream(void* closure,
char* toRawSegment,
PRUint32 offset,
PRUint32 count,
PRUint32 *readCount)
{
nsIInputStream* fromStream = (nsIInputStream*)closure;
return fromStream->Read(toRawSegment, count, readCount);
}
NS_IMETHODIMP
nsBuffer::WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount)
{
return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount);
}
NS_IMETHODIMP
nsBuffer::GetWriteSegment(char* *resultSegment,
PRUint32 *resultSegmentLen)
{
nsAutoCMonitor mon(this);
if (mReaderClosed)
return NS_BASE_STREAM_CLOSED;
nsresult rv;
*resultSegmentLen = 0;
*resultSegment = nsnull;
if (mWriteSegment == nsnull) {
rv = PushWriteSegment();
if (NS_FAILED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK) return rv;
NS_ASSERTION(mWriteSegment != nsnull, "failed to allocate segment");
}
*resultSegmentLen = mWriteSegmentEnd - mWriteCursor;
*resultSegment = mWriteCursor;
NS_ASSERTION(*resultSegmentLen > 0, "Failed to get write segment.");
return NS_OK;
}
NS_IMETHODIMP
nsBuffer::GetWritableAmount(PRUint32 *amount)
{
if (mReaderClosed)
return NS_BASE_STREAM_CLOSED;
nsresult rv;
PRUint32 readableAmount;
rv = GetReadableAmount(&readableAmount);
if (NS_FAILED(rv)) return rv;
*amount = mMaxSize - readableAmount;
return NS_OK;
}
NS_IMETHODIMP
nsBuffer::GetReaderClosed(PRBool *result)
{
*result = mReaderClosed;
return NS_OK;
}
NS_IMETHODIMP
nsBuffer::SetCondition(nsresult condition)
{
nsAutoCMonitor mon(this);
if (mReaderClosed)
return NS_BASE_STREAM_CLOSED;
mCondition = condition;
mWriteSegment = nsnull; // allows reader to free last segment w/o asserting
mWriteSegmentEnd = nsnull;
// don't reset mWriteCursor here -- we need it for the EOF point in the buffer
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
static NS_DEFINE_CID(kAllocatorCID, NS_ALLOCATOR_CID);
NS_COM nsresult
NS_NewBuffer(nsIBuffer* *result,
PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer)
{
nsresult rv;
NS_WITH_SERVICE(nsIAllocator, alloc, kAllocatorCID, &rv);
if (NS_FAILED(rv)) return rv;
nsBuffer* buf;
rv = nsBuffer::Create(NULL, nsIBuffer::GetIID(), (void**)&buf);
if (NS_FAILED(rv)) return rv;
rv = buf->Init(growBySize, maxSize, observer, alloc);
if (NS_FAILED(rv)) {
NS_RELEASE(buf);
return rv;
}
*result = buf;
return NS_OK;
}
static NS_DEFINE_CID(kPageManagerCID, NS_PAGEMANAGER_CID);
NS_COM nsresult
NS_NewPageBuffer(nsIBuffer* *result,
PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer)
{
nsresult rv;
NS_WITH_SERVICE(nsIAllocator, alloc, kPageManagerCID, &rv);
if (NS_FAILED(rv)) return rv;
nsBuffer* buf;
rv = nsBuffer::Create(NULL, nsIBuffer::GetIID(), (void**)&buf);
if (NS_FAILED(rv)) return rv;
rv = buf->Init(growBySize, maxSize, observer, alloc);
if (NS_FAILED(rv)) {
NS_RELEASE(buf);
return rv;
}
*result = buf;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,87 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsBuffer_h___
#define nsBuffer_h___
#include "nsIBuffer.h"
#include "nscore.h"
#include "prclist.h"
#include "nsIAllocator.h"
class nsBuffer : public nsIBuffer {
public:
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
// nsIBuffer methods:
NS_IMETHOD Init(PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer, nsIAllocator* allocator);
NS_IMETHOD Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount);
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
PRUint32 *readCount);
NS_IMETHOD GetReadSegment(PRUint32 segmentLogicalOffset,
const char* *resultSegment,
PRUint32 *resultSegmentLen);
NS_IMETHOD GetReadableAmount(PRUint32 *amount);
NS_IMETHOD Search(const char* forString, PRBool ignoreCase,
PRBool *found, PRUint32 *offsetSearchedTo);
NS_IMETHOD ReaderClosed(void);
NS_IMETHOD GetCondition(nsresult *result);
NS_IMETHOD Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount);
NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount);
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
PRUint32 *writeCount);
NS_IMETHOD GetWriteSegment(char* *resultSegment,
PRUint32 *resultSegmentLen);
NS_IMETHOD GetWritableAmount(PRUint32 *amount);
NS_IMETHOD GetReaderClosed(PRBool *result);
NS_IMETHOD SetCondition(nsresult condition);
// nsBuffer methods:
nsBuffer();
virtual ~nsBuffer();
nsresult PushWriteSegment();
nsresult PopReadSegment();
protected:
PRUint32 mGrowBySize;
PRUint32 mMaxSize;
nsIAllocator* mAllocator;
nsIBufferObserver* mObserver;
PRCList mSegments;
PRUint32 mBufferSize;
PRCList* mReadSegment;
char* mReadSegmentEnd;
char* mReadCursor;
PRCList* mWriteSegment;
char* mWriteSegmentEnd;
char* mWriteCursor;
PRBool mReaderClosed;
nsresult mCondition;
};
#endif // nsBuffer_h___

View File

@@ -1,151 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsByteBuffer.h"
#include "nsIInputStream.h"
#include "nsCRT.h"
#define MIN_BUFFER_SIZE 32
ByteBufferImpl::ByteBufferImpl(void)
: mBuffer(NULL), mSpace(0), mLength(0)
{
NS_INIT_REFCNT();
}
NS_IMETHODIMP
ByteBufferImpl::Init(PRUint32 aBufferSize)
{
if (aBufferSize < MIN_BUFFER_SIZE) {
aBufferSize = MIN_BUFFER_SIZE;
}
mSpace = aBufferSize;
mLength = 0;
mBuffer = new char[aBufferSize];
return mBuffer ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
NS_IMPL_ISUPPORTS1(ByteBufferImpl,nsIByteBuffer)
ByteBufferImpl::~ByteBufferImpl()
{
if (nsnull != mBuffer) {
delete[] mBuffer;
mBuffer = nsnull;
}
mLength = 0;
}
NS_METHOD
ByteBufferImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
ByteBufferImpl* it = new ByteBufferImpl();
if (nsnull == it)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(it);
nsresult rv = it->QueryInterface(aIID, (void**)aResult);
NS_RELEASE(it);
return rv;
}
NS_IMETHODIMP_(PRUint32)
ByteBufferImpl::GetLength(void) const
{
return mLength;
}
NS_IMETHODIMP_(PRUint32)
ByteBufferImpl::GetBufferSize(void) const
{
return mSpace;
}
NS_IMETHODIMP_(char*)
ByteBufferImpl::GetBuffer(void) const
{
return mBuffer;
}
NS_IMETHODIMP_(PRBool)
ByteBufferImpl::Grow(PRUint32 aNewSize)
{
if (aNewSize < MIN_BUFFER_SIZE) {
aNewSize = MIN_BUFFER_SIZE;
}
char* newbuf = new char[aNewSize];
if (nsnull != newbuf) {
if (0 != mLength) {
nsCRT::memcpy(newbuf, mBuffer, mLength);
}
delete[] mBuffer;
mBuffer = newbuf;
return PR_TRUE;
}
return PR_FALSE;
}
NS_IMETHODIMP_(PRInt32)
ByteBufferImpl::Fill(nsresult* aErrorCode, nsIInputStream* aStream,
PRUint32 aKeep)
{
NS_PRECONDITION(nsnull != aStream, "null stream");
NS_PRECONDITION(aKeep <= mLength, "illegal keep count");
if ((nsnull == aStream) || (PRUint32(aKeep) > PRUint32(mLength))) {
// whoops
*aErrorCode = NS_BASE_STREAM_ILLEGAL_ARGS;
return -1;
}
if (0 != aKeep) {
// Slide over kept data
nsCRT::memmove(mBuffer, mBuffer + (mLength - aKeep), aKeep);
}
// Read in some new data
mLength = aKeep;
PRUint32 nb;
*aErrorCode = aStream->Read(mBuffer + aKeep, mSpace - aKeep, &nb);
if (NS_SUCCEEDED(*aErrorCode)) {
mLength += nb;
}
else
nb = 0;
return nb;
}
NS_COM nsresult NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult,
nsISupports* aOuter,
PRUint32 aBufferSize)
{
nsresult rv;
nsIByteBuffer* buf;
rv = ByteBufferImpl::Create(aOuter, nsIByteBuffer::GetIID(), (void**)&buf);
if (NS_FAILED(rv)) return rv;
rv = buf->Init(aBufferSize);
if (NS_FAILED(rv)) {
NS_RELEASE(buf);
return rv;
}
*aInstancePtrResult = buf;
return rv;
}

View File

@@ -1,47 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsByteBuffer_h__
#define nsByteBuffer_h__
#include "nsIByteBuffer.h"
class ByteBufferImpl : public nsIByteBuffer {
public:
ByteBufferImpl(void);
virtual ~ByteBufferImpl();
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
NS_IMETHOD Init(PRUint32 aBufferSize);
NS_IMETHOD_(PRUint32) GetLength(void) const;
NS_IMETHOD_(PRUint32) GetBufferSize(void) const;
NS_IMETHOD_(char*) GetBuffer() const;
NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize);
NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream,
PRUint32 aKeep);
char* mBuffer;
PRUint32 mSpace;
PRUint32 mLength;
};
#endif // nsByteBuffer_h__

View File

@@ -1,555 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/**
* MODULE NOTES:
* @update gess7/30/98
*
* Much as I hate to do it, we were using string compares wrong.
* Often, programmers call functions like strcmp(s1,s2), and pass
* one or more null strings. Rather than blow up on these, I've
* added quick checks to ensure that cases like this don't cause
* us to fail.
*
* In general, if you pass a null into any of these string compare
* routines, we simply return 0.
*/
#include "nsCRT.h"
#include "nsUnicharUtilCIID.h"
#include "nsIServiceManager.h"
#include "nsICaseConversion.h"
// XXX Bug: These tables don't lowercase the upper 128 characters properly
// This table maps uppercase characters to lower case characters;
// characters that are neither upper nor lower case are unaffected.
static const unsigned char kUpper2Lower[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64,
// upper band mapped to lower [A-Z] => [a-z]
97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,120,121,122,
91, 92, 93, 94, 95,
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};
static const unsigned char kLower2Upper[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96,
// lower band mapped to upper [a-z] => [A-Z]
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};
// XXX bug: this doesn't map 0x80 to 0x9f properly
const PRUnichar kIsoLatin1ToUCS2[256] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
};
//----------------------------------------------------------------------
#define TOLOWER(_ucs2) \
(((_ucs2) < 128) ? PRUnichar(kUpper2Lower[_ucs2]) : _ToLower(_ucs2))
#define TOUPPER(_ucs2) \
(((_ucs2) < 128) ? PRUnichar(kLower2Upper[_ucs2]) : _ToUpper(_ucs2))
class HandleCaseConversionShutdown : public nsIShutdownListener {
public :
NS_IMETHOD OnShutdown(const nsCID& cid, nsISupports* service);
HandleCaseConversionShutdown(void) { NS_INIT_REFCNT(); }
virtual ~HandleCaseConversionShutdown(void) {}
NS_DECL_ISUPPORTS
};
static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
static nsICaseConversion * gCaseConv = NULL;
NS_IMPL_ISUPPORTS1(HandleCaseConversionShutdown, nsIShutdownListener)
nsresult
HandleCaseConversionShutdown::OnShutdown(const nsCID& cid,
nsISupports* aService)
{
if (cid.Equals(kUnicharUtilCID)) {
NS_ASSERTION(aService == gCaseConv, "wrong service!");
gCaseConv->Release();
gCaseConv = NULL;
}
return NS_OK;
}
static HandleCaseConversionShutdown* gListener = NULL;
static void StartUpCaseConversion()
{
nsresult err;
if ( NULL == gListener )
{
gListener = new HandleCaseConversionShutdown();
gListener->AddRef();
}
err = nsServiceManager::GetService(kUnicharUtilCID, NS_GET_IID(nsICaseConversion),
(nsISupports**) &gCaseConv, gListener);
}
static void CheckCaseConversion()
{
if(NULL == gCaseConv )
StartUpCaseConversion();
NS_ASSERTION( gCaseConv != NULL , "cannot obtain UnicharUtil");
}
static PRUnichar _ToLower(PRUnichar aChar)
{
PRUnichar oLower;
CheckCaseConversion();
nsresult err = gCaseConv->ToLower(aChar, &oLower);
NS_ASSERTION( NS_SUCCEEDED(err), "failed to communicate to UnicharUtil");
return ( NS_SUCCEEDED(err) ) ? oLower : aChar ;
}
static PRUnichar _ToUpper(PRUnichar aChar)
{
nsresult err;
PRUnichar oUpper;
CheckCaseConversion();
err = gCaseConv->ToUpper(aChar, &oUpper);
NS_ASSERTION( NS_SUCCEEDED(err), "failed to communicate to UnicharUtil");
return ( NS_SUCCEEDED(err) ) ? oUpper : aChar ;
}
//----------------------------------------------------------------------
PRUnichar nsCRT::ToUpper(PRUnichar aChar)
{
return TOUPPER(aChar);
}
PRUnichar nsCRT::ToLower(PRUnichar aChar)
{
return TOLOWER(aChar);
}
PRBool nsCRT::IsUpper(PRUnichar aChar)
{
return aChar != nsCRT::ToLower(aChar);
}
PRBool nsCRT::IsLower(PRUnichar aChar)
{
return aChar != nsCRT::ToUpper(aChar);
}
////////////////////////////////////////////////////////////////////////////////
// My lovely strtok routine
#define IS_DELIM(m, c) ((m)[(c) >> 3] & (1 << ((c) & 7)))
#define SET_DELIM(m, c) ((m)[(c) >> 3] |= (1 << ((c) & 7)))
#define DELIM_TABLE_SIZE 32
char* nsCRT::strtok(char* string, const char* delims, char* *newStr)
{
NS_ASSERTION(string, "Unlike regular strtok, the first argument cannot be null.");
char delimTable[DELIM_TABLE_SIZE];
PRUint32 i;
char* result;
char* str = string;
for (i = 0; i < DELIM_TABLE_SIZE; i++)
delimTable[i] = '\0';
for (i = 0; i < DELIM_TABLE_SIZE && delims[i]; i++) {
SET_DELIM(delimTable, delims[i]);
}
NS_ASSERTION(delims[i] == '\0', "too many delimiters");
// skip to beginning
while (*str && IS_DELIM(delimTable, *str)) {
str++;
}
result = str;
// fix up the end of the token
while (*str) {
if (IS_DELIM(delimTable, *str)) {
*str++ = '\0';
break;
}
str++;
}
*newStr = str;
return str == result ? NULL : result;
}
////////////////////////////////////////////////////////////////////////////////
PRUint32 nsCRT::strlen(const PRUnichar* s)
{
PRUint32 len = 0;
if(s) {
while (*s++ != 0) {
len++;
}
}
return len;
}
/**
* Compare unichar string ptrs, stopping at the 1st null
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 and s2 both point to unichar strings
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strcmp(const PRUnichar* s1, const PRUnichar* s2)
{
if(s1 && s2) {
for (;;) {
PRUnichar c1 = *s1++;
PRUnichar c2 = *s2++;
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
if ((0==c1) || (0==c2)) break;
}
}
return 0;
}
/**
* Compare unichar string ptrs, stopping at the 1st null or nth char.
* NOTE: If either is null, we return 0.
* @update gess7/30/98
* @param s1 and s2 both point to unichar strings
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strncmp(const PRUnichar* s1, const PRUnichar* s2, PRUint32 n)
{
if(s1 && s2) {
if(n != 0) {
do {
PRUnichar c1 = *s1++;
PRUnichar c2 = *s2++;
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
if ((0==c1) || (0==c2)) break;
} while (--n != 0);
}
}
return 0;
}
/**
* Compare unichar string ptrs without regard to case
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 and s2 both point to unichar strings
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const PRUnichar* s2)
{
if(s1 && s2) {
for (;;) {
PRUnichar c1 = *s1++;
PRUnichar c2 = *s2++;
if (c1 != c2) {
c1 = TOLOWER(c1);
c2 = TOLOWER(c2);
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
}
if ((0==c1) || (0==c2)) break;
}
}
return 0;
}
/**
* Compare unichar string ptrs, stopping at the 1st null or nth char;
* also ignoring the case of characters.
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 and s2 both point to unichar strings
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const PRUnichar* s2, PRUint32 n)
{
if(s1 && s2) {
if(n != 0){
do {
PRUnichar c1 = *s1++;
PRUnichar c2 = *s2++;
if (c1 != c2) {
c1 = TOLOWER(c1);
c2 = TOLOWER(c2);
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
}
if ((0==c1) || (0==c2)) break;
} while (--n != 0);
}
}
return 0;
}
/**
* Compare a unichar string ptr to cstring.
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 points to unichar string
* @param s2 points to cstring
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strcmp(const PRUnichar* s1, const char* s2)
{
if(s1 && s2) {
for (;;) {
PRUnichar c1 = *s1++;
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
if ((0==c1) || (0==c2)) break;
}
}
return 0;
}
/**
* Compare a unichar string ptr to cstring, up to N chars.
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 points to unichar string
* @param s2 points to cstring
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strncmp(const PRUnichar* s1, const char* s2, PRUint32 n)
{
if(s1 && s2) {
if(n != 0){
do {
PRUnichar c1 = *s1++;
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
if ((0==c1) || (0==c2)) break;
} while (--n != 0);
}
}
return 0;
}
/**
* Compare a unichar string ptr to cstring without regard to case
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 points to unichar string
* @param s2 points to cstring
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strcasecmp(const PRUnichar* s1, const char* s2)
{
if(s1 && s2) {
for (;;) {
PRUnichar c1 = *s1++;
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
if (c1 != c2) {
c1 = TOLOWER(c1);
c2 = TOLOWER(c2);
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
}
if ((0==c1) || (0==c2)) break;
}
}
return 0;
}
/**
* Caseless compare up to N chars between unichar string ptr to cstring.
* NOTE: If both are null, we return 0.
* @update gess7/30/98
* @param s1 points to unichar string
* @param s2 points to cstring
* @return 0 if they match, -1 if s1<s2; 1 if s1>s2
*/
PRInt32 nsCRT::strncasecmp(const PRUnichar* s1, const char* s2, PRUint32 n)
{
if(s1 && s2){
if(n != 0){
do {
PRUnichar c1 = *s1++;
PRUnichar c2 = kIsoLatin1ToUCS2[*(const unsigned char*)s2++];
if (c1 != c2) {
c1 = TOLOWER(c1);
c2 = TOLOWER(c2);
if (c1 != c2) {
if (c1 < c2) return -1;
return 1;
}
}
if (c1 == 0) break;
} while (--n != 0);
}
}
return 0;
}
PRUnichar* nsCRT::strdup(const PRUnichar* str)
{
PRUint32 len = nsCRT::strlen(str) + 1; // add one for null
nsCppSharedAllocator<PRUnichar> shared_allocator;
PRUnichar* rslt = shared_allocator.allocate(len);
// PRUnichar* rslt = new PRUnichar[len];
if (rslt == NULL) return NULL;
nsCRT::memcpy(rslt, str, len * sizeof(PRUnichar));
return rslt;
}
PRUint32 nsCRT::HashValue(const char* us)
{
PRUint32 rv = 0;
if(us) {
char ch;
while ((ch = *us++) != 0) {
// FYI: rv = rv*37 + ch
rv = ((rv << 5) + (rv << 2) + rv) + ch;
}
}
return rv;
}
PRUint32 nsCRT::HashValue(const char* us, PRUint32* uslenp)
{
PRUint32 rv = 0;
PRUint32 len = 0;
char ch;
while ((ch = *us++) != 0) {
// FYI: rv = rv*37 + ch
rv = ((rv << 5) + (rv << 2) + rv) + ch;
len++;
}
*uslenp = len;
return rv;
}
PRUint32 nsCRT::HashValue(const PRUnichar* us)
{
PRUint32 rv = 0;
if(us) {
PRUnichar ch;
while ((ch = *us++) != 0) {
// FYI: rv = rv*37 + ch
rv = ((rv << 5) + (rv << 2) + rv) + ch;
}
}
return rv;
}
PRUint32 nsCRT::HashValue(const PRUnichar* us, PRUint32* uslenp)
{
PRUint32 rv = 0;
PRUint32 len = 0;
PRUnichar ch;
while ((ch = *us++) != 0) {
// FYI: rv = rv*37 + ch
rv = ((rv << 5) + (rv << 2) + rv) + ch;
len++;
}
*uslenp = len;
return rv;
}
PRInt32 nsCRT::atoi( const PRUnichar *string )
{
return atoi(string);
}

View File

@@ -1,239 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsCRT_h___
#define nsCRT_h___
#include <stdlib.h>
#include <string.h>
#include "plstr.h"
#include "nscore.h"
#include "prtypes.h"
#include "nsCppSharedAllocator.h"
#define CR '\015'
#define LF '\012'
#define VTAB '\013'
#define FF '\014'
#define TAB '\011'
#define CRLF "\015\012" /* A CR LF equivalent string */
#ifdef XP_MAC
# define NS_LINEBREAK "\015"
# define NS_LINEBREAK_LEN 1
#else
# ifdef XP_PC
# define NS_LINEBREAK "\015\012"
# define NS_LINEBREAK_LEN 2
# else
# if defined(XP_UNIX) || defined(XP_BEOS)
# define NS_LINEBREAK "\012"
# define NS_LINEBREAK_LEN 1
# endif /* XP_UNIX */
# endif /* XP_PC */
#endif /* XP_MAC */
extern const PRUnichar kIsoLatin1ToUCS2[256];
// This macro can be used in a class declaration for classes that want
// to ensure that their instance memory is zeroed.
#define NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW \
void* operator new(size_t sz) { \
void* rv = ::operator new(sz); \
if (rv) { \
nsCRT::zero(rv, sz); \
} \
return rv; \
} \
void operator delete(void* ptr) { \
::operator delete(ptr); \
}
// This macro works with the next macro to declare a non-inlined
// version of the above.
#define NS_DECL_ZEROING_OPERATOR_NEW \
void* operator new(size_t sz); \
void operator delete(void* ptr);
#define NS_IMPL_ZEROING_OPERATOR_NEW(_class) \
void* _class::operator new(size_t sz) { \
void* rv = ::operator new(sz); \
if (rv) { \
nsCRT::zero(rv, sz); \
} \
return rv; \
} \
void _class::operator delete(void* ptr) { \
::operator delete(ptr); \
}
// Freeing helper
#define CRTFREEIF(x) if (x) { nsCRT::free(x); x = 0; }
/// This is a wrapper class around all the C runtime functions.
class NS_COM nsCRT {
public:
/** Copy bytes from aSrc to aDest.
@param aDest the destination address
@param aSrc the source address
@param aCount the number of bytes to copy
*/
static void memcpy(void* aDest, const void* aSrc, PRUint32 aCount) {
::memcpy(aDest, aSrc, (size_t)aCount);
}
static void memmove(void* aDest, const void* aSrc, PRUint32 aCount) {
::memmove(aDest, aSrc, (size_t)aCount);
}
static void memset(void* aDest, PRUint8 aByte, PRUint32 aCount) {
::memset(aDest, aByte, aCount);
}
static void zero(void* aDest, PRUint32 aCount) {
::memset(aDest, 0, (size_t)aCount);
}
/** Compute the string length of s
@param s the string in question
@return the length of s
*/
static PRUint32 strlen(const char* s) {
return PRUint32(::strlen(s));
}
/// Compare s1 and s2.
static PRInt32 strcmp(const char* s1, const char* s2) {
return PRUint32(PL_strcmp(s1, s2));
}
static PRInt32 strncmp(const char* s1, const char* s2,
PRUint32 aMaxLen) {
return PRInt32(PL_strncmp(s1, s2, aMaxLen));
}
/// Case-insensitive string comparison.
static PRInt32 strcasecmp(const char* s1, const char* s2) {
return PRInt32(PL_strcasecmp(s1, s2));
}
/// Case-insensitive string comparison with length
static PRInt32 strncasecmp(const char* s1, const char* s2, PRUint32 aMaxLen) {
return PRInt32(PL_strncasecmp(s1, s2, aMaxLen));
}
static PRInt32 strncmp(const char* s1, const char* s2, PRInt32 aMaxLen) {
// inline the first test (assumes strings are not null):
PRInt32 diff = ((const unsigned char*)s1)[0] - ((const unsigned char*)s2)[0];
if (diff != 0) return diff;
return PRInt32(PL_strncmp(s1,s2,aMaxLen));
}
static char* strdup(const char* str) {
return PL_strdup(str);
}
static void free(char* str) {
PL_strfree(str);
}
/**
How to use this fancy (thread-safe) version of strtok:
void main( void ) {
printf( "%s\n\nTokens:\n", string );
// Establish string and get the first token:
char* newStr;
token = nsCRT::strtok( string, seps, &newStr );
while( token != NULL ) {
// While there are tokens in "string"
printf( " %s\n", token );
// Get next token:
token = nsCRT::strtok( newStr, seps, &newStr );
}
}
* WARNING - STRTOK WHACKS str THE FIRST TIME IT IS CALLED *
* MAKE A COPY OF str IF YOU NEED TO USE IT AFTER strtok() *
*/
static char* strtok(char* str, const char* delims, char* *newStr);
/// Like strlen except for ucs2 strings
static PRUint32 strlen(const PRUnichar* s);
/// Like strcmp except for ucs2 strings
static PRInt32 strcmp(const PRUnichar* s1, const PRUnichar* s2);
/// Like strcmp except for ucs2 strings
static PRInt32 strncmp(const PRUnichar* s1, const PRUnichar* s2,
PRUint32 aMaxLen);
/// Like strcasecmp except for ucs2 strings
static PRInt32 strcasecmp(const PRUnichar* s1, const PRUnichar* s2);
/// Like strncasecmp except for ucs2 strings
static PRInt32 strncasecmp(const PRUnichar* s1, const PRUnichar* s2,
PRUint32 aMaxLen);
/// Like strcmp with a char* and a ucs2 string
static PRInt32 strcmp(const PRUnichar* s1, const char* s2);
/// Like strncmp with a char* and a ucs2 string
static PRInt32 strncmp(const PRUnichar* s1, const char* s2,
PRUint32 aMaxLen);
/// Like strcasecmp with a char* and a ucs2 string
static PRInt32 strcasecmp(const PRUnichar* s1, const char* s2);
/// Like strncasecmp with a char* and a ucs2 string
static PRInt32 strncasecmp(const PRUnichar* s1, const char* s2,
PRUint32 aMaxLen);
// Note: uses new[] to allocate memory, so you must use delete[] to
// free the memory
static PRUnichar* strdup(const PRUnichar* str);
static void free(PRUnichar* str) {
nsCppSharedAllocator<PRUnichar> shared_allocator;
shared_allocator.deallocate(str, 0 /*we never new or kept the size*/);
}
/// Compute a hashcode for a C string
static PRUint32 HashValue(const char* s1);
/// Same as above except that we return the length in s1len
static PRUint32 HashValue(const char* s1, PRUint32* s1len);
/// Compute a hashcode for a ucs2 string
static PRUint32 HashValue(const PRUnichar* s1);
/// Same as above except that we return the length in s1len
static PRUint32 HashValue(const PRUnichar* s1, PRUint32* s1len);
/// String to integer.
static PRInt32 atoi( const PRUnichar *string );
static PRUnichar ToUpper(PRUnichar aChar);
static PRUnichar ToLower(PRUnichar aChar);
static PRBool IsUpper(PRUnichar aChar);
static PRBool IsLower(PRUnichar aChar);
};
#endif /* nsCRT_h___ */

View File

@@ -1,365 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsIEnumerator.h"
////////////////////////////////////////////////////////////////////////////////
// Intersection Enumerators
////////////////////////////////////////////////////////////////////////////////
class nsConjoiningEnumerator : public nsIBidirectionalEnumerator
{
public:
NS_DECL_ISUPPORTS
// nsIEnumerator methods:
NS_DECL_NSIENUMERATOR
// nsIBidirectionalEnumerator methods:
NS_DECL_NSIBIDIRECTIONALENUMERATOR
// nsConjoiningEnumerator methods:
nsConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second);
virtual ~nsConjoiningEnumerator(void);
protected:
nsIEnumerator* mFirst;
nsIEnumerator* mSecond;
nsIEnumerator* mCurrent;
};
nsConjoiningEnumerator::nsConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second)
: mFirst(first), mSecond(second), mCurrent(first)
{
NS_ADDREF(mFirst);
NS_ADDREF(mSecond);
}
nsConjoiningEnumerator::~nsConjoiningEnumerator(void)
{
NS_RELEASE(mFirst);
NS_RELEASE(mSecond);
}
NS_IMPL_ISUPPORTS2(nsConjoiningEnumerator, nsIBidirectionalEnumerator, nsIEnumerator)
NS_IMETHODIMP
nsConjoiningEnumerator::First(void)
{
mCurrent = mFirst;
return mCurrent->First();
}
NS_IMETHODIMP
nsConjoiningEnumerator::Next(void)
{
nsresult rv = mCurrent->Next();
if (NS_FAILED(rv) && mCurrent == mFirst) {
mCurrent = mSecond;
rv = mCurrent->First();
}
return rv;
}
NS_IMETHODIMP
nsConjoiningEnumerator::CurrentItem(nsISupports **aItem)
{
return mCurrent->CurrentItem(aItem);
}
NS_IMETHODIMP
nsConjoiningEnumerator::IsDone(void)
{
return (mCurrent == mFirst && mCurrent->IsDone() == NS_OK)
|| (mCurrent == mSecond && mCurrent->IsDone() == NS_OK)
? NS_OK : NS_COMFALSE;
}
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsConjoiningEnumerator::Last(void)
{
nsresult rv;
nsIBidirectionalEnumerator* be;
rv = mSecond->QueryInterface(nsIBidirectionalEnumerator::GetIID(), (void**)&be);
if (NS_FAILED(rv)) return rv;
mCurrent = mSecond;
rv = be->Last();
NS_RELEASE(be);
return rv;
}
NS_IMETHODIMP
nsConjoiningEnumerator::Prev(void)
{
nsresult rv;
nsIBidirectionalEnumerator* be;
rv = mCurrent->QueryInterface(nsIBidirectionalEnumerator::GetIID(), (void**)&be);
if (NS_FAILED(rv)) return rv;
rv = be->Prev();
NS_RELEASE(be);
if (NS_FAILED(rv) && mCurrent == mSecond) {
rv = mFirst->QueryInterface(nsIBidirectionalEnumerator::GetIID(), (void**)&be);
if (NS_FAILED(rv)) return rv;
mCurrent = mFirst;
rv = be->Last();
NS_RELEASE(be);
}
return rv;
}
////////////////////////////////////////////////////////////////////////////////
extern "C" NS_COM nsresult
NS_NewConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second,
nsIBidirectionalEnumerator* *aInstancePtrResult)
{
if (aInstancePtrResult == 0)
return NS_ERROR_NULL_POINTER;
nsConjoiningEnumerator* e = new nsConjoiningEnumerator(first, second);
if (e == 0)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(e);
*aInstancePtrResult = e;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
static nsresult
nsEnumeratorContains(nsIEnumerator* e, nsISupports* item)
{
nsresult rv;
for (e->First(); e->IsDone() != NS_OK; e->Next()) {
nsISupports* other;
rv = e->CurrentItem(&other);
if (NS_FAILED(rv)) return rv;
if (item == other) {
NS_RELEASE(other);
return NS_OK; // true -- exists in enumerator
}
NS_RELEASE(other);
}
return NS_COMFALSE; // false -- doesn't exist
}
////////////////////////////////////////////////////////////////////////////////
// Intersection Enumerators
////////////////////////////////////////////////////////////////////////////////
class nsIntersectionEnumerator : public nsIEnumerator
{
public:
NS_DECL_ISUPPORTS
// nsIEnumerator methods:
NS_DECL_NSIENUMERATOR
// nsIntersectionEnumerator methods:
nsIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second);
virtual ~nsIntersectionEnumerator(void);
protected:
nsIEnumerator* mFirst;
nsIEnumerator* mSecond;
};
nsIntersectionEnumerator::nsIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second)
: mFirst(first), mSecond(second)
{
NS_ADDREF(mFirst);
NS_ADDREF(mSecond);
}
nsIntersectionEnumerator::~nsIntersectionEnumerator(void)
{
NS_RELEASE(mFirst);
NS_RELEASE(mSecond);
}
NS_IMPL_ISUPPORTS1(nsIntersectionEnumerator, nsIEnumerator)
NS_IMETHODIMP
nsIntersectionEnumerator::First(void)
{
nsresult rv = mFirst->First();
if (NS_FAILED(rv)) return rv;
return Next();
}
NS_IMETHODIMP
nsIntersectionEnumerator::Next(void)
{
nsresult rv;
// find the first item that exists in both
for (; mFirst->IsDone() != NS_OK; mFirst->Next()) {
nsISupports* item;
rv = mFirst->CurrentItem(&item);
if (NS_FAILED(rv)) return rv;
// see if it also exists in mSecond
rv = nsEnumeratorContains(mSecond, item);
if (NS_FAILED(rv)) return rv;
NS_RELEASE(item);
if (rv == NS_OK) {
// found in both, so return leaving it as the current item of mFirst
return NS_OK;
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsIntersectionEnumerator::CurrentItem(nsISupports **aItem)
{
return mFirst->CurrentItem(aItem);
}
NS_IMETHODIMP
nsIntersectionEnumerator::IsDone(void)
{
return mFirst->IsDone();
}
////////////////////////////////////////////////////////////////////////////////
extern "C" NS_COM nsresult
NS_NewIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
nsIEnumerator* *aInstancePtrResult)
{
if (aInstancePtrResult == 0)
return NS_ERROR_NULL_POINTER;
nsIntersectionEnumerator* e = new nsIntersectionEnumerator(first, second);
if (e == 0)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(e);
*aInstancePtrResult = e;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// Union Enumerators
////////////////////////////////////////////////////////////////////////////////
class nsUnionEnumerator : public nsIEnumerator
{
public:
NS_DECL_ISUPPORTS
// nsIEnumerator methods:
NS_DECL_NSIENUMERATOR
// nsUnionEnumerator methods:
nsUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second);
virtual ~nsUnionEnumerator(void);
protected:
nsIEnumerator* mFirst;
nsIEnumerator* mSecond;
};
nsUnionEnumerator::nsUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second)
: mFirst(first), mSecond(second)
{
NS_ADDREF(mFirst);
NS_ADDREF(mSecond);
}
nsUnionEnumerator::~nsUnionEnumerator(void)
{
NS_RELEASE(mFirst);
NS_RELEASE(mSecond);
}
NS_IMPL_ISUPPORTS1(nsUnionEnumerator, nsIEnumerator)
NS_IMETHODIMP
nsUnionEnumerator::First(void)
{
nsresult rv = mFirst->First();
if (NS_FAILED(rv)) return rv;
return Next();
}
NS_IMETHODIMP
nsUnionEnumerator::Next(void)
{
nsresult rv;
// find the first item that exists in both
for (; mFirst->IsDone() != NS_OK; mFirst->Next()) {
nsISupports* item;
rv = mFirst->CurrentItem(&item);
if (NS_FAILED(rv)) return rv;
// see if it also exists in mSecond
rv = nsEnumeratorContains(mSecond, item);
if (NS_FAILED(rv)) return rv;
NS_RELEASE(item);
if (rv != NS_OK) {
// if it didn't exist in mSecond, return, making it the current item
return NS_OK;
}
// each time around, make sure that mSecond gets reset to the beginning
// so that when mFirst is done, we'll be ready to enumerate mSecond
rv = mSecond->First();
if (NS_FAILED(rv)) return rv;
}
return mSecond->Next();
}
NS_IMETHODIMP
nsUnionEnumerator::CurrentItem(nsISupports **aItem)
{
if (mFirst->IsDone() != NS_OK)
return mFirst->CurrentItem(aItem);
else
return mSecond->CurrentItem(aItem);
}
NS_IMETHODIMP
nsUnionEnumerator::IsDone(void)
{
return (mFirst->IsDone() == NS_OK && mSecond->IsDone() == NS_OK)
? NS_OK : NS_COMFALSE;
}
////////////////////////////////////////////////////////////////////////////////
extern "C" NS_COM nsresult
NS_NewUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
nsIEnumerator* *aInstancePtrResult)
{
if (aInstancePtrResult == 0)
return NS_ERROR_NULL_POINTER;
nsUnionEnumerator* e = new nsUnionEnumerator(first, second);
if (e == 0)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(e);
*aInstancePtrResult = e;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,122 +0,0 @@
#ifndef nsCppSharedAllocator_h__
#define nsCppSharedAllocator_h__
#include "nsIAllocator.h" // for |nsAllocator|
#include "nscore.h" // for |NS_XXX_CAST|
#include <new.h> // to allow placement |new|
// under Metrowerks (Mac), we don't have autoconf yet
#ifdef __MWERKS__
#define HAVE_CPP_MEMBER_TEMPLATES
#define HAVE_CPP_NUMERIC_LIMITS
#endif
#ifdef HAVE_CPP_NUMERIC_LIMITS
#include <limits>
#else
#include <limits.h>
#endif
template <class T>
class nsCppSharedAllocator
/*
...allows Standard Library containers, et al, to use our global shared
(XP)COM-aware allocator.
*/
{
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
nsCppSharedAllocator() { }
#ifdef HAVE_CPP_MEMBER_TEMPLATES
template <class U>
nsCppSharedAllocator( const nsCppSharedAllocator<U>& ) { }
#endif
~nsCppSharedAllocator() { }
pointer
address( reference r ) const
{
return &r;
}
const_pointer
address( const_reference r ) const
{
return &r;
}
pointer
allocate( size_type n, const void* /*hint*/=0 )
{
return NS_REINTERPRET_CAST(pointer, nsAllocator::Alloc(NS_STATIC_CAST(PRUint32, n*sizeof(T))));
}
void
deallocate( pointer p, size_type /*n*/ )
{
nsAllocator::Free(p);
}
void
construct( pointer p, const T& val )
{
new (p) T(val);
}
void
destroy( pointer p )
{
p->~T();
}
size_type
max_size() const
{
#ifdef HAVE_CPP_NUMERIC_LIMITS
return numeric_limits<size_type>::max() / sizeof(T);
#else
return ULONG_MAX / sizeof(T);
#endif
}
#ifdef HAVE_CPP_MEMBER_TEMPLATES
template <class U>
struct rebind
{
typedef nsCppSharedAllocator<U> other;
};
#endif
};
template <class T>
PRBool
operator==( const nsCppSharedAllocator<T>&, const nsCppSharedAllocator<T>& )
{
return PR_TRUE;
}
template <class T>
PRBool
operator!=( const nsCppSharedAllocator<T>&, const nsCppSharedAllocator<T>& )
{
return PR_FALSE;
}
#endif /* !defined(nsCppSharedAllocator_h__) */

View File

@@ -1,594 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsDeque.h"
#include "nsCRT.h"
#include <stdio.h>
//#define _SELFTEST_DEQUE 1
#undef _SELFTEST_DEQUE
/**
* Standard constructor
* @update gess4/18/98
* @return new deque
*/
nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
mDeallocator=aDeallocator;
mOrigin=mSize=0;
mData=mBuffer; // don't allocate space until you must
mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]);
nsCRT::zero(mData,mCapacity*sizeof(mBuffer[0]));
}
/**
* Destructor
* @update gess4/18/98
*/
nsDeque::~nsDeque() {
#if 0
char buffer[30];
printf("Capacity: %i\n",mCapacity);
static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
switch(mCapacity) {
case 4: mCaps[0]++; break;
case 8: mCaps[1]++; break;
case 16: mCaps[2]++; break;
case 32: mCaps[3]++; break;
case 64: mCaps[4]++; break;
case 128: mCaps[5]++; break;
case 256: mCaps[6]++; break;
case 512: mCaps[7]++; break;
case 1024: mCaps[8]++; break;
case 2048: mCaps[9]++; break;
case 4096: mCaps[10]++; break;
default:
break;
}
#endif
Erase();
if(mData && (mData!=mBuffer))
delete [] mData;
mData=0;
if(mDeallocator) {
delete mDeallocator;
}
mDeallocator=0;
}
/**
*
* @update gess4/18/98
* @param
* @return
*/
void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){
if(mDeallocator) {
delete mDeallocator;
}
mDeallocator=aDeallocator;
}
/**
* Remove all items from container without destroying them.
*
* @update gess4/18/98
* @param
* @return
*/
nsDeque& nsDeque::Empty() {
if((0<mCapacity) && (mData)) {
nsCRT::zero(mData,mCapacity*sizeof(mData));
}
mSize=0;
mOrigin=0;
return *this;
}
/**
* Remove and delete all items from container
*
* @update gess4/18/98
* @return this
*/
nsDeque& nsDeque::Erase() {
if(mDeallocator && mSize) {
ForEach(*mDeallocator);
}
return Empty();
}
/**
* This method adds an item to the end of the deque.
* This operation has the potential to cause the
* underlying buffer to resize.
*
* @update gess4/18/98
* @param anItem: new item to be added to deque
* @return nada
*/
nsDeque& nsDeque::GrowCapacity(void) {
PRInt32 theNewSize = mCapacity<<2;
void** temp=new void*[theNewSize];
//Here's the interesting part: You can't just move the elements
//directy (in situ) from the old buffer to the new one.
//Since capacity has changed, the old origin doesn't make
//sense anymore. It's better to resequence the elements now.
if(mData) {
int tempi=0;
int i=0;
int j=0;
for(i=mOrigin;i<mCapacity;i++) temp[tempi++]=mData[i]; //copy the leading elements...
for(j=0;j<mOrigin;j++) temp[tempi++]=mData[j]; //copy the trailing elements...
if(mData!=mBuffer)
delete [] mData;
}
mCapacity=theNewSize;
mOrigin=0; //now realign the origin...
mData=temp;
return *this;
}
/**
* This method adds an item to the end of the deque.
* This operation has the potential to cause the
* underlying buffer to resize.
*
* @update gess4/18/98
* @param anItem: new item to be added to deque
* @return nada
*/
nsDeque& nsDeque::Push(void* anItem) {
if(mSize==mCapacity) {
GrowCapacity();
}
int offset=mOrigin+mSize;
if(offset<mCapacity)
mData[offset]=anItem;
else mData[offset-mCapacity]=anItem;
mSize++;
return *this;
}
/**
* This method adds an item to the front of the deque.
* This operation has the potential to cause the
* underlying buffer to resize.
*
* @update gess4/18/98
* @param anItem: new item to be added to deque
* @return nada
*/
nsDeque& nsDeque::PushFront(void* anItem) {
if(mSize==mCapacity) {
GrowCapacity();
}
if(0==mOrigin){ //case1: [xxx..]
//mOrigin=mCapacity-1-mSize++;
mOrigin=mCapacity-1;
mData[mOrigin]=anItem;
}
else {// if(mCapacity==(mOrigin+mSize-1)){ //case2: [..xxx] and case3: [.xxx.]
mData[--mOrigin]=anItem;
}
mSize++;
return *this;
}
/**
* Remove and return the last item in the container.
*
* @update gess4/18/98
* @param none
* @return ptr to last item in container
*/
void* nsDeque::Pop(void) {
void* result=0;
if(mSize>0) {
int offset=mOrigin+mSize-1;
if(offset>=mCapacity)
offset-=mCapacity;
result=mData[offset];
mData[offset]=0;
mSize--;
if(0==mSize)
mOrigin=0;
}
return result;
}
/**
* This method gets called you want to remove and return
* the first member in the container.
*
* @update gess4/18/98
* @param nada
* @return last item in container
*/
void* nsDeque::PopFront() {
void* result=0;
if(mSize>0) {
NS_ASSERTION(mOrigin<mCapacity,"Error: Bad origin");
result=mData[mOrigin];
mData[mOrigin++]=0; //zero it out for debugging purposes.
mSize--;
if(mCapacity==mOrigin) //you popped off the end, so cycle back around...
mOrigin=0;
if(0==mSize)
mOrigin=0;
}
return result;
}
/**
* This method gets called you want to peek at the topmost
* member without removing it.
*
* @update gess4/18/98
* @param nada
* @return last item in container
*/
void* nsDeque::Peek() {
void* result=0;
if(mSize>0) {
result=mData[mOrigin];
}
return result;
}
/**
* Call this to retrieve the ith element from this container.
* Keep in mind that accessing the underlying elements is
* done in a relative fashion. Object 0 is not necessarily
* the first element (the first element is at mOrigin).
*
* @update gess4/18/98
* @param anIndex : 0 relative offset of item you want
* @return void* or null
*/
void* nsDeque::ObjectAt(PRInt32 anIndex) const {
void* result=0;
if((anIndex>=0) && (anIndex<mSize))
{
if(anIndex<(mCapacity-mOrigin)) {
result=mData[mOrigin+anIndex];
}
else {
result=mData[anIndex-(mCapacity-mOrigin)];
}
}
return result;
}
/**
* Create and return an iterator pointing to
* the beginning of the queue. Note that this
* takes the circular buffer semantics into account.
*
* @update gess4/18/98
* @return new deque iterator, init'ed to 1st item
*/
nsDequeIterator nsDeque::Begin(void) const{
return nsDequeIterator(*this,0);
}
/**
* Create and return an iterator pointing to
* the last of the queue. Note that this
* takes the circular buffer semantics into account.
*
* @update gess4/18/98
* @return new deque iterator, init'ed to last item
*/
nsDequeIterator nsDeque::End(void) const{
return nsDequeIterator(*this,mSize);
}
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{
int i=0;
for(i=0;i<mSize;i++){
void* obj=ObjectAt(i);
obj=aFunctor(obj);
}
}
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code. Iteration continues until your
* functor returns a non-null.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{
int i=0;
for(i=0;i<mSize;i++){
void* obj=ObjectAt(i);
obj=aFunctor(obj);
if(obj)
return obj;
}
return 0;
}
/******************************************************
* Here comes the nsDequeIterator class...
******************************************************/
/**
* DequeIterator is an object that knows how to iterate (forward and backward)
* a Deque. Normally, you don't need to do this, but there are some special
* cases where it is pretty handy, so here you go.
*
* This is a standard dequeiterator constructor
*
* @update gess4/18/98
* @param aQueue is the deque object to be iterated
* @param anIndex is the starting position for your iteration
*/
nsDequeIterator::nsDequeIterator(const nsDeque& aQueue,int anIndex): mIndex(anIndex), mDeque(aQueue) {
}
/**
* Copy construct a new iterator beginning with given
*
* @update gess4/20/98
* @param aCopy is another iterator to copy from
* @return
*/
nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy) : mIndex(aCopy.mIndex), mDeque(aCopy.mDeque) {
}
/**
* Moves iterator to first element in deque
* @update gess4/18/98
* @return this
*/
nsDequeIterator& nsDequeIterator::First(void){
mIndex=0;
return *this;
}
/**
* Standard assignment operator for dequeiterator
*
* @update gess4/18/98
* @param aCopy is an iterator to be copied from
* @return *this
*/
nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) {
//queue's are already equal.
mIndex=aCopy.mIndex;
return *this;
}
/**
* preform ! operation against to iterators to test for equivalence
* (or lack thereof)!
*
* @update gess4/18/98
* @param anIter is the object to be compared to
* @return TRUE if NOT equal.
*/
PRBool nsDequeIterator::operator!=(nsDequeIterator& anIter) {
return PRBool(!this->operator==(anIter));
}
/**
* Compare 2 iterators for equivalence.
*
* @update gess4/18/98
* @param anIter is the other iterator to be compared to
* @return TRUE if EQUAL
*/
PRBool nsDequeIterator::operator<(nsDequeIterator& anIter) {
return PRBool(((mIndex<anIter.mIndex) && (&mDeque==&anIter.mDeque)));
}
/**
* Compare 2 iterators for equivalence.
*
* @update gess4/18/98
* @param anIter is the other iterator to be compared to
* @return TRUE if EQUAL
*/
PRBool nsDequeIterator::operator==(nsDequeIterator& anIter) {
return PRBool(((mIndex==anIter.mIndex) && (&mDeque==&anIter.mDeque)));
}
/**
* Compare 2 iterators for equivalence.
*
* @update gess4/18/98
* @param anIter is the other iterator to be compared to
* @return TRUE if EQUAL
*/
PRBool nsDequeIterator::operator>=(nsDequeIterator& anIter) {
return PRBool(((mIndex>=anIter.mIndex) && (&mDeque==&anIter.mDeque)));
}
/**
* Pre-increment operator
*
* @update gess4/18/98
* @return object at preincremented index
*/
void* nsDequeIterator::operator++() {
return mDeque.ObjectAt(++mIndex);
}
/**
* Post-increment operator
*
* @update gess4/18/98
* @param param is ignored
* @return object at post-incremented index
*/
void* nsDequeIterator::operator++(int) {
return mDeque.ObjectAt(mIndex++);
}
/**
* Pre-decrement operator
*
* @update gess4/18/98
* @return object at pre-decremented index
*/
void* nsDequeIterator::operator--() {
return mDeque.ObjectAt(--mIndex);
}
/**
* Post-decrement operator
*
* @update gess4/18/98
* @param param is ignored
* @return object at post-decremented index
*/
void* nsDequeIterator::operator--(int) {
return mDeque.ObjectAt(mIndex--);
}
/**
* Dereference operator
*
* @update gess4/18/98
* @return object at ith index
*/
void* nsDequeIterator::GetCurrent(void) {
return mDeque.ObjectAt(mIndex);
}
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{
mDeque.ForEach(aFunctor);
}
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{
return mDeque.FirstThat(aFunctor);
}
#ifdef _SELFTEST_DEQUE
/**************************************************************
Now define the token deallocator class...
**************************************************************/
class _SelfTestDeallocator: public nsDequeFunctor{
public:
_SelfTestDeallocator::_SelfTestDeallocator() {
nsDeque::SelfTest();
}
virtual void* operator()(void* anObject) {
return 0;
}
};
static _SelfTestDeallocator gDeallocator;
#endif
/**
* conduct automated self test for this class
*
* @update gess4/18/98
* @param
* @return
*/
void nsDeque::SelfTest(void) {
#ifdef _SELFTEST_DEQUE
{
nsDeque theDeque(gDeallocator); //construct a simple one...
int ints[200];
int count=sizeof(ints)/sizeof(int);
int i=0;
for(i=0;i<count;i++){ //initialize'em
ints[i]=10*(1+i);
}
for(i=0;i<70;i++){
theDeque.Push(&ints[i]);
}
for(i=0;i<56;i++){
int* temp=(int*)theDeque.Pop();
}
for(i=0;i<55;i++){
theDeque.Push(&ints[i]);
}
for(i=0;i<35;i++){
int* temp=(int*)theDeque.Pop();
}
for(i=0;i<35;i++){
theDeque.Push(&ints[i]);
}
for(i=0;i<38;i++){
int* temp=(int*)theDeque.Pop();
}
}
int x;
x=10;
#endif
}

View File

@@ -1,410 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/**
* MODULE NOTES:
* @update gess 4/15/98 (tax day)
*
* The Deque is a very small, very efficient container object
* than can hold elements of type void*, offering the following features:
* It's interface supports pushing and poping of children.
* It can iterate (via an interator class) it's children.
* When full, it can efficently resize dynamically.
*
*
* NOTE: The only bit of trickery here is that this deque is
* built upon a ring-buffer. Like all ring buffers, the first
* element may not be at index[0]. The mOrigin member determines
* where the first child is. This point is quietly hidden from
* customers of this class.
*
*/
#ifndef _NSDEQUE
#define _NSDEQUE
#include "nscore.h"
/**
* The nsDequefunctor class is used when you want to create
* callbacks between the deque and your generic code.
* Use these objects in a call to ForEach();
*
* @update gess4/20/98
*/
class NS_COM nsDequeFunctor{
public:
virtual void* operator()(void* anObject)=0;
};
/******************************************************
* Here comes the nsDeque class itself...
******************************************************/
/**
* The deque (double-ended queue) class is a common container type,
* whose behavior mimics a line in your favorite checkout stand.
* Classic CS describes the common behavior of a queue as FIFO.
* A Deque allows items to be added and removed from either end of
* the queue.
*
* @update gess4/20/98
*/
class NS_COM nsDeque {
friend class nsDequeIterator;
public:
nsDeque(nsDequeFunctor* aDeallocator);
~nsDeque();
/**
* Returns the number of elements currently stored in
* this deque.
*
* @update gess4/18/98
* @param
* @return int contains element count
*/
inline PRInt32 GetSize() const { return mSize;}
/**
* Pushes new member onto the end of the deque
*
* @update gess4/18/98
* @param ptr to object to store
* @return *this
*/
nsDeque& Push(void* anItem);
/**
* Pushes new member onto the front of the deque
*
* @update gess4/18/98
* @param ptr to object to store
* @return *this
*/
nsDeque& PushFront(void* anItem);
/**
* Remove and return the first item in the container.
*
* @update gess4/18/98
* @param none
* @return ptr to first item in container
*/
void* Pop(void);
/**
* Remove and return the first item in the container.
*
* @update gess4/18/98
* @param none
* @return ptr to first item in container
*/
void* PopFront(void);
/**
* Return topmost item without removing it.
*
* @update gess4/18/98
* @param none
* @return ptr to first item in container
*/
void* Peek(void);
/**
* method used to retrieve ptr to
* ith member in container. DOesn't remove
* that item.
*
* @update gess4/18/98
* @param index of desired item
* @return ptr to ith element in list
*/
void* ObjectAt(int anIndex) const;
/**
* Remove all items from container without destroying them
*
* @update gess4/18/98
* @param
* @return
*/
nsDeque& Empty();
/**
* Remove and delete all items from container
*
* @update gess4/18/98
* @param
* @return
*/
nsDeque& Erase();
/**
* Creates a new iterator, init'ed to start of container
*
* @update gess4/18/98
* @return new dequeIterator
*/
nsDequeIterator Begin() const;
/**
* Creates a new iterator, init'ed to end of container
*
* @update gess4/18/98
* @return new dequeIterator
*/
nsDequeIterator End() const;
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
void ForEach(nsDequeFunctor& aFunctor) const;
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code. This process will interupt if
* your function returns a null to this iterator.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
const void* FirstThat(nsDequeFunctor& aFunctor) const;
void SetDeallocator(nsDequeFunctor* aDeallocator);
/**
* Perform automated selftest on the deque
*
* @update gess4/18/98
* @param
* @return
*/
static void SelfTest();
protected:
PRInt32 mSize;
PRInt32 mCapacity;
PRInt32 mOrigin;
nsDequeFunctor* mDeallocator;
void* mBuffer[8];
void** mData;
private:
/**
* Simple default constructor (PRIVATE)
*
* @update gess4/18/98
* @param
* @return
*/
nsDeque();
/**
* Copy constructor (PRIVATE)
*
* @update gess4/18/98
* @param
* @return
*/
nsDeque(const nsDeque& other);
/**
* Deque assignment operator (PRIVATE)
*
* @update gess4/18/98
* @param another deque
* @return *this
*/
nsDeque& operator=(const nsDeque& anOther);
nsDeque& GrowCapacity(void);
};
/******************************************************
* Here comes the nsDequeIterator class...
******************************************************/
class NS_COM nsDequeIterator {
public:
/**
* DequeIterator is an object that knows how to iterate (forward and backward)
* a Deque. Normally, you don't need to do this, but there are some special
* cases where it is pretty handy, so here you go.
*
* @update gess4/18/98
* @param aQueue is the deque object to be iterated
* @param anIndex is the starting position for your iteration
*/
nsDequeIterator(const nsDeque& aQueue,int anIndex=0);
/**
* DequeIterator is an object that knows how to iterate (forward and backward)
* a Deque. Normally, you don't need to do this, but there are some special
* cases where it is pretty handy, so here you go.
*
* @update gess4/18/98
* @param aQueue is the deque object to be iterated
* @param anIndex is the starting position for your iteration
*/
nsDequeIterator(const nsDequeIterator& aCopy);
/**
* Moves iterator to first element in deque
* @update gess4/18/98
* @return this
*/
nsDequeIterator& First(void);
/**
* Standard assignment operator for deque
* @update gess4/18/98
* @param
* @return
*/
nsDequeIterator& operator=(const nsDequeIterator& aCopy);
/**
* preform ! operation against to iterators to test for equivalence
* (or lack thereof)!
*
* @update gess4/18/98
* @param anIter is the object to be compared to
* @return TRUE if NOT equal.
*/
PRBool operator!=(nsDequeIterator& anIter);
/**
* Compare 2 iterators for equivalence.
*
* @update gess4/18/98
* @param anIter is the other iterator to be compared to
* @return TRUE if EQUAL
*/
PRBool operator<(nsDequeIterator& anIter);
/**
* Compare 2 iterators for equivalence.
*
* @update gess4/18/98
* @param anIter is the other iterator to be compared to
* @return TRUE if EQUAL
*/
PRBool operator==(nsDequeIterator& anIter);
/**
* Compare 2 iterators for equivalence.
*
* @update gess4/18/98
* @param anIter is the other iterator to be compared to
* @return TRUE if EQUAL
*/
PRBool operator>=(nsDequeIterator& anIter);
/**
* Pre-increment operator
*
* @update gess4/18/98
* @return object at preincremented index
*/
void* operator++();
/**
* Post-increment operator
*
* @update gess4/18/98
* @param param is ignored
* @return object at post-incremented index
*/
void* operator++(int);
/**
* Pre-decrement operator
*
* @update gess4/18/98
* @return object at pre-decremented index
*/
void* operator--();
/**
* Post-decrement operator
*
* @update gess4/18/98
* @param param is ignored
* @return object at post-decremented index
*/
void* operator--(int);
/**
* Retrieve the ptr to the iterators notion of current node
*
* @update gess4/18/98
* @return object at ith index
*/
void* GetCurrent(void);
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
void ForEach(nsDequeFunctor& aFunctor) const;
/**
* Call this method when you wanto to iterate all the
* members of the container, passing a functor along
* to call your code.
*
* @update gess4/20/98
* @param aFunctor object to call for each member
* @return *this
*/
const void* FirstThat(nsDequeFunctor& aFunctor) const;
protected:
PRInt32 mIndex;
const nsDeque& mDeque;
};
#endif

View File

@@ -1,75 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
An empty enumerator.
*/
#include "nsIEnumerator.h"
////////////////////////////////////////////////////////////////////////
class EmptyEnumeratorImpl : public nsISimpleEnumerator
{
public:
EmptyEnumeratorImpl(void) {};
virtual ~EmptyEnumeratorImpl(void) {};
// nsISupports interface
NS_IMETHOD_(nsrefcnt) AddRef(void) {
return 2;
}
NS_IMETHOD_(nsrefcnt) Release(void) {
return 1;
}
NS_IMETHOD QueryInterface(REFNSIID iid, void** result) {
if (! result)
return NS_ERROR_NULL_POINTER;
if (iid.Equals(nsISimpleEnumerator::GetIID()) ||
iid.Equals(NS_GET_IID(nsISupports))) {
*result = (nsISimpleEnumerator*) this;
NS_ADDREF(this);
return NS_OK;
}
return NS_NOINTERFACE;
}
// nsISimpleEnumerator
NS_IMETHOD HasMoreElements(PRBool* aResult) {
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHOD GetNext(nsISupports** aResult) {
return NS_ERROR_UNEXPECTED;
}
};
extern "C" NS_COM nsresult
NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult)
{
static EmptyEnumeratorImpl gEmptyEnumerator;
*aResult = &gEmptyEnumerator;
return NS_OK;
}

View File

@@ -1,228 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsEnumeratorUtils.h"
nsArrayEnumerator::nsArrayEnumerator(nsISupportsArray* aValueArray)
: mValueArray(aValueArray),
mIndex(0)
{
NS_INIT_REFCNT();
NS_IF_ADDREF(mValueArray);
}
nsArrayEnumerator::~nsArrayEnumerator(void)
{
NS_IF_RELEASE(mValueArray);
}
NS_IMPL_ISUPPORTS1(nsArrayEnumerator, nsISimpleEnumerator)
NS_IMETHODIMP
nsArrayEnumerator::HasMoreElements(PRBool* aResult)
{
NS_PRECONDITION(aResult != 0, "null ptr");
if (! aResult)
return NS_ERROR_NULL_POINTER;
PRUint32 cnt;
nsresult rv = mValueArray->Count(&cnt);
if (NS_FAILED(rv)) return rv;
*aResult = (mIndex < (PRInt32) cnt);
return NS_OK;
}
NS_IMETHODIMP
nsArrayEnumerator::GetNext(nsISupports** aResult)
{
NS_PRECONDITION(aResult != 0, "null ptr");
if (! aResult)
return NS_ERROR_NULL_POINTER;
PRUint32 cnt;
nsresult rv = mValueArray->Count(&cnt);
if (NS_FAILED(rv)) return rv;
if (mIndex >= (PRInt32) cnt)
return NS_ERROR_UNEXPECTED;
*aResult = mValueArray->ElementAt(mIndex++);
return NS_OK;
}
extern "C" NS_COM nsresult
NS_NewArrayEnumerator(nsISimpleEnumerator* *result,
nsISupportsArray* array)
{
nsArrayEnumerator* enumer = new nsArrayEnumerator(array);
if (enumer == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(enumer);
*result = enumer;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
nsSingletonEnumerator::nsSingletonEnumerator(nsISupports* aValue)
: mValue(aValue)
{
NS_INIT_REFCNT();
NS_IF_ADDREF(mValue);
mConsumed = (mValue ? PR_FALSE : PR_TRUE);
}
nsSingletonEnumerator::~nsSingletonEnumerator()
{
NS_IF_RELEASE(mValue);
}
NS_IMPL_ISUPPORTS1(nsSingletonEnumerator, nsISimpleEnumerator)
NS_IMETHODIMP
nsSingletonEnumerator::HasMoreElements(PRBool* aResult)
{
NS_PRECONDITION(aResult != 0, "null ptr");
if (! aResult)
return NS_ERROR_NULL_POINTER;
*aResult = !mConsumed;
return NS_OK;
}
NS_IMETHODIMP
nsSingletonEnumerator::GetNext(nsISupports** aResult)
{
NS_PRECONDITION(aResult != 0, "null ptr");
if (! aResult)
return NS_ERROR_NULL_POINTER;
if (mConsumed)
return NS_ERROR_UNEXPECTED;
mConsumed = PR_TRUE;
NS_ADDREF(mValue);
*aResult = mValue;
return NS_OK;
}
extern "C" NS_COM nsresult
NS_NewSingletonEnumerator(nsISimpleEnumerator* *result,
nsISupports* singleton)
{
nsSingletonEnumerator* enumer = new nsSingletonEnumerator(singleton);
if (enumer == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(enumer);
*result = enumer;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
nsAdapterEnumerator::nsAdapterEnumerator(nsIEnumerator* aEnum)
: mEnum(aEnum), mCurrent(0), mStarted(PR_FALSE)
{
NS_INIT_REFCNT();
NS_ADDREF(mEnum);
}
nsAdapterEnumerator::~nsAdapterEnumerator()
{
NS_RELEASE(mEnum);
NS_IF_RELEASE(mCurrent);
}
NS_IMPL_ISUPPORTS1(nsAdapterEnumerator, nsISimpleEnumerator)
NS_IMETHODIMP
nsAdapterEnumerator::HasMoreElements(PRBool* aResult)
{
nsresult rv;
if (mCurrent) {
*aResult = PR_TRUE;
return NS_OK;
}
if (! mStarted) {
mStarted = PR_TRUE;
rv = mEnum->First();
if (rv == NS_OK) {
mEnum->CurrentItem(&mCurrent);
*aResult = PR_TRUE;
}
else {
*aResult = PR_FALSE;
}
}
else {
*aResult = PR_FALSE;
rv = mEnum->IsDone();
if (rv != NS_OK) {
// We're not done. Advance to the next one.
rv = mEnum->Next();
if (rv == NS_OK) {
mEnum->CurrentItem(&mCurrent);
*aResult = PR_TRUE;
}
}
}
return NS_OK;
}
NS_IMETHODIMP
nsAdapterEnumerator::GetNext(nsISupports** aResult)
{
nsresult rv;
PRBool hasMore;
rv = HasMoreElements(&hasMore);
if (NS_FAILED(rv)) return rv;
if (! hasMore)
return NS_ERROR_UNEXPECTED;
// No need to addref, we "transfer" the ownership to the caller.
*aResult = mCurrent;
mCurrent = 0;
return NS_OK;
}
extern "C" NS_COM nsresult
NS_NewAdapterEnumerator(nsISimpleEnumerator* *result,
nsIEnumerator* enumerator)
{
nsAdapterEnumerator* enumer = new nsAdapterEnumerator(enumerator);
if (enumer == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(enumer);
*result = enumer;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,97 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsEnumeratorUtils_h__
#define nsEnumeratorUtils_h__
#include "nsIEnumerator.h"
#include "nsISupportsArray.h"
class NS_COM nsArrayEnumerator : public nsISimpleEnumerator
{
public:
// nsISupports interface
NS_DECL_ISUPPORTS
// nsISimpleEnumerator interface
NS_IMETHOD HasMoreElements(PRBool* aResult);
NS_IMETHOD GetNext(nsISupports** aResult);
// nsRDFArrayEnumerator methods
nsArrayEnumerator(nsISupportsArray* aValueArray);
virtual ~nsArrayEnumerator(void);
protected:
nsISupportsArray* mValueArray;
PRInt32 mIndex;
};
extern "C" NS_COM nsresult
NS_NewArrayEnumerator(nsISimpleEnumerator* *result,
nsISupportsArray* array);
////////////////////////////////////////////////////////////////////////////////
class NS_COM nsSingletonEnumerator : public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
// nsISimpleEnumerator methods
NS_IMETHOD HasMoreElements(PRBool* aResult);
NS_IMETHOD GetNext(nsISupports** aResult);
nsSingletonEnumerator(nsISupports* aValue);
virtual ~nsSingletonEnumerator();
protected:
nsISupports* mValue;
PRBool mConsumed;
};
extern "C" NS_COM nsresult
NS_NewSingletonEnumerator(nsISimpleEnumerator* *result,
nsISupports* singleton);
////////////////////////////////////////////////////////////////////////////////
class NS_COM nsAdapterEnumerator : public nsISimpleEnumerator
{
public:
NS_DECL_ISUPPORTS
// nsISimpleEnumerator methods
NS_IMETHOD HasMoreElements(PRBool* aResult);
NS_IMETHOD GetNext(nsISupports** aResult);
nsAdapterEnumerator(nsIEnumerator* aEnum);
virtual ~nsAdapterEnumerator();
protected:
nsIEnumerator* mEnum;
nsISupports* mCurrent;
PRBool mStarted;
};
extern "C" NS_COM nsresult
NS_NewAdapterEnumerator(nsISimpleEnumerator* *result,
nsIEnumerator* enumerator);
////////////////////////////////////////////////////////////////////////
#endif /* nsEnumeratorUtils_h__ */

View File

@@ -1,67 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIArena_h___
#define nsIArena_h___
#include "nscore.h"
#include "nsISupports.h"
#define NS_MIN_ARENA_BLOCK_SIZE 64
#define NS_DEFAULT_ARENA_BLOCK_SIZE 4096
/// Interface IID for nsIArena
#define NS_IARENA_IID \
{ 0xa24fdad0, 0x93b4, 0x11d1, \
{0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} }
#define NS_ARENA_PROGID "component://netscape/arena"
#define NS_ARENA_CLASSNAME "Arena"
/** Interface to a memory arena abstraction. Arena's use large blocks
* of memory to allocate smaller objects. Arena's provide no free
* operator; instead, all of the objects in the arena are deallocated
* by deallocating the arena (e.g. when it's reference count goes to
* zero)
*/
class nsIArena : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IARENA_IID; return iid; }
NS_IMETHOD Init(PRUint32 arenaBlockSize) = 0;
NS_IMETHOD_(void*) Alloc(PRUint32 size) = 0;
};
/**
* Create a new arena using the desired block size for allocating the
* underlying memory blocks. The underlying memory blocks are allocated
* using the PR heap.
*/
extern NS_COM nsresult NS_NewHeapArena(nsIArena** aInstancePtrResult,
PRUint32 aArenaBlockSize = 0);
#define NS_ARENA_CID \
{ /* 9832ec80-0d6b-11d3-9331-00104ba0fd40 */ \
0x9832ec80, \
0x0d6b, \
0x11d3, \
{0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#endif /* nsIArena_h___ */

View File

@@ -1,82 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code,
* released March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998-1999 Netscape Communications Corporation. All Rights
* Reserved.
*
* Contributors:
*
*/
#include "nsISupports.idl"
interface nsISizeOfHandler;
[ref] native nsStringRef(nsString);
%{ C++
class nsString;
%}
[uuid(3d1b15b0-93b4-11d1-895b-006008911b81)]
interface nsIAtom : nsISupports
{
/**
* Translate the unicode string into the stringbuf.
*/
void ToString(in nsStringRef aString);
/**
* Return a pointer to a zero terminated unicode string.
*/
void GetUnicode([shared, retval] out wstring aResult);
/**
* Get the size, in bytes, of the atom.
*/
PRUint32 SizeOf(in nsISizeOfHandler aHandler);
};
%{C++
/**
* Find an atom that matches the given iso-latin1 C string. The
* C string is translated into it's unicode equivalent.
*/
extern NS_COM nsIAtom* NS_NewAtom(const char* isolatin1);
/**
* Find an atom that matches the given unicode string. The string is assumed
* to be zero terminated.
*/
extern NS_COM nsIAtom* NS_NewAtom(const PRUnichar* unicode);
/**
* Find an atom that matches the given string.
*/
extern NS_COM nsIAtom* NS_NewAtom(const nsString& aString);
/**
* Return a count of the total number of atoms currently
* alive in the system.
*/
extern NS_COM nsrefcnt NS_GetNumberOfAtoms(void);
extern NS_COM void NS_PurgeAtomTable(void);
%}

View File

@@ -1,312 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIBuffer_h___
#define nsIBuffer_h___
/**
* nsIBuffer is something that we use to implement pipes (buffered
* input/output stream pairs). It might be useful to you for other
* purposes, but if not, oh well.
*
* One of the important things to understand about pipes is how
* they work with respect to EOF and result values. The following
* table describes:
*
* | empty & not EOF | full | reader closed | writer closed |
* -------------------------------------------------------------------------------------------------------------
* buffer Read | readCount == 0 | readCount == N | N/A | readCount == N, return NS_OK -or- |
* operations | return WOULD_BLOCK | return NS_OK | | readCount == 0, return EOF |
* -------------------------------------------------------------------------------------------------------------
* buffer Write | writeCount == N | writeCount == 0 | N/A | assertion! |
* operations | return NS_OK | return WOULD_BLOCK | | |
* -------------------------------------------------------------------------------------------------------------
* input stream | readCount == 0 | readCount == N | assertion! | readCount == N, return NS_OK -or- |
* Read ops | return WOULD_BLOCK | return NS_OK | | readCount == 0, return EOF |
* -------------------------------------------------------------------------------------------------------------
* output stream | writeCount == N | writeCount == 0 | return | assertion! |
* Write ops | return NS_OK | return WOULD_BLOCK | STREAM_CLOSED | |
* -------------------------------------------------------------------------------------------------------------
*/
#include "nsISupports.h"
#include "nscore.h"
class nsIInputStream;
class nsIAllocator;
class nsIBufferInputStream;
class nsIBufferOutputStream;
class nsIBufferObserver;
#define NS_IBUFFER_IID \
{ /* 1eebb300-fb8b-11d2-9324-00104ba0fd40 */ \
0x1eebb300, \
0xfb8b, \
0x11d2, \
{0x93, 0x24, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#define NS_BUFFER_CID \
{ /* 5dbe4de0-fbab-11d2-9324-00104ba0fd40 */ \
0x5dbe4de0, \
0xfbab, \
0x11d2, \
{0x93, 0x24, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#define NS_BUFFER_PROGID "component://netscape/buffer"
#define NS_BUFFER_CLASSNAME "Buffer"
/**
* The signature for the reader function passed to WriteSegment. This
* specifies where the data should come from that gets written into the buffer.
* Implementers should return the following:
* @return NS_OK and readCount - if successfully read something
* @return NS_BASE_STREAM_EOF - if no more to read
* @return NS_BASE_STREAM_WOULD_BLOCK - if there is currently no data (in
* a non-blocking mode)
* @return <other-error> - on failure
*/
typedef NS_CALLBACK(nsReadSegmentFun)(void* closure,
char* toRawSegment,
PRUint32 fromOffset,
PRUint32 count,
PRUint32 *readCount);
/**
* The signature of the writer function passed to ReadSegments. This
* specifies where the data should go that gets read from the buffer.
* Implementers should return the following:
* @return NS_OK and writeCount - if successfully wrote something
* @return NS_BASE_STREAM_CLOSED - if no more can be written
* @return NS_BASE_STREAM_WOULD_BLOCK - if there is currently space to write (in
* a non-blocking mode)
* @return <other-error> - on failure
*/
typedef NS_CALLBACK(nsWriteSegmentFun)(void* closure,
const char* fromRawSegment,
PRUint32 toOffset,
PRUint32 count,
PRUint32 *writeCount);
class nsIBuffer : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBUFFER_IID);
/**
* The segment overhead is the amount of space chopped out of each
* segment for implementation purposes. The remainder of the segment
* is available for data, e.g.:
* segmentDataSize = growBySize - SEGMENT_OVERHEAD;
*/
enum { SEGMENT_OVERHEAD = 8 };
/**
* Initializes a buffer. The segment size (including overhead) will
* start from and increment by the growBySize, until reaching maxSize.
* The size of the data that can fit in a segment will be the growBySize
* minus SEGMENT_OVERHEAD bytes.
*/
NS_IMETHOD Init(PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer, nsIAllocator* allocator) = 0;
////////////////////////////////////////////////////////////////////////////
// Methods for Readers
/**
* Reads from the read cursor into a char buffer up to a specified length.
*/
NS_IMETHOD Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) = 0;
/**
* This read method allows you to pass a callback function that gets called
* repeatedly for each buffer segment until the entire amount is read.
* This avoids the need to copy data to/from and intermediate buffer.
*/
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
PRUint32 *readCount) = 0;
/**
* Returns the raw char buffer segment and its length available for reading.
* @param segmentLogicalOffset - The offset from the current read cursor for
* the segment to be returned. If this is beyond the available written area,
* NULL is returned for the resultSegment.
* @param resultSegment - The resulting read segment.
* @param resultSegmentLength - The resulting read segment length.
*
* @return NS_OK - if a read segment is successfully returned, or if
* the requested offset is at or beyond the write cursor (in which case
* the resultSegment will be nsnull and the resultSegmentLen will be 0)
* @return NS_BASE_STREAM_WOULD_BLOCK - if the buffer size becomes 0
* @return any error set by SetCondition if the requested offset is at
* or beyond the write cursor (in which case the resultSegment will be
* nsnull and the resultSegmentLen will be 0). Note that NS_OK will be
* returned if SetCondition has not been called.
* @return any error returned by OnEmpty
*/
NS_IMETHOD GetReadSegment(PRUint32 segmentLogicalOffset,
const char* *resultSegment,
PRUint32 *resultSegmentLen) = 0;
/**
* Returns the amount of data currently in the buffer available for reading.
*/
NS_IMETHOD GetReadableAmount(PRUint32 *amount) = 0;
/**
* Searches for a string in the buffer. Since the buffer has a notion
* of EOF, it is possible that the string may at some time be in the
* buffer, but is is not currently found up to some offset. Consequently,
* both the found and not found cases return an offset:
* if found, return offset where it was found
* if not found, return offset of the first byte not searched
* In the case the buffer is at EOF and the string is not found, the first
* byte not searched will correspond to the length of the buffer.
*/
NS_IMETHOD Search(const char* forString, PRBool ignoreCase,
PRBool *found, PRUint32 *offsetSearchedTo) = 0;
/**
* Sets that the reader has closed their end of the stream.
*/
NS_IMETHOD ReaderClosed(void) = 0;
/**
* Tests whether EOF marker is set. Note that this does not necessarily mean that
* all the data in the buffer has yet been consumed.
*/
NS_IMETHOD GetCondition(nsresult *result) = 0;
////////////////////////////////////////////////////////////////////////////
// Methods for Writers
/**
* Writes from a char buffer up to a specified length.
* @param writeCount - The amount that could be written. If the buffer becomes full,
* this could be less then the specified bufLen.
*/
NS_IMETHOD Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount) = 0;
/**
* Writes from an input stream up to a specified count of bytes.
* @param writeCount - The amount that could be written. If the buffer becomes full,
* this could be less then the specified count.
*/
NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount) = 0;
/**
* This write method allows you to pass a callback function that gets called
* repeatedly for each buffer segment until the entire amount is written.
* This avoids the need to copy data to/from and intermediate buffer.
*/
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
PRUint32 *writeCount) = 0;
/**
* Returns the raw char buffer segment and its length available for writing.
* @param resultSegment - The resulting write segment.
* @param resultSegmentLength - The resulting write segment length.
*
* @return NS_OK - if there is a segment available to write to
* @return NS_BASE_STREAM_CLOSED - if ReaderClosed has been called
* @return NS_BASE_STREAM_WOULD_BLOCK - if the max buffer size is exceeded
* @return NS_ERROR_OUT_OF_MEMORY - if a new segment could not be allocated
* @return any error returned by OnFull
*/
NS_IMETHOD GetWriteSegment(char* *resultSegment,
PRUint32 *resultSegmentLen) = 0;
/**
* Returns the amount of space currently in the buffer available for writing.
*/
NS_IMETHOD GetWritableAmount(PRUint32 *amount) = 0;
/**
* Returns whether the reader has closed their end of the stream.
*/
NS_IMETHOD GetReaderClosed(PRBool *result) = 0;
/**
* Sets an EOF marker (typcially done by the writer) so that a reader can be informed
* when all the data in the buffer is consumed. After the EOF marker has been
* set, all subsequent calls to the above write methods will return NS_BASE_STREAM_EOF.
*/
NS_IMETHOD SetCondition(nsresult condition) = 0;
};
////////////////////////////////////////////////////////////////////////////////
#define NS_IBUFFEROBSERVER_IID \
{ /* 0c18bef0-22a8-11d3-9349-00104ba0fd40 */ \
0x0c18bef0, \
0x22a8, \
0x11d3, \
{0x93, 0x49, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
/**
* A buffer observer is used to detect when the buffer becomes completely full
* or completely empty.
*/
class nsIBufferObserver : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBUFFEROBSERVER_IID);
NS_IMETHOD OnFull(nsIBuffer* buffer) = 0;
NS_IMETHOD OnWrite(nsIBuffer*, PRUint32 amount) = 0;
NS_IMETHOD OnEmpty(nsIBuffer* buffer) = 0;
};
////////////////////////////////////////////////////////////////////////////////
/**
* Creates a new buffer.
* @param observer - may be null
*/
extern NS_COM nsresult
NS_NewBuffer(nsIBuffer* *result,
PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer);
/**
* Creates a new buffer, allocating segments from virtual memory pages.
*/
extern NS_COM nsresult
NS_NewPageBuffer(nsIBuffer* *result,
PRUint32 growBySize, PRUint32 maxSize,
nsIBufferObserver* observer);
extern NS_COM nsresult
NS_NewBufferInputStream(nsIBufferInputStream* *result,
nsIBuffer* buffer, PRBool blocking = PR_FALSE);
extern NS_COM nsresult
NS_NewBufferOutputStream(nsIBufferOutputStream* *result,
nsIBuffer* buffer, PRBool blocking = PR_FALSE);
extern NS_COM nsresult
NS_NewPipe(nsIBufferInputStream* *inStrResult,
nsIBufferOutputStream* *outStrResult,
PRUint32 growBySize, PRUint32 maxSize,
PRBool blocking, nsIBufferObserver* observer);
////////////////////////////////////////////////////////////////////////////////
#endif // nsIBuffer_h___

View File

@@ -1,76 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIByteBuffer_h___
#define nsIByteBuffer_h___
#include "nscore.h"
#include "nsISupports.h"
class nsIInputStream;
#define NS_IBYTE_BUFFER_IID \
{ 0xe4a6e4b0, 0x93b4, 0x11d1, \
{0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} }
#define NS_IBYTEBUFFER_IID \
{ 0xe4a6e4b0, 0x93b4, 0x11d1, \
{0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} }
#define NS_BYTEBUFFER_PROGID "component://netscape/byte-buffer"
#define NS_BYTEBUFFER_CLASSNAME "Byte Buffer"
/** Interface to a buffer that holds bytes */
class nsIByteBuffer : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IBYTEBUFFER_IID; return iid; }
NS_IMETHOD Init(PRUint32 aBufferSize) = 0;
/** @return length of buffer, i.e. how many bytes are currently in it. */
NS_IMETHOD_(PRUint32) GetLength(void) const = 0;
/** @return number of bytes allocated in the buffer */
NS_IMETHOD_(PRUint32) GetBufferSize(void) const = 0;
/** @return the buffer */
NS_IMETHOD_(char*) GetBuffer(void) const = 0;
/** Grow buffer to aNewSize bytes. */
NS_IMETHOD_(PRBool) Grow(PRUint32 aNewSize) = 0;
/** Fill the buffer with data from aStream. Don't grow the buffer, only
* read until length of buffer equals buffer size. */
NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIInputStream* aStream,
PRUint32 aKeep) = 0;
};
#define NS_BYTEBUFFER_CID \
{ /* a49d5280-0d6b-11d3-9331-00104ba0fd40 */ \
0xa49d5280, \
0x0d6b, \
0x11d3, \
{0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
/** Create a new byte buffer using the given buffer size. */
extern NS_COM nsresult
NS_NewByteBuffer(nsIByteBuffer** aInstancePtrResult,
nsISupports* aOuter,
PRUint32 aBufferSize = 0);
#endif /* nsIByteBuffer_h___ */

View File

@@ -1,38 +0,0 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsISupports.idl"
#include "nsIEnumerator.idl"
[scriptable, uuid(83b6019c-cbc4-11d2-8cca-0060b0fc14a3)]
interface nsICollection : nsISupports
{
PRUint32 Count();
nsISupports GetElementAt(in PRUint32 index);
void QueryElementAt(in PRUint32 index, in nsIIDRef uuid,
[iid_is(uuid),retval] out nsQIResult result);
void SetElementAt(in PRUint32 index, in nsISupports item);
void AppendElement(in nsISupports item);
void RemoveElement(in nsISupports item);
nsIEnumerator Enumerate();
void Clear();
};

View File

@@ -1,95 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsISupports.idl"
[scriptable, uuid(D1899240-F9D2-11D2-BDD6-000064657374)]
interface nsISimpleEnumerator : nsISupports {
boolean HasMoreElements();
nsISupports GetNext();
};
/*
* DO NOT USE THIS INTERFACE. IT IS HORRIBLY BROKEN, USES NS_COMFALSE
* AND IS BASICALLY IMPOSSIBLE TO USE CORRECTLY THROUGH PROXIES OR
* XPCONNECT. IF YOU SEE NEW USES OF THIS INTERFACE IN CODE YOU ARE
* REVIEWING, YOU SHOULD INSIST ON nsISimpleEnumerator.
*
* DON'T MAKE ME COME OVER THERE.
*/
[scriptable, uuid(ad385286-cbc4-11d2-8cca-0060b0fc14a3)]
interface nsIEnumerator : nsISupports {
/** First will reset the list. will return NS_FAILED if no items
*/
void first();
/** Next will advance the list. will return failed if already at end
*/
void next();
/** CurrentItem will return the CurrentItem item it will fail if the
* list is empty
*/
nsISupports currentItem();
/** return if the collection is at the end. that is the beginning following
* a call to Prev and it is the end of the list following a call to next
*/
void isDone();
};
[uuid(75f158a0-cadd-11d2-8cca-0060b0fc14a3)]
interface nsIBidirectionalEnumerator : nsIEnumerator {
/** Last will reset the list to the end. will return NS_FAILED if no items
*/
void Last();
/** Prev will decrement the list. will return failed if already at beginning
*/
void Prev();
};
%{C++
extern "C" NS_COM nsresult
NS_NewEmptyEnumerator(nsISimpleEnumerator** aResult);
// Construct and return an implementation of a "conjoining enumerator." This
// enumerator lets you string together two other enumerators into one sequence.
// The result is an nsIBidirectionalEnumerator, but if either input is not
// also bidirectional, the Last and Prev operations will fail.
extern "C" NS_COM nsresult
NS_NewConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second,
nsIBidirectionalEnumerator* *aInstancePtrResult);
// Construct and return an implementation of a "union enumerator." This
// enumerator will only return elements that are found in both constituent
// enumerators.
extern "C" NS_COM nsresult
NS_NewUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
nsIEnumerator* *aInstancePtrResult);
// Construct and return an implementation of an "intersection enumerator." This
// enumerator will return elements that are found in either constituent
// enumerators, eliminating duplicates.
extern "C" NS_COM nsresult
NS_NewIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
nsIEnumerator* *aInstancePtrResult);
%}

View File

@@ -1,44 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsISupports.idl"
[scriptable, uuid(DB242E01-E4D9-11d2-9DDE-000064657374)]
interface nsIObserver : nsISupports {
/*------------------------------- Observe ----------------------------------
| Called when aTopic changes for aSubject (presumably; it is actually |
| called whenever anyone calls nsIObserverService::Notify for aTopic). |
| |
| Implement this in your class to handle the event appropriately. If |
| your observer objects can respond to multiple topics and/or subjects, |
| then you will have to filter accordingly. |
--------------------------------------------------------------------------*/
void Observe( in nsISupports aSubject,
in wstring aTopic,
in wstring someData );
};
%{C++
#define NS_OBSERVER_PROGID "component://netscape/xpcom/observer"
#define NS_OBSERVER_CLASSNAME "Observer"
%}

View File

@@ -1,48 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIObserverList_h__
#define nsIObserverList_h__
#include "nsISupports.h"
#include "nsIObserver.h"
#include "nsIEnumerator.h"
#include "nscore.h"
// {E777D482-E6E3-11d2-8ACD-00105A1B8860}
#define NS_IOBSERVERLIST_IID \
{ 0xe777d482, 0xe6e3, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
// {E777D484-E6E3-11d2-8ACD-00105A1B8860}
#define NS_OBSERVERLIST_CID \
{ 0xe777d484, 0xe6e3, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
class nsIObserverList : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IOBSERVERLIST_IID; return iid; }
NS_IMETHOD AddObserver(nsIObserver** anObserver) = 0;
NS_IMETHOD RemoveObserver(nsIObserver** anObserver) = 0;
NS_IMETHOD EnumerateObserverList(nsIEnumerator** anEnumerator) = 0;
};
extern NS_COM nsresult NS_NewObserverList(nsIObserverList** anObserverList);
#endif /* nsIObserverList_h__ */

View File

@@ -1,41 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsISupports.idl"
#include "nsIObserver.idl"
#include "nsIEnumerator.idl"
[scriptable, uuid(D07F5192-E3D1-11d2-8ACD-00105A1B8860)]
interface nsIObserverService : nsISupports {
void AddObserver( in nsIObserver anObserver, in wstring aTopic );
void RemoveObserver( in nsIObserver anObserver, in wstring nsString );
nsIEnumerator EnumerateObserverList( in wstring aTopic );
void Notify( in nsISupports aSubject,
in wstring aTopic,
in wstring someData );
};
%{C++
#define NS_OBSERVERSERVICE_PROGID "component://netscape/observer-service"
#define NS_OBSERVERSERVICE_CLASSNAME "Observer Service"
%}

View File

@@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIPageManager_h__
#define nsIPageManager_h__
#include "nsISupports.h"
#define NS_PAGEMGR_PAGE_BITS 12 // 4k pages
#define NS_PAGEMGR_PAGE_SIZE (1 << NS_PAGEMGR_PAGE_BITS)
#define NS_PAGEMGR_PAGE_MASK (NS_PAGEMGR_PAGE_SIZE - 1)
#define NS_PAGEMGR_PAGE_COUNT(bytes) (((bytes) + NS_PAGEMGR_PAGE_MASK) >> NS_PAGEMGR_PAGE_BITS)
#define NS_IPAGEMANAGER_IID \
{ /* bea98210-fb7b-11d2-9324-00104ba0fd40 */ \
0xbea98210, \
0xfb7b, \
0x11d2, \
{0x93, 0x24, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#define NS_PAGEMANAGER_CID \
{ /* cac907e0-fb7b-11d2-9324-00104ba0fd40 */ \
0xcac907e0, \
0xfb7b, \
0x11d2, \
{0x93, 0x24, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#define NS_PAGEMANAGER_PROGID "component://netscape/page-manager"
#define NS_PAGEMANAGER_CLASSNAME "Page Manager"
class nsIPageManager : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPAGEMANAGER_IID);
NS_IMETHOD AllocPages(PRUint32 pageCount, void* *result) = 0;
NS_IMETHOD DeallocPages(PRUint32 pageCount, void* pages) = 0;
};
#endif // nsIPageManager_h__

View File

@@ -1,150 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIProperties_h___
#define nsIProperties_h___
#include "nsISupports.h"
#include "nsIEnumerator.h"
#include "nsISupportsArray.h"
#define NS_IPROPERTIES_IID \
{ /* f42bc870-dc17-11d2-9311-00e09805570f */ \
0xf42bc870, \
0xdc17, \
0x11d2, \
{0x93, 0x11, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \
}
#define NS_PROPERTIES_CID \
{ /* b3efe4d0-0d6b-11d3-9331-00104ba0fd40 */ \
0xb3efe4d0, \
0x0d6b, \
0x11d3, \
{0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#define NS_PROPERTIES_PROGID "component://netscape/properties"
#define NS_PROPERTIES_CLASSNAME "Properties"
class nsIProperties : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_IPROPERTIES_IID; return iid; }
/**
* Defines a new property.
* @return NS_ERROR_FAILURE if a property is already defined.
*/
NS_IMETHOD DefineProperty(const char* prop, nsISupports* initialValue) = 0;
/**
* Undefines a property.
* @return NS_ERROR_FAILURE if a property is not already defined.
*/
NS_IMETHOD UndefineProperty(const char* prop) = 0;
/**
* Gets a property.
* @return NS_ERROR_FAILURE if a property is not already defined.
*/
NS_IMETHOD GetProperty(const char* prop, nsISupports* *result) = 0;
/**
* Sets a property.
* @return NS_ERROR_FAILURE if a property is not already defined.
*/
NS_IMETHOD SetProperty(const char* prop, nsISupports* value) = 0;
/**
* @return NS_OK if the property exists with the specified value
* @return NS_COMFALSE if the property does not exist, or doesn't have
* the specified value (values are compared with ==)
*/
NS_IMETHOD HasProperty(const char* prop, nsISupports* value) = 0;
};
// Returns a default implementation of an nsIProperties object.
extern nsresult
NS_NewIProperties(nsIProperties* *result);
////////////////////////////////////////////////////////////////////////////////
#include "nsID.h"
#include "nsIInputStream.h"
#include "nsIOutputStream.h"
#include "nsString.h"
// {1A180F60-93B2-11d2-9B8B-00805F8A16D9}
#define NS_IPERSISTENTPROPERTIES_IID \
{ 0x1a180f60, 0x93b2, 0x11d2, \
{ 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
// {2245E573-9464-11d2-9B8B-00805F8A16D9}
NS_DECLARE_ID(kPersistentPropertiesCID,
0x2245e573, 0x9464, 0x11d2, 0x9b, 0x8b, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9);
#define NS_PERSISTENTPROPERTIES_PROGID "component://netscape/persistent-properties"
#define NS_PERSISTENTPROPERTIES_CLASSNAME "Persistent Properties"
class nsIPersistentProperties : public nsIProperties
{
public:
static const nsIID& GetIID() { static nsIID iid = NS_IPERSISTENTPROPERTIES_IID; return iid; }
NS_IMETHOD Load(nsIInputStream* aIn) = 0;
NS_IMETHOD Save(nsIOutputStream* aOut, const nsString& aHeader) = 0;
NS_IMETHOD Subclass(nsIPersistentProperties* aSubclass) = 0;
/**
* Enumerates the properties in the supplied enumerator.
* @return NS_ERROR_FAILURE if no properties to enumerate
*/
NS_IMETHOD EnumerateProperties(nsIBidirectionalEnumerator** aResult) = 0;
// XXX these 2 methods will be subsumed by the ones from
// nsIProperties once we figure this all out
NS_IMETHOD GetStringProperty(const nsString& aKey, nsString& aValue) = 0;
NS_IMETHOD SetStringProperty(const nsString& aKey, nsString& aNewValue,
nsString& aOldValue) = 0;
};
////////////////////////////////////////////////////////////////////////////////
// {C23C10B3-0E1A-11d3-A430-0060B0EB5963}
#define NS_IPROPERTYELEMENT_IID \
{ 0xc23c10b3, 0xe1a, 0x11d3, \
{ 0xa4, 0x30, 0x0, 0x60, 0xb0, 0xeb, 0x59, 0x63 } }
// {579C0568-0E1B-11d3-A430-0060B0EB5963}
NS_DECLARE_ID(kPropertyElementCID,
0x579c0568, 0xe1b, 0x11d3, 0xa4, 0x30, 0x0, 0x60, 0xb0, 0xeb, 0x59, 0x63);
class nsIPropertyElement : public nsISupports
{
public:
static const nsIID& GetIID() { static nsIID iid = NS_IPROPERTYELEMENT_IID; return iid; }
NS_IMETHOD SetKey(nsString* aKey) = 0;
NS_IMETHOD SetValue(nsString* aValue) = 0;
NS_IMETHOD GetKey(nsString** aReturnKey) = 0;
NS_IMETHOD GetValue(nsString** aReturnValue) = 0;
};
////////////////////////////////////////////////////////////////////////////////
#endif // nsIProperties_h___

View File

@@ -1,100 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsISizeOfHandler_h___
#define nsISizeOfHandler_h___
#include "nscore.h"
#include "nsISupports.h"
/* c028d1f0-fc9e-11d1-89e4-006008911b81 */
#define NS_ISIZEOF_HANDLER_IID \
{ 0xc028d1f0, 0xfc9e, 0x11d1, {0x89, 0xe4, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81}}
class nsIAtom;
class nsISizeOfHandler;
/**
* Function used by the Report method to report data gathered during
* a collection of data.
*/
typedef void (*nsISizeofReportFunc)(nsISizeOfHandler* aHandler,
nsIAtom* aKey,
PRUint32 aCount,
PRUint32 aTotalSize,
PRUint32 aMinSize,
PRUint32 aMaxSize,
void* aArg);
/**
* An API to managing a sizeof computation of an arbitrary graph.
* The handler is responsible for remembering which objects have been
* seen before (using RecordObject). Note that the handler doesn't
* hold references to nsISupport's objects; the assumption is that the
* objects being sized are stationary and will not be modified during
* the sizing computation and therefore do not need an extra reference
* count.
*
* Users of this API are responsible for the actual graph/tree walking.
*/
class nsISizeOfHandler : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISIZEOF_HANDLER_IID)
/**
* Initialize the handler for a new collection of data. This empties
* out the object prescence table and the keyed size table.
*/
NS_IMETHOD Init() = 0;
/**
* Record the sizing status of a given object. The first time
* aObject is recorded, aResult will be PR_FALSE. Subsequent times,
* aResult will be PR_TRUE.
*/
NS_IMETHOD RecordObject(void* aObject, PRBool* aResult) = 0;
/**
* Add size information to the running size data. The atom is used
* as a key to keep type specific running totals of size
* information. This increments the total count and the total size
* as well as updates the minimum, maximum and total size for aKey's
* type.
*/
NS_IMETHOD AddSize(nsIAtom* aKey, PRUint32 aSize) = 0;
/**
* Enumerate data collected for each type and invoke the
* reporting function with the data gathered.
*/
NS_IMETHOD Report(nsISizeofReportFunc aFunc, void* aArg) = 0;
/**
* Get the current totals - the number of total objects sized (not
* necessarily anything to do with RecordObject's tracking of
* objects) and the total number of bytes that those object use. The
* counters are not reset by this call (use Init to reset
* everything).
*/
NS_IMETHOD GetTotals(PRUint32* aTotalCountResult,
PRUint32* aTotalSizeResult) = 0;
};
extern NS_COM nsresult
NS_NewSizeOfHandler(nsISizeOfHandler** aInstancePtrResult);
#endif /* nsISizeofHandler_h___ */

View File

@@ -1,104 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsISupports.idl"
#include "nsICollection.idl"
native nsISupportsArrayEnumFunc(nsISupportsArrayEnumFunc);
%{C++
class nsIBidirectionalEnumerator;
#define NS_SUPPORTSARRAY_CID \
{ /* bda17d50-0d6b-11d3-9331-00104ba0fd40 */ \
0xbda17d50, \
0x0d6b, \
0x11d3, \
{0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#define NS_SUPPORTSARRAY_PROGID "component://netscape/supports-array"
#define NS_SUPPORTSARRAY_CLASSNAME "Supports Array"
// Enumerator callback function. Return PR_FALSE to stop
typedef PRBool (*nsISupportsArrayEnumFunc)(nsISupports* aElement, void *aData);
%}
[scriptable, uuid(791eafa0-b9e6-11d1-8031-006008159b5a)]
interface nsISupportsArray : nsICollection {
[notxpcom] boolean Equals([const] in nsISupportsArray other);
[notxpcom] nsISupports ElementAt(in unsigned long aIndex);
[notxpcom] long IndexOf([const] in nsISupports aPossibleElement);
[notxpcom] long IndexOfStartingAt([const] in nsISupports aPossibleElement,
in unsigned long aStartIndex);
[notxpcom] long LastIndexOf([const] in nsISupports aPossibleElement);
// xpcom-compatible versions
long GetIndexOf(in nsISupports aPossibleElement);
long GetIndexOfStartingAt(in nsISupports aPossibleElement,
in unsigned long aStartIndex);
long GetLastIndexOf(in nsISupports aPossibleElement);
[notxpcom] boolean InsertElementAt(in nsISupports aElement,
in unsigned long aIndex);
[notxpcom] boolean ReplaceElementAt(in nsISupports aElement,
in unsigned long aIndex);
[notxpcom] boolean RemoveElementAt(in unsigned long aIndex);
[notxpcom] boolean RemoveLastElement([const] in nsISupports aElement);
// xpcom-compatible versions
void DeleteLastElement(in nsISupports aElement);
void DeleteElementAt(in unsigned long aIndex);
[notxpcom] boolean AppendElements(in nsISupportsArray aElements);
void Compact();
[notxpcom, noscript]
boolean EnumerateForwards(in nsISupportsArrayEnumFunc aFunc,
in voidStar aData);
[notxpcom, noscript]
boolean EnumerateBackwards(in nsISupportsArrayEnumFunc aFunc,
in voidStar aData);
%{C++
private:
// NS_IMETHOD_(nsISupportsArray&) operator=(const nsISupportsArray& other) = 0;
NS_IMETHOD_(PRBool) operator==(const nsISupportsArray& other) = 0;
NS_IMETHOD_(nsISupports*) operator[](PRUint32 aIndex) = 0;
%}
};
%{C++
// Construct and return a default implementation of nsISupportsArray:
extern NS_COM nsresult
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult);
// Construct and return a default implementation of an enumerator for nsISupportsArrays:
extern NS_COM nsresult
NS_NewISupportsArrayEnumerator(nsISupportsArray* array,
nsIBidirectionalEnumerator* *aInstancePtrResult);
%}

View File

@@ -1,263 +0,0 @@
/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* nsISupports wrappers for single primitive pieces of data. */
#include "nsISupports.idl"
/**
* These first three are pointer types and do data copying
* using the nsIAllocator. Be careful!
*/
[scriptable, uuid(d18290a0-4a1c-11d3-9890-006008962422)]
interface nsISupportsID : nsISupports
{
attribute nsIDPtr data;
string toString();
};
[scriptable, uuid(d65ff270-4a1c-11d3-9890-006008962422)]
interface nsISupportsString : nsISupports
{
attribute string data;
string toString();
};
[scriptable, uuid(d79dc970-4a1c-11d3-9890-006008962422)]
interface nsISupportsWString : nsISupports
{
attribute wstring data;
wstring toString();
};
/**
* The rest are truly primitive and are passed by value
*/
[scriptable, uuid(ddc3b490-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRBool : nsISupports
{
attribute PRBool data;
string toString();
};
[scriptable, uuid(dec2e4e0-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRUint8 : nsISupports
{
attribute PRUint8 data;
string toString();
};
[scriptable, uuid(dfacb090-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRUint16 : nsISupports
{
attribute PRUint16 data;
string toString();
};
[scriptable, uuid(e01dc470-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRUint32 : nsISupports
{
attribute PRUint32 data;
string toString();
};
[scriptable, uuid(e13567c0-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRUint64 : nsISupports
{
attribute PRUint64 data;
string toString();
};
[scriptable, uuid(e2563630-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRTime : nsISupports
{
attribute PRTime data;
string toString();
};
[scriptable, uuid(e2b05e40-4a1c-11d3-9890-006008962422)]
interface nsISupportsChar : nsISupports
{
attribute char data;
string toString();
};
[scriptable, uuid(e30d94b0-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRInt16 : nsISupports
{
attribute PRInt16 data;
string toString();
};
[scriptable, uuid(e36c5250-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRInt32 : nsISupports
{
attribute PRInt32 data;
string toString();
};
[scriptable, uuid(e3cb0ff0-4a1c-11d3-9890-006008962422)]
interface nsISupportsPRInt64 : nsISupports
{
attribute PRInt64 data;
string toString();
};
[scriptable, uuid(abeaa390-4ac0-11d3-baea-00805f8a5dd7)]
interface nsISupportsFloat : nsISupports
{
attribute float data;
string toString();
};
[scriptable, uuid(b32523a0-4ac0-11d3-baea-00805f8a5dd7)]
interface nsISupportsDouble : nsISupports
{
attribute double data;
string toString();
};
[scriptable, uuid(464484f0-568d-11d3-baf8-00805f8a5dd7)]
interface nsISupportsVoid : nsISupports
{
/*
* This would be: "[noscript] attribute voidStar data;" but for...
* http://bugzilla.mozilla.org/show_bug.cgi?id=11454
*/
[noscript] void GetData([shared,retval] out voidStar aData);
[noscript] void SetData(in voidStar aData);
string toString();
};
/////////////////////////////////////////////////////////////////////////
%{C++
// {ACF8DC40-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_ID_CID \
{ 0xacf8dc40, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_ID_PROGID "component://netscape/supports-id"
#define NS_SUPPORTS_ID_CLASSNAME "Supports ID"
// {ACF8DC41-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_STRING_CID \
{ 0xacf8dc41, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_STRING_PROGID "component://netscape/supports-string"
#define NS_SUPPORTS_STRING_CLASSNAME "Supports String"
// {ACF8DC42-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_WSTRING_CID \
{ 0xacf8dc42, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_WSTRING_PROGID "component://netscape/supports-wstring"
#define NS_SUPPORTS_WSTRING_CLASSNAME "Supports WString"
// {ACF8DC43-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRBOOL_CID \
{ 0xacf8dc43, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRBOOL_PROGID "component://netscape/supports-PRBool"
#define NS_SUPPORTS_PRBOOL_CLASSNAME "Supports PRBool"
// {ACF8DC44-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRUINT8_CID \
{ 0xacf8dc44, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT8_PROGID "component://netscape/supports-PRUint8"
#define NS_SUPPORTS_PRUINT8_CLASSNAME "Supports PRUint8"
// {ACF8DC46-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRUINT16_CID \
{ 0xacf8dc46, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT16_PROGID "component://netscape/supports-PRUint16"
#define NS_SUPPORTS_PRUINT16_CLASSNAME "Supports PRUint16"
// {ACF8DC47-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRUINT32_CID \
{ 0xacf8dc47, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT32_PROGID "component://netscape/supports-PRUint32"
#define NS_SUPPORTS_PRUINT32_CLASSNAME "Supports PRUint32"
// {ACF8DC48-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRUINT64_CID \
{ 0xacf8dc48, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRUINT64_PROGID "component://netscape/supports-PRUint64"
#define NS_SUPPORTS_PRUINT64_CLASSNAME "Supports PRUint64"
// {ACF8DC49-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRTIME_CID \
{ 0xacf8dc49, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRTIME_PROGID "component://netscape/supports-PRTime"
#define NS_SUPPORTS_PRTIME_CLASSNAME "Supports PRTime"
// {ACF8DC4A-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_CHAR_CID \
{ 0xacf8dc4a, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_CHAR_PROGID "component://netscape/supports-char"
#define NS_SUPPORTS_CHAR_CLASSNAME "Supports Char"
// {ACF8DC4B-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRINT16_CID \
{ 0xacf8dc4b, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRINT16_PROGID "component://netscape/supports-PRInt16"
#define NS_SUPPORTS_PRINT16_CLASSNAME "Supports PRInt16"
// {ACF8DC4C-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRINT32_CID \
{ 0xacf8dc4c, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRINT32_PROGID "component://netscape/supports-PRInt32"
#define NS_SUPPORTS_PRINT32_CLASSNAME "Supports PRInt32"
// {ACF8DC4D-4A25-11d3-9890-006008962422}
#define NS_SUPPORTS_PRINT64_CID \
{ 0xacf8dc4d, 0x4a25, 0x11d3, \
{ 0x98, 0x90, 0x0, 0x60, 0x8, 0x96, 0x24, 0x22 } }
#define NS_SUPPORTS_PRINT64_PROGID "component://netscape/supports-PRInt64"
#define NS_SUPPORTS_PRINT64_CLASSNAME "Supports PRInt64"
// {CBF86870-4AC0-11d3-BAEA-00805F8A5DD7}
#define NS_SUPPORTS_FLOAT_CID \
{ 0xcbf86870, 0x4ac0, 0x11d3, \
{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
#define NS_SUPPORTS_FLOAT_PROGID "component://netscape/supports-float"
#define NS_SUPPORTS_FLOAT_CLASSNAME "Supports float"
// {CBF86871-4AC0-11d3-BAEA-00805F8A5DD7}
#define NS_SUPPORTS_DOUBLE_CID \
{ 0xcbf86871, 0x4ac0, 0x11d3, \
{ 0xba, 0xea, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
#define NS_SUPPORTS_DOUBLE_PROGID "component://netscape/supports-double"
#define NS_SUPPORTS_DOUBLE_CLASSNAME "Supports double"
// {AF10F3E0-568D-11d3-BAF8-00805F8A5DD7}
#define NS_SUPPORTS_VOID_CID \
{ 0xaf10f3e0, 0x568d, 0x11d3, \
{ 0xba, 0xf8, 0x0, 0x80, 0x5f, 0x8a, 0x5d, 0xd7 } }
#define NS_SUPPORTS_VOID_PROGID "component://netscape/supports-void"
#define NS_SUPPORTS_VOID_CLASSNAME "Supports void"
%}

View File

@@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsIUnicharBuffer_h___
#define nsIUnicharBuffer_h___
#include "nscore.h"
#include "nsISupports.h"
class nsIUnicharInputStream;
#define NS_IUNICHARBUFFER_IID \
{ 0x14cf6970, 0x93b5, 0x11d1, \
{0x89, 0x5b, 0x00, 0x60, 0x08, 0x91, 0x1b, 0x81} }
/// Interface to a buffer that holds unicode characters
class nsIUnicharBuffer : public nsISupports {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IUNICHARBUFFER_IID);
NS_IMETHOD Init(PRUint32 aBufferSize) = 0;
NS_IMETHOD_(PRInt32) GetLength() const = 0;
NS_IMETHOD_(PRInt32) GetBufferSize() const = 0;
NS_IMETHOD_(PRUnichar*) GetBuffer() const = 0;
NS_IMETHOD_(PRBool) Grow(PRInt32 aNewSize) = 0;
NS_IMETHOD_(PRInt32) Fill(nsresult* aErrorCode, nsIUnicharInputStream* aStream,
PRInt32 aKeep) = 0;
};
/// Factory method for nsIUnicharBuffer.
extern NS_COM nsresult
NS_NewUnicharBuffer(nsIUnicharBuffer** aInstancePtrResult,
nsISupports* aOuter,
PRUint32 aBufferSize = 0);
#define NS_UNICHARBUFFER_CID \
{ /* c81fd8f0-0d6b-11d3-9331-00104ba0fd40 */ \
0xc81fd8f0, \
0x0d6b, \
0x11d3, \
{0x93, 0x31, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \
}
#endif /* nsIUnicharBuffer_h___ */

View File

@@ -1,340 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsInt64_h__
#define nsInt64_h__
#include "prlong.h"
#include "nscore.h"
/**
* This class encapsulates full 64-bit integer functionality and
* provides simple arithmetic and conversion operations.
*/
// If you ever decide that you need to add a non-inline method to this
// class, be sure to change the class declaration to "class NS_BASE
// nsInt64".
class nsInt64
{
private:
PRInt64 mValue;
public:
/**
* Construct a new 64-bit integer.
*/
nsInt64(void) : mValue(LL_ZERO) {
}
/**
* Construct a new 64-bit integer from a 32-bit signed integer
*/
nsInt64(const PRInt32 aInt32) {
LL_I2L(mValue, aInt32);
}
/**
* Construct a new 64-bit integer from a 32-bit unsigned integer
*/
nsInt64(const PRUint32 aUint32) {
LL_UI2L(mValue, aUint32);
}
/**
* Construct a new 64-bit integer from a floating point value.
*/
nsInt64(const PRFloat64 aFloat64) {
LL_D2L(mValue, aFloat64);
}
/**
* Construct a new 64-bit integer from a native 64-bit integer
*/
nsInt64(const PRInt64 aInt64) : mValue(aInt64) {
}
/**
* Construct a new 64-bit integer from another 64-bit integer
*/
nsInt64(const nsInt64& aObject) : mValue(aObject.mValue) {
}
// ~nsInt64(void) -- XXX destructor unnecessary
/**
* Assign a 64-bit integer to another 64-bit integer
*/
const nsInt64& operator =(const nsInt64& aObject) {
mValue = aObject.mValue;
return *this;
}
/**
* Convert a 64-bit integer to a signed 32-bit value
*/
operator PRInt32(void) const {
PRInt32 result;
LL_L2I(result, mValue);
return result;
}
/**
* Convert a 64-bit integer to an unsigned 32-bit value
*/
operator PRUint32(void) const {
PRUint32 result;
LL_L2UI(result, mValue);
return result;
}
/**
* Convert a 64-bit integer to a floating point value
*/
operator PRFloat64(void) const {
PRFloat64 result;
LL_L2D(result, mValue);
return result;
}
/**
* Convert a 64-bit integer to a native 64-bit integer.
*/
operator PRInt64(void) const {
return mValue;
}
/**
* Perform unary negation on a 64-bit integer.
*/
const nsInt64 operator -(void) {
nsInt64 result;
LL_NEG(result.mValue, mValue);
return result;
}
// Arithmetic operators
friend const nsInt64 operator +(const nsInt64& aObject1, const nsInt64& aObject2);
friend const nsInt64 operator -(const nsInt64& aObject1, const nsInt64& aObject2);
friend const nsInt64 operator *(const nsInt64& aObject1, const nsInt64& aObject2);
friend const nsInt64 operator /(const nsInt64& aObject1, const nsInt64& aObject2);
friend const nsInt64 operator %(const nsInt64& aObject1, const nsInt64& aObject2);
/**
* Increment a 64-bit integer by a 64-bit integer amount.
*/
nsInt64& operator +=(const nsInt64& aObject) {
LL_ADD(mValue, mValue, aObject.mValue);
return *this;
}
/**
* Decrement a 64-bit integer by a 64-bit integer amount.
*/
nsInt64& operator -=(const nsInt64& aObject) {
LL_SUB(mValue, mValue, aObject.mValue);
return *this;
}
/**
* Multiply a 64-bit integer by a 64-bit integer amount.
*/
nsInt64& operator *=(const nsInt64& aObject) {
LL_MUL(mValue, mValue, aObject.mValue);
return *this;
}
/**
* Divide a 64-bit integer by a 64-bit integer amount.
*/
nsInt64& operator /=(const nsInt64& aObject) {
LL_DIV(mValue, mValue, aObject.mValue);
return *this;
}
/**
* Compute the modulus of a 64-bit integer to a 64-bit value.
*/
nsInt64& operator %=(const nsInt64& aObject) {
LL_MOD(mValue, mValue, aObject.mValue);
return *this;
}
// Comparison operators
friend PRBool operator ==(const nsInt64& aObject1, const nsInt64& aObject2);
friend PRBool operator !=(const nsInt64& aObject1, const nsInt64& aObject2);
friend PRBool operator >(const nsInt64& aObject1, const nsInt64& aObject2);
friend PRBool operator >=(const nsInt64& aObject1, const nsInt64& aObject2);
friend PRBool operator <(const nsInt64& aObject1, const nsInt64& aObject2);
friend PRBool operator <=(const nsInt64& aObject1, const nsInt64& aObject2);
// Bitwise operators
friend const nsInt64 operator &(const nsInt64& aObject1, const nsInt64& aObject2);
friend const nsInt64 operator |(const nsInt64& aObject1, const nsInt64& aObject2);
friend const nsInt64 operator ^(const nsInt64& aObject1, const nsInt64& aObject2);
/**
* Compute the bitwise NOT of a 64-bit integer
*/
const nsInt64 operator ~(void) {
nsInt64 result;
LL_NOT(result.mValue, mValue);
return result;
}
/**
* Compute the bitwise AND with another 64-bit integer
*/
nsInt64& operator &=(const nsInt64& aObject) {
LL_AND(mValue, mValue, aObject.mValue);
return *this;
}
/**
* Compute the bitwise OR with another 64-bit integer
*/
nsInt64& operator |=(const nsInt64& aObject) {
LL_OR(mValue, mValue, aObject.mValue);
return *this;
}
/**
* Compute the bitwise XOR with another 64-bit integer
*/
nsInt64& operator ^=(const nsInt64& aObject) {
LL_XOR(mValue, mValue, aObject.mValue);
return *this;
}
};
/**
* Add two 64-bit integers.
*/
inline const nsInt64
operator +(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) += aObject2;
}
/**
* Subtract one 64-bit integer from another.
*/
inline const nsInt64
operator -(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) -= aObject2;
}
/**
* Multiply two 64-bit integers
*/
inline const nsInt64
operator *(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) *= aObject2;
}
/**
* Divide one 64-bit integer by another
*/
inline const nsInt64
operator /(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) /= aObject2;
}
/**
* Compute the modulus of two 64-bit integers
*/
inline const nsInt64
operator %(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) %= aObject2;
}
/**
* Determine if two 64-bit integers are equal
*/
inline PRBool
operator ==(const nsInt64& aObject1, const nsInt64& aObject2) {
return LL_EQ(aObject1.mValue, aObject2.mValue);
}
/**
* Determine if two 64-bit integers are not equal
*/
inline PRBool
operator !=(const nsInt64& aObject1, const nsInt64& aObject2) {
return LL_NE(aObject1.mValue, aObject2.mValue);
}
/**
* Determine if one 64-bit integer is strictly greater than another, using signed values
*/
inline PRBool
operator >(const nsInt64& aObject1, const nsInt64& aObject2) {
return LL_CMP(aObject1.mValue, >, aObject2.mValue);
}
/**
* Determine if one 64-bit integer is greater than or equal to another, using signed values
*/
inline PRBool
operator >=(const nsInt64& aObject1, const nsInt64& aObject2) {
return LL_CMP(aObject1.mValue, >=, aObject2.mValue);
}
/**
* Determine if one 64-bit integer is strictly less than another, using signed values
*/
inline PRBool
operator <(const nsInt64& aObject1, const nsInt64& aObject2) {
return LL_CMP(aObject1.mValue, <, aObject2.mValue);
}
/**
* Determine if one 64-bit integers is less than or equal to another, using signed values
*/
inline PRBool
operator <=(const nsInt64& aObject1, const nsInt64& aObject2) {
return LL_CMP(aObject1.mValue, <=, aObject2.mValue);
}
/**
* Perform a bitwise AND of two 64-bit integers
*/
inline const nsInt64
operator &(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) &= aObject2;
}
/**
* Perform a bitwise OR of two 64-bit integers
*/
inline const nsInt64
operator |(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) |= aObject2;
}
/**
* Perform a bitwise XOR of two 64-bit integers
*/
inline const nsInt64
operator ^(const nsInt64& aObject1, const nsInt64& aObject2) {
return nsInt64(aObject1) ^= aObject2;
}
#endif // nsInt64_h__

View File

@@ -1,92 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define NS_IMPL_IDS
#include "pratom.h"
#include "nsIFactory.h"
#include "nsIServiceManager.h"
#include "nsRepository.h"
#include "nsIObserver.h"
#include "nsObserver.h"
#include "nsString.h"
static NS_DEFINE_CID(kObserverCID, NS_OBSERVER_CID);
////////////////////////////////////////////////////////////////////////////////
// nsObserver Implementation
NS_IMPL_AGGREGATED(nsObserver)
NS_COM nsresult NS_NewObserver(nsIObserver** anObserver, nsISupports* outer)
{
return nsObserver::Create(outer, NS_GET_IID(nsIObserver), (void**)anObserver);
}
NS_METHOD
nsObserver::Create(nsISupports* outer, const nsIID& aIID, void* *anObserver)
{
NS_ENSURE_ARG_POINTER(anObserver);
NS_ENSURE_PROPER_AGGREGATION(outer, aIID);
nsObserver* it = new nsObserver(outer);
if (it == NULL)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = it->AggregatedQueryInterface(aIID, anObserver);
if (NS_FAILED(rv)) {
delete it;
return rv;
}
return rv;
}
nsObserver::nsObserver(nsISupports* outer)
{
NS_INIT_AGGREGATED(outer);
}
nsObserver::~nsObserver(void)
{
}
NS_IMETHODIMP
nsObserver::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID()))
*aInstancePtr = GetInner();
else if(aIID.Equals(nsIObserver::GetIID()))
*aInstancePtr = NS_STATIC_CAST(nsIObserver*, this);
else {
*aInstancePtr = nsnull;
return NS_NOINTERFACE;
}
NS_ADDREF((nsISupports*)*aInstancePtr);
return NS_OK;
}
NS_IMETHODIMP
nsObserver::Observe( nsISupports *, const PRUnichar *, const PRUnichar * ) {
nsresult rv = NS_OK;
return rv;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,50 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsObserver_h___
#define nsObserver_h___
#include "nsIObserver.h"
#include "nsAgg.h"
// {DB242E03-E4D9-11d2-9DDE-000064657374}
#define NS_OBSERVER_CID \
{ 0xdb242e03, 0xe4d9, 0x11d2, { 0x9d, 0xde, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
class nsObserver : public nsIObserver {
public:
NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVER_CID )
NS_DECL_NSIOBSERVER
nsObserver(nsISupports* outer);
virtual ~nsObserver(void);
static NS_METHOD
Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
NS_DECL_AGGREGATED
private:
};
extern NS_COM nsresult NS_NewObserver(nsIObserver** anObserver, nsISupports* outer = NULL);
#endif /* nsObserver_h___ */

View File

@@ -1,133 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define NS_IMPL_IDS
#include "pratom.h"
#include "nsIObserverList.h"
#include "nsObserverList.h"
#include "nsString.h"
#include "nsAutoLock.h"
#define NS_AUTOLOCK(__monitor) nsAutoLock __lock(__monitor)
static NS_DEFINE_CID(kObserverListCID, NS_OBSERVERLIST_CID);
////////////////////////////////////////////////////////////////////////////////
// nsObserverList Implementation
NS_IMPL_ISUPPORTS1(nsObserverList, nsIObserverList)
NS_COM nsresult NS_NewObserverList(nsIObserverList** anObserverList)
{
if (anObserverList == NULL)
{
return NS_ERROR_NULL_POINTER;
}
nsObserverList* it = new nsObserverList();
if (it == 0) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(NS_GET_IID(nsIObserverList), (void **) anObserverList);
}
nsObserverList::nsObserverList()
: mLock(nsnull),
mObserverList(NULL)
{
NS_INIT_REFCNT();
mLock = PR_NewLock();
}
nsObserverList::~nsObserverList(void)
{
PR_DestroyLock(mLock);
NS_IF_RELEASE(mObserverList);
}
nsresult nsObserverList::AddObserver(nsIObserver** anObserver)
{
nsresult rv;
PRBool inserted;
NS_AUTOLOCK(mLock);
if (anObserver == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if(!mObserverList) {
rv = NS_NewISupportsArray(&mObserverList);
if (NS_FAILED(rv)) return rv;
}
if(*anObserver) {
inserted = mObserverList->AppendElement(*anObserver);
return inserted ? NS_OK : NS_ERROR_FAILURE;
}
return NS_ERROR_FAILURE;
}
nsresult nsObserverList::RemoveObserver(nsIObserver** anObserver)
{
PRBool removed;
NS_AUTOLOCK(mLock);
if (anObserver == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if(!mObserverList) {
return NS_ERROR_FAILURE;
}
if(*anObserver) {
removed = mObserverList->RemoveElement(*anObserver);
return removed ? NS_OK : NS_ERROR_FAILURE;
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP nsObserverList::EnumerateObserverList(nsIEnumerator** anEnumerator)
{
NS_AUTOLOCK(mLock);
if (anEnumerator == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if(!mObserverList) {
return NS_ERROR_FAILURE;
}
return mObserverList->Enumerate(anEnumerator);
}

View File

@@ -1,51 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsObserverList_h___
#define nsObserverList_h___
#include "nsIObserverList.h"
#include "nsIEnumerator.h"
#include "nsISupportsArray.h"
class nsObserverList : public nsIObserverList {
public:
NS_IMETHOD AddObserver(nsIObserver** anObserver);
NS_IMETHOD RemoveObserver(nsIObserver** anObserver);
NS_IMETHOD EnumerateObserverList(nsIEnumerator** anEnumerator);
nsObserverList();
virtual ~nsObserverList(void);
// This is ObserverList monitor object.
PRLock* mLock;
NS_DECL_ISUPPORTS
private:
nsISupportsArray *mObserverList;
};
#endif /* nsObserverList_h___ */

View File

@@ -1,249 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define NS_IMPL_IDS
#include "prlock.h"
#include "nsIFactory.h"
#include "nsIServiceManager.h"
#include "nsRepository.h"
#include "nsIObserverService.h"
#include "nsObserverService.h"
#include "nsIObserverList.h"
#include "nsObserverList.h"
#include "nsHashtable.h"
#include "nsString.h"
static NS_DEFINE_CID(kObserverServiceCID, NS_OBSERVERSERVICE_CID);
////////////////////////////////////////////////////////////////////////////////
static nsObserverService* gObserverService = nsnull; // The one-and-only ObserverService
////////////////////////////////////////////////////////////////////////////////
// nsObserverService Implementation
NS_IMPL_ISUPPORTS1(nsObserverService, nsIObserverService)
NS_COM nsresult NS_NewObserverService(nsIObserverService** anObserverService)
{
return nsObserverService::GetObserverService(anObserverService);
}
nsObserverService::nsObserverService()
: mObserverTopicTable(NULL)
{
NS_INIT_REFCNT();
mObserverTopicTable = nsnull;
}
nsObserverService::~nsObserverService(void)
{
if(mObserverTopicTable)
delete mObserverTopicTable;
gObserverService = nsnull;
}
NS_METHOD
nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
{
nsresult rv;
nsObserverService* os = new nsObserverService();
if (os == NULL)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(os);
rv = os->QueryInterface(aIID, aInstancePtr);
NS_RELEASE(os);
return rv;
}
nsresult nsObserverService::GetObserverService(nsIObserverService** anObserverService)
{
if (! gObserverService) {
nsObserverService* it = new nsObserverService();
if (! it)
return NS_ERROR_OUT_OF_MEMORY;
gObserverService = it;
}
NS_ADDREF(gObserverService);
*anObserverService = gObserverService;
return NS_OK;
}
static PRBool
ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure)
{
nsIObserverList* observerList = NS_STATIC_CAST(nsIObserverList*, aData);
NS_RELEASE(observerList);
return PR_TRUE;
}
nsresult nsObserverService::GetObserverList(const nsString& aTopic, nsIObserverList** anObserverList)
{
if (anObserverList == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if(mObserverTopicTable == NULL) {
mObserverTopicTable = new nsObjectHashtable(nsnull, nsnull, // should never be cloned
ReleaseObserverList, nsnull,
256, PR_TRUE);
if (mObserverTopicTable == NULL)
return NS_ERROR_OUT_OF_MEMORY;
}
nsStringKey key(aTopic);
nsIObserverList *topicObservers = nsnull;
if (mObserverTopicTable->Exists(&key)) {
topicObservers = (nsIObserverList *) mObserverTopicTable->Get(&key);
if (topicObservers != NULL) {
*anObserverList = topicObservers;
} else {
NS_NewObserverList(&topicObservers);
mObserverTopicTable->Put(&key, topicObservers);
}
} else {
NS_NewObserverList(&topicObservers);
*anObserverList = topicObservers;
mObserverTopicTable->Put(&key, topicObservers);
}
return NS_OK;
}
nsresult nsObserverService::AddObserver(nsIObserver* anObserver, const PRUnichar* aTopic)
{
nsIObserverList* anObserverList;
nsresult rv;
if (anObserver == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if (aTopic == NULL)
{
return NS_ERROR_NULL_POINTER;
}
nsAutoString topic(aTopic);
rv = GetObserverList(topic, &anObserverList);
if (NS_FAILED(rv)) return rv;
if (anObserverList) {
return anObserverList->AddObserver(&anObserver);
}
return NS_ERROR_FAILURE;
}
nsresult nsObserverService::RemoveObserver(nsIObserver* anObserver, const PRUnichar* aTopic)
{
nsIObserverList* anObserverList;
nsresult rv;
if (anObserver == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if (aTopic == NULL)
{
return NS_ERROR_NULL_POINTER;
}
nsAutoString topic(aTopic);
rv = GetObserverList(topic, &anObserverList);
if (NS_FAILED(rv)) return rv;
if (anObserverList) {
return anObserverList->RemoveObserver(&anObserver);
}
return NS_ERROR_FAILURE;
}
nsresult nsObserverService::EnumerateObserverList(const PRUnichar* aTopic, nsIEnumerator** anEnumerator)
{
nsIObserverList* anObserverList;
nsresult rv;
if (anEnumerator == NULL)
{
return NS_ERROR_NULL_POINTER;
}
if (aTopic == NULL)
{
return NS_ERROR_NULL_POINTER;
}
nsAutoString topic(aTopic);
rv = GetObserverList(topic, &anObserverList);
if (NS_FAILED(rv)) return rv;
if (anObserverList) {
return anObserverList->EnumerateObserverList(anEnumerator);
}
return NS_ERROR_FAILURE;
}
// Enumerate observers of aTopic and call Observe on each.
nsresult nsObserverService::Notify( nsISupports *aSubject,
const PRUnichar *aTopic,
const PRUnichar *someData ) {
nsresult rv = NS_OK;
nsIEnumerator *observers;
// Get observer list enumerator.
rv = this->EnumerateObserverList( aTopic, &observers );
if ( NS_SUCCEEDED( rv ) ) {
// Go to start of observer list.
rv = observers->First();
// Continue until error or end of list.
while ( observers->IsDone() != NS_OK && NS_SUCCEEDED(rv) ) {
// Get current item (observer).
nsISupports *base;
rv = observers->CurrentItem( &base );
if ( NS_SUCCEEDED( rv ) ) {
// Convert item to nsIObserver.
nsIObserver *observer;
rv = base->QueryInterface( nsIObserver::GetIID(), (void**)&observer );
if ( NS_SUCCEEDED( rv ) && observer ) {
// Tell the observer what's up.
observer->Observe( aSubject, aTopic, someData );
// Release the observer.
observer->Release();
}
}
// Go on to next observer in list.
rv = observers->Next();
}
// Release the observer list.
observers->Release();
rv = NS_OK;
}
return rv;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,56 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsObserverService_h___
#define nsObserverService_h___
#include "nsIObserverService.h"
#include "nsIObserverList.h"
class nsObjectHashtable;
class nsString;
// {D07F5195-E3D1-11d2-8ACD-00105A1B8860}
#define NS_OBSERVERSERVICE_CID \
{ 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
class nsObserverService : public nsIObserverService {
public:
NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVERSERVICE_CID )
static nsresult GetObserverService(nsIObserverService** anObserverService);
NS_DECL_NSIOBSERVERSERVICE
nsObserverService();
virtual ~nsObserverService(void);
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
private:
NS_IMETHOD GetObserverList(const nsString& aTopic, nsIObserverList** anObserverList);
nsObjectHashtable* mObserverTopicTable;
};
#endif /* nsObserverService_h___ */

View File

@@ -1,914 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsPageMgr.h"
#include "prmem.h"
#if defined(XP_PC)
#include <windows.h>
#elif defined(XP_MAC)
#include <stdlib.h>
#elif defined(XP_BEOS)
#include <fcntl.h>
#elif defined(XP_UNIX)
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <malloc.h>
#ifndef MAP_FAILED
#if defined (__STDC__) && __STDC__
#define MAP_FAILED ((void *) -1)
#else
#define MAP_FAILED ((char *) -1)
#endif
#endif
#if defined(VMS)
#if defined(DEBUG)
#include <stdio.h>
#endif
#include <starlet.h>
#include <ssdef.h>
#include <vadef.h>
#include <va_rangedef.h>
#endif
#endif
/******************************************************************************/
#define NS_PAGEMGR_CLUSTERDESC_CLUMPSIZE 16
void
nsPageMgr::DeleteFreeClusterDesc(nsClusterDesc *desc)
{
desc->mNext = mUnusedClusterDescs;
mUnusedClusterDescs = desc;
}
nsPageMgr::nsClusterDesc*
nsPageMgr::NewFreeClusterDesc(void)
{
nsClusterDesc *desc = mUnusedClusterDescs;
if (desc)
mUnusedClusterDescs = desc->mNext;
else {
/* Allocate a clump of cluster records at once, and link all except
the first onto the list of mUnusedClusterDescs */
desc = (nsClusterDesc*)PR_Malloc(NS_PAGEMGR_CLUSTERDESC_CLUMPSIZE * sizeof(nsClusterDesc));
if (desc) {
nsClusterDesc* desc2 = desc + (NS_PAGEMGR_CLUSTERDESC_CLUMPSIZE - 1);
while (desc2 != desc) {
DeleteFreeClusterDesc(desc2--);
}
}
}
return desc;
}
/* Search the mFreeClusters looking for the first cluster of consecutive free
pages that is at least size bytes long. If there is one, remove these pages
from the free page list and return their address; if not, return nil. */
nsPage*
nsPageMgr::AllocClusterFromFreeList(PRUword nPages)
{
nsClusterDesc **p = &mFreeClusters;
nsClusterDesc *desc;
while ((desc = *p) != NULL) {
if (desc->mPageCount >= nPages) {
nsPage* addr = desc->mAddr;
if (desc->mPageCount == nPages) {
*p = desc->mNext;
DeleteFreeClusterDesc(desc);
}
else {
desc->mAddr += nPages;
desc->mPageCount -= nPages;
}
return addr;
}
p = &desc->mNext;
}
return NULL;
}
/* Add the segment to the nsClusterDesc list, coalescing it with any
clusters already in the list when possible. */
void
nsPageMgr::AddClusterToFreeList(nsPage* addr, PRWord nPages)
{
nsClusterDesc **p = &mFreeClusters;
nsClusterDesc *desc;
nsClusterDesc *newDesc;
while ((desc = *p) != NULL) {
if (desc->mAddr + desc->mPageCount == addr) {
/* Coalesce with the previous cluster. */
nsClusterDesc *next = desc->mNext;
desc->mPageCount += nPages;
if (next && next->mAddr == addr + nPages) {
/* We can coalesce with both the previous and the next cluster. */
desc->mPageCount += next->mPageCount;
desc->mNext = next->mNext;
DeleteFreeClusterDesc(next);
}
return;
}
if (desc->mAddr == addr + nPages) {
/* Coalesce with the next cluster. */
desc->mAddr -= nPages;
desc->mPageCount += nPages;
return;
}
if (desc->mAddr > addr) {
PR_ASSERT(desc->mAddr > addr + nPages);
break;
}
PR_ASSERT(desc->mAddr + desc->mPageCount < addr);
p = &desc->mNext;
}
newDesc = NewFreeClusterDesc();
/* In the unlikely event that this malloc fails, we drop the free cluster
on the floor. The only consequence is that the memory mapping table
becomes slightly larger. */
if (newDesc) {
newDesc->mNext = desc;
newDesc->mAddr = addr;
newDesc->mPageCount = nPages;
*p = newDesc;
}
}
#ifdef NS_PAGEMGR_VERIFYCLUSTERS
#ifndef XP_PC
#define OutputDebugString(x) puts(x)
#endif
void
nsPageMgr::VerifyClusters(PRWord nPagesDelta)
{
static PRUword expectedPagesUsed = 0;
nsPageCount calculatedPagesUsed;
nsPage* lastDescEnd = 0;
nsClusterDesc* desc;
char str[256];
expectedPagesUsed += nPagesDelta;
calculatedPagesUsed = mBoundary - mMemoryBase;
sprintf(str, "[Clusters: %p", mMemoryBase);
OutputDebugString(str);
for (desc = mFreeClusters; desc; desc = desc->mNext) {
PR_ASSERT(desc->mAddr > lastDescEnd);
calculatedPagesUsed -= desc->mPageCount;
lastDescEnd = desc->mAddr + desc->mPageCount;
sprintf(str, "..%p, %p", desc->mAddr-1, desc->mAddr + desc->mPageCount);
OutputDebugString(str);
}
sprintf(str, "..%p]\n", mBoundary);
OutputDebugString(str);
PR_ASSERT(lastDescEnd < mBoundary);
PR_ASSERT(calculatedPagesUsed == expectedPagesUsed);
}
#endif /* NS_PAGEMGR_VERIFYCLUSTERS */
/*******************************************************************************
* Machine-dependent stuff
******************************************************************************/
#if defined(XP_PC)
#define GC_VMBASE 0x40000000 /* XXX move */
#define GC_VMLIMIT 0x0FFFFFFF
#elif defined(XP_MAC)
#define NS_PAGEMGR_MAC_SEGMENT_SIZE
#define NS_PAGEMGR_MAC_SEGMENT_COUNT
#endif
PRStatus
nsPageMgr::InitPages(nsPageCount minPages, nsPageCount maxPages)
{
#if defined(XP_PC)
nsPage* addr = NULL;
nsPageCount size = maxPages;
#ifdef NS_PAGEMGR_DEBUG
/* first try to place the heap at a well-known address for debugging */
addr = (nsPage*)VirtualAlloc((void*)GC_VMBASE, size << NS_PAGEMGR_PAGE_BITS,
MEM_RESERVE, PAGE_READWRITE);
#endif
while (addr == NULL) {
/* let the system place the heap */
addr = (nsPage*)VirtualAlloc(0, size << NS_PAGEMGR_PAGE_BITS,
MEM_RESERVE, PAGE_READWRITE);
if (addr == NULL) {
size--;
if (size < minPages) {
return PR_FAILURE;
}
}
}
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(addr, NS_PAGEMGR_PAGE_BITS));
mMemoryBase = addr;
mPageCount = size;
mBoundary = addr;
return PR_SUCCESS;
#elif defined(XP_MAC)
OSErr err;
void* seg;
void* segLimit;
Handle h;
PRUword segSize = (minPages + 1) * NS_PAGEMGR_PAGE_SIZE;
nsPage* firstPage;
nsPage* lastPage;
nsSegmentDesc* mSegTable;
int mSegTableCount, otherCount;
h = TempNewHandle(segSize, &err);
if (err || h == NULL) goto fail;
MoveHHi(h);
TempHLock(h, &err);
if (err) goto fail;
seg = *h;
segLimit = (void*)((char*)seg + segSize);
firstPage = NS_PAGEMGR_PAGE_ROUNDUP(seg);
lastPage = NS_PAGEMGR_PAGE_ROUNDDN(((char*)seg + segSize));
/* Put the segment table in the otherwise wasted space at one
end of the segment. We'll put it at which ever end is bigger. */
mSegTable = (nsSegmentDesc*)seg;
mSegTableCount = ((char*)firstPage - (char*)seg) / sizeof(nsSegmentDesc);
otherCount = ((char*)segLimit - (char*)lastPage) / sizeof(nsSegmentDesc);
if (otherCount > mSegTableCount) {
mSegTable = (nsSegmentDesc*)lastPage;
mSegTableCount = otherCount;
}
else if (mSegTableCount == 0) {
mSegTable = (nsSegmentDesc*)firstPage;
firstPage++;
mSegTableCount = NS_PAGEMGR_PAGE_SIZE / sizeof(nsSegmentDesc);
}
PR_ASSERT(mSegTableCount > 0);
mSegTable = mSegTable;
mSegTableCount = mSegTableCount;
mSegTable[0].mHandle = h;
mSegTable[0].mFirstPage = firstPage;
mSegTable[0].mLastPage = lastPage;
/* XXX hack for now -- just one segment */
mMemoryBase = firstPage;
mBoundary = firstPage;
mPageCount = lastPage - firstPage;
return PR_SUCCESS;
fail:
if (h) {
TempDisposeHandle(h, &err);
}
return PR_FAILURE;
#elif defined(XP_BEOS)
nsPage* addr = NULL;
nsPageCount size = maxPages;
#if (1L<<NS_PAGEMGR_PAGE_BITS) != B_PAGE_SIZE
#error can only work with 4096 byte pages
#endif
while(addr == NULL)
{
/* let the system place the heap */
if((mAid = create_area("MozillaHeap", (void **)&addr, B_ANY_ADDRESS,
size << NS_PAGEMGR_PAGE_BITS, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA)) < 0)
{
addr = NULL;
size--;
if (size < minPages) {
return PR_FAILURE;
}
}
}
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(addr, NS_PAGEMGR_PAGE_BITS));
mMemoryBase = addr;
mPageCount = size;
mBoundary = addr;
return PR_SUCCESS;
#elif defined(VMS)
nsPage* addr = NULL;
nsPageCount size = maxPages;
struct _va_range retadr, retadr2;
int status;
/*
** The default is 32767 pages. This is quite a lot (the pages are 4k).
** Let's at least make it configurable.
*/
char *tmp;
tmp = getenv("VMS_PAGE_MANAGER_SIZE");
if (tmp)
size=atoi(tmp);
#if defined(DEBUG)
printf("Requested page manager size is %d 4k pages\n",size);
#endif
/*
** $EXPREG will extend the virtual address region by the requested
** number of pages (or pagelets on Alpha). The process must have
** sufficient PGFLQUOTA for the operation, otherwise SS$_EXQUOTA will
** be returned. However, in the case of SS$_EXQUOTA, $EXPREG will have
** grown the region by the largest possible amount. In this case we will
** put back the maximum amount and repeat the $EXPREG requesting half of
** maximum (so as to leave some memory for others), just so long as its
** over our minimum threshold.
*/
status = sys$expreg(size << (NS_PAGEMGR_PAGE_BITS-VA$C_PAGELET_SHIFT_SIZE),
&retadr,0,0);
switch (status) {
case SS$_NORMAL:
break;
case SS$_EXQUOTA:
size = ( (int)retadr.va_range$ps_end_va -
(int)retadr.va_range$ps_start_va + 1
) >> NS_PAGEMGR_PAGE_BITS;
status=sys$deltva(&retadr,&retadr2,0);
size=size/2;
if (size < minPages) {
return PR_FAILURE;
}
status = sys$expreg(
size << (NS_PAGEMGR_PAGE_BITS-VA$C_PAGELET_SHIFT_SIZE),
&retadr,0,0);
if (status != SS$_NORMAL) {
status=sys$deltva(&retadr,&retadr2,0);
return PR_FAILURE;
}
size = ( (int)retadr.va_range$ps_end_va -
(int)retadr.va_range$ps_start_va + 1
) >> NS_PAGEMGR_PAGE_BITS;
break;
default:
return PR_FAILURE;
}
#if defined(DEBUG)
printf("Actual page manager size is %d 4k pages\n",size);
#endif
/* We got at least something */
addr = (nsPage *)retadr.va_range$ps_start_va;
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(addr, NS_PAGEMGR_PAGE_BITS));
mMemoryBase = addr;
mPageCount = size;
mBoundary = addr;
return PR_SUCCESS;
#else
nsPage* addr = NULL;
nsPageCount size = maxPages;
mZero_fd = 0;
#ifdef HAVE_DEV_ZERO
mZero_fd = open("/dev/zero", O_RDWR);
while (addr == NULL) {
/* let the system place the heap */
addr = (nsPage*)mmap(0, size << NS_PAGEMGR_PAGE_BITS,
PROT_READ | PROT_WRITE,
MAP_PRIVATE,
mZero_fd, 0);
if (addr == (nsPage*)MAP_FAILED) {
addr = NULL;
size--;
if (size < minPages) {
return PR_FAILURE;
}
}
}
#else
#ifdef HAVE_VALLOC
while (addr == NULL) {
addr = (nsPage*)valloc(size << NS_PAGEMGR_PAGE_BITS);
if (NULL == addr) {
size--;
if (size < minPages) {
return PR_FAILURE;
}
}
}
memset(addr, '\0', size << NS_PAGEMGR_PAGE_BITS);
#endif /* HAVE_VALLOC */
#endif /* HAVE_DEV_ZERO */
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(addr, NS_PAGEMGR_PAGE_BITS));
mMemoryBase = addr;
mPageCount = size;
mBoundary = addr;
return PR_SUCCESS;
#endif
}
void
nsPageMgr::FinalizePages()
{
#if defined(XP_PC)
BOOL ok;
ok = VirtualFree((void*)mMemoryBase, 0, MEM_RELEASE);
PR_ASSERT(ok);
mMemoryBase = NULL;
mPageCount = 0;
nsAutoMonitor::DestroyMonitor(mMonitor);
mMonitor = NULL;
#elif defined(XP_MAC)
OSErr err;
PRUword i;
for (i = 0; i < mSegTableCount; i++) {
if (mSegTable[i].mHandle) {
TempDisposeHandle(mSegTable[i].mHandle, &err);
PR_ASSERT(err == 0);
}
}
#elif defined(XP_BEOS)
delete_area(mAid);
#elif defined(VMS)
struct _va_range retadr, retadr2;
retadr.va_range$ps_start_va = mMemoryBase;
retadr.va_range$ps_end_va = mMemoryBase +
(mPageCount << NS_PAGEMGR_PAGE_BITS) - 1;
sys$deltva(&retadr,&retadr2,0);
#else
#ifdef HAVE_DEV_ZERO
munmap((caddr_t)mMemoryBase, mPageCount << NS_PAGEMGR_PAGE_BITS);
close(mZero_fd);
#else /* HAVE_DEV_ZERO */
#ifdef HAVE_VALLOC
free(mMemoryBase);
#endif /* HAVE_VALLOC */
#endif /* HAVE_DEV_ZERO */
#endif
}
/*******************************************************************************
* Page Manager
******************************************************************************/
nsPageMgr::nsPageMgr()
: mUnusedClusterDescs(nsnull),
mFreeClusters(nsnull),
mInUseClusters(nsnull),
mMonitor(nsnull),
mMemoryBase(nsnull),
mBoundary(nsnull),
#ifdef XP_PC
mLastPageFreed(nsnull),
mLastPageFreedSize(0),
mLastPageTemp(nsnull),
mLastPageTempSize(0),
#ifdef NS_PAGEMGR_DEBUG
mLastPageAllocTries(0),
mLastPageAllocHits(0),
mLastPageFreeTries(0),
mLastPageFreeHits(0),
#endif
#endif
#if defined(XP_MAC)
mSegMap(nsnull),
mSegTable(nsnull),
mSegTableCount(0),
#endif
#if defined(XP_BEOS)
mAid(B_ERROR),
#endif
mPageCount(0)
{
NS_INIT_REFCNT();
}
nsresult
nsPageMgr::Init(nsPageCount minPages, nsPageCount maxPages)
{
PRStatus status;
mMonitor = nsAutoMonitor::NewMonitor("PageMgr");
if (mMonitor == NULL)
return PR_FAILURE;
status = InitPages(minPages, maxPages);
if (status != PR_SUCCESS)
return status;
/* make sure these got set */
PR_ASSERT(mMemoryBase);
PR_ASSERT(mBoundary);
mFreeClusters = NULL;
mInUseClusters = NULL;
return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
}
nsPageMgr::~nsPageMgr()
{
#if defined(XP_PC) && defined(NS_PAGEMGR_DEBUG)
if (stderr) {
fprintf(stderr, "Page Manager Cache: alloc hits: %u/%u %u%%, free hits: %u/%u %u%%\n",
mLastPageAllocHits, mLastPageAllocTries,
(mLastPageAllocHits * 100 / mLastPageAllocTries),
mLastPageFreeHits, mLastPageFreeTries,
(mLastPageFreeHits * 100 / mLastPageFreeTries));
}
#endif
FinalizePages();
nsClusterDesc* chain = mUnusedClusterDescs;
while (chain) {
nsClusterDesc* desc = chain;
chain = chain->mNext;
PR_Free(desc);
}
}
NS_METHOD
nsPageMgr::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsPageMgr* pageMgr = new nsPageMgr();
if (pageMgr == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(pageMgr);
nsresult rv = pageMgr->Init();
if (NS_FAILED(rv)) {
NS_RELEASE(pageMgr);
return rv;
}
rv = pageMgr->QueryInterface(aIID, aResult);
NS_RELEASE(pageMgr);
return NS_OK;
}
NS_IMPL_ISUPPORTS2(nsPageMgr, nsIPageManager, nsIAllocator)
/******************************************************************************/
#ifdef XP_PC
#ifdef NS_PAGEMGR_PAGE_HYSTERESIS
#ifdef NS_PAGEMGR_DEBUG
void*
nsPageMgr::NS_PAGEMGR_COMMIT_CLUSTER(void* addr, PRUword size)
{
mLastPageAllocTries++;
if (mLastPageFreed == (void*)(addr) && mLastPageFreedSize == (size)) {
#ifdef NS_PAGEMGR_COMMIT_TRACE
char buf[64];
PR_snprintf(buf, sizeof(buf), "lalloc %p %u\n",
mLastPageFreed, mLastPageFreedSize);
OutputDebugString(buf);
#endif
DBG_MEMSET(mLastPageFreed, NS_PAGEMGR_PAGE_ALLOC_PATTERN, mLastPageFreedSize);
mLastPageTemp = mLastPageFreed;
mLastPageFreed = NULL;
mLastPageFreedSize = 0;
mLastPageAllocHits++;
return mLastPageTemp;
}
else {
/* If the cached pages intersect the current request, we lose.
Just free the cached request instead of trying to split it up. */
if (mLastPageFreed &&
nsOverlapping((char*)mLastPageFreed, ((char*)mLastPageFreed + mLastPageFreedSize),
(char*)(addr), ((char*)(addr) + (size)))
// ((char*)mLastPageFreed < ((char*)(addr) + (size))
// && ((char*)mLastPageFreed + mLastPageFreedSize) > (char*)(addr))
) {
#ifdef NS_PAGEMGR_COMMIT_TRACE
char buf[64];
PR_snprintf(buf, sizeof(buf), "valloc %p %u (vfree %p %u last=%u:%u req=%u:%u)\n",
addr, size,
mLastPageFreed, mLastPageFreedSize,
(char*)mLastPageFreed, ((char*)mLastPageFreed + mLastPageFreedSize),
(char*)(addr), ((char*)(addr) + (size)));
OutputDebugString(buf);
#endif
VirtualFree(mLastPageFreed, mLastPageFreedSize, MEM_DECOMMIT);
mLastPageFreed = NULL;
mLastPageFreedSize = 0;
mLastPageFreeHits--; /* lost after all */
}
else {
#ifdef NS_PAGEMGR_COMMIT_TRACE
char buf[64];
PR_snprintf(buf, sizeof(buf), "valloc %p %u (skipping %p %u)\n",
addr, size,
mLastPageFreed, mLastPageFreedSize);
OutputDebugString(buf);
#endif
}
return VirtualAlloc((void*)(addr), (size), MEM_COMMIT, PAGE_READWRITE);
}
}
int
nsPageMgr::NS_PAGEMGR_DECOMMIT_CLUSTER(void* addr, PRUword size)
{
mLastPageFreeTries++;
PR_ASSERT(mLastPageFreed != (void*)(addr));
if (mLastPageFreed) {
/* If we've already got a cached page, just keep it. Heuristically,
this tends to give us a higher hit rate because of the order in
which pages are decommitted. */
#ifdef NS_PAGEMGR_COMMIT_TRACE
char buf[64];
PR_snprintf(buf, sizeof(buf), "vfree %p %u (cached %p %u)\n",
addr, size, mLastPageFreed, mLastPageFreedSize);
OutputDebugString(buf);
#endif
return VirtualFree(addr, size, MEM_DECOMMIT);
}
mLastPageFreed = (void*)(addr);
mLastPageFreedSize = (size);
DBG_MEMSET(mLastPageFreed, NS_PAGEMGR_PAGE_FREE_PATTERN, mLastPageFreedSize);
#ifdef NS_PAGEMGR_COMMIT_TRACE
{
char buf[64];
PR_snprintf(buf, sizeof(buf), "lfree %p %u\n",
mLastPageFreed, mLastPageFreedSize);
OutputDebugString(buf);
}
#endif
mLastPageFreeHits++;
return 1;
}
#else /* !NS_PAGEMGR_DEBUG */
#define NS_PAGEMGR_COMMIT_CLUSTER(addr, size) \
(PR_ASSERT((void*)(addr) != NULL), \
((mLastPageFreed == (void*)(addr) && mLastPageFreedSize == (size)) \
? (DBG_MEMSET(mLastPageFreed, NS_PAGEMGR_PAGE_ALLOC_PATTERN, mLastPageFreedSize), \
mLastPageTemp = mLastPageFreed, \
mLastPageFreed = NULL, \
mLastPageFreedSize = 0, \
mLastPageTemp) \
: (((mLastPageFreed && \
((char*)mLastPageFreed < ((char*)(addr) + (size)) \
&& ((char*)mLastPageFreed + mLastPageFreedSize) > (char*)(addr))) \
? (VirtualFree(mLastPageFreed, mLastPageFreedSize, MEM_DECOMMIT), \
mLastPageFreed = NULL, \
mLastPageFreedSize = 0) \
: ((void)0)), \
VirtualAlloc((void*)(addr), (size), MEM_COMMIT, PAGE_READWRITE)))) \
#define NS_PAGEMGR_DECOMMIT_CLUSTER(addr, size) \
(PR_ASSERT(mLastPageFreed != (void*)(addr)), \
(mLastPageFreed \
? (VirtualFree(addr, size, MEM_DECOMMIT)) \
: (mLastPageFreed = (addr), \
mLastPageFreedSize = (size), \
DBG_MEMSET(mLastPageFreed, NS_PAGEMGR_PAGE_FREE_PATTERN, mLastPageFreedSize), \
1))) \
#endif /* !NS_PAGEMGR_DEBUG */
#else /* !NS_PAGEMGR_PAGE_HYSTERESIS */
#define NS_PAGEMGR_COMMIT_CLUSTER(addr, size) \
VirtualAlloc((void*)(addr), (size), MEM_COMMIT, PAGE_READWRITE)
#define NS_PAGEMGR_DECOMMIT_CLUSTER(addr, size) \
VirtualFree((void*)(addr), (size), MEM_DECOMMIT)
#endif /* !NS_PAGEMGR_PAGE_HYSTERESIS */
#else /* !XP_PC */
#define NS_PAGEMGR_COMMIT_CLUSTER(addr, size) (addr)
#define NS_PAGEMGR_DECOMMIT_CLUSTER(addr, size) 1
#endif /* !XP_PC */
nsPage*
nsPageMgr::NewCluster(nsPageCount nPages)
{
nsAutoMonitor mon(mMonitor);
nsPage* addr;
PR_ASSERT(nPages > 0);
addr = AllocClusterFromFreeList(nPages);
if (!addr && mBoundary + nPages <= mMemoryBase + mPageCount) {
addr = mBoundary;
mBoundary += nPages;
}
if (addr) {
/* Extend the mapping */
nsPage* vaddr;
PRUword size = nPages << NS_PAGEMGR_PAGE_BITS;
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(addr, NS_PAGEMGR_PAGE_BITS));
vaddr = (nsPage*)NS_PAGEMGR_COMMIT_CLUSTER((void*)addr, size);
#ifdef NS_PAGEMGR_VERIFYCLUSTERS
VerifyClusters(nPages);
#endif
if (addr) {
PR_ASSERT(vaddr == addr);
}
else {
DestroyCluster(addr, nPages);
}
DBG_MEMSET(addr, NS_PAGEMGR_PAGE_ALLOC_PATTERN, size);
}
return (nsPage*)addr;
}
void
nsPageMgr::DestroyCluster(nsPage* basePage, nsPageCount nPages)
{
nsAutoMonitor mon(mMonitor);
int freeResult;
PRUword size = nPages << NS_PAGEMGR_PAGE_BITS;
PR_ASSERT(nPages > 0);
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(basePage, NS_PAGEMGR_PAGE_BITS));
PR_ASSERT(mMemoryBase <= basePage);
PR_ASSERT(basePage + nPages <= mMemoryBase + mPageCount);
DBG_MEMSET(basePage, NS_PAGEMGR_PAGE_FREE_PATTERN, size);
freeResult = NS_PAGEMGR_DECOMMIT_CLUSTER((void*)basePage, size);
PR_ASSERT(freeResult);
if (basePage + nPages == mBoundary) {
nsClusterDesc **p;
nsClusterDesc *desc;
/* We deallocated the last set of clusters. Move the mBoundary lower. */
mBoundary = basePage;
/* The last free cluster might now be adjacent to the mBoundary; if so,
move the mBoundary before that cluster and delete that cluster
altogether. */
p = &mFreeClusters;
while ((desc = *p) != NULL) {
if (!desc->mNext && desc->mAddr + desc->mPageCount == mBoundary) {
*p = 0;
mBoundary = desc->mAddr;
DeleteFreeClusterDesc(desc);
}
else {
p = &desc->mNext;
}
}
}
else {
AddClusterToFreeList(basePage, nPages);
}
#ifdef NS_PAGEMGR_VERIFYCLUSTERS
VerifyClusters(-(PRWord)nPages);
#endif
}
////////////////////////////////////////////////////////////////////////////////
// nsIPageManager methods:
NS_IMETHODIMP
nsPageMgr::AllocPages(PRUint32 pageCount, void* *result)
{
nsPage* page = NewCluster(NS_STATIC_CAST(nsPageCount, pageCount));
if (page == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
*result = page;
return NS_OK;
}
NS_IMETHODIMP
nsPageMgr::DeallocPages(PRUint32 pageCount, void* pages)
{
DestroyCluster(NS_STATIC_CAST(nsPage*, pages),
NS_STATIC_CAST(nsPageCount, pageCount));
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIAllocator methods:
//
// Note: nsIAllocator needs to keep track of the size of the blocks it allocates
// whereas, nsIPageManager doesn't. That means that there's a little extra
// overhead for users of this interface. It also means that things allocated
// with the nsIPageManager interface can't be freed with the nsIAllocator
// interface and vice versa.
NS_IMETHODIMP_(void*)
nsPageMgr::Alloc(PRUint32 size)
{
nsAutoMonitor mon(mMonitor);
nsresult rv;
void* page = nsnull;
PRUint32 pageCount = NS_PAGEMGR_PAGE_COUNT(size);
rv = AllocPages(pageCount, &page);
if (NS_FAILED(rv))
return nsnull;
// Add this cluster to the mInUseClusters list:
nsClusterDesc* desc = NewFreeClusterDesc();
if (desc == nsnull) {
rv = DeallocPages(pageCount, page);
NS_ASSERTION(NS_SUCCEEDED(rv), "DeallocPages failed");
return nsnull;
}
desc->mAddr = (nsPage*)page;
desc->mPageCount = pageCount;
desc->mNext = mInUseClusters;
mInUseClusters = desc;
return page;
}
NS_IMETHODIMP_(void*)
nsPageMgr::Realloc(void* ptr, PRUint32 size)
{
// XXX This realloc implementation could be made smarter by trying to
// append to the current block, but I don't think we really care right now.
nsresult rv;
rv = Free(ptr);
if (NS_FAILED(rv)) return nsnull;
void* newPtr = Alloc(size);
return newPtr;
}
NS_IMETHODIMP
nsPageMgr::Free(void* ptr)
{
nsAutoMonitor mon(mMonitor);
PR_ASSERT(NS_PAGEMGR_IS_ALIGNED(ptr, NS_PAGEMGR_PAGE_BITS));
// Remove the cluster from the mInUseClusters list:
nsClusterDesc** list = &mInUseClusters;
nsClusterDesc* desc;
while ((desc = *list) != nsnull) {
if (desc->mAddr == ptr) {
// found -- unlink the desc and free it
*list = desc->mNext;
nsresult rv = DeallocPages(desc->mPageCount, ptr);
DeleteFreeClusterDesc(desc);
return rv;
}
list = &desc->mNext;
}
NS_ASSERTION(0, "memory not allocated with nsPageMgr::Alloc");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsPageMgr::HeapMinimize(void)
{
// can't compact this heap
return NS_ERROR_FAILURE;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,203 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsPageMgr_h__
#define nsPageMgr_h__
#include "nsIPageManager.h"
#include "nsIAllocator.h"
#include "nscore.h"
#include "nsAutoLock.h"
#include "prlog.h"
#ifdef XP_MAC
#include <Types.h>
#include <Memory.h>
#endif
#if defined(XP_BEOS)
#include <OS.h>
#endif
/*******************************************************************************
* Configuration/Debugging parameters:
******************************************************************************/
#ifdef NS_DEBUG
//#define NS_PAGEMGR_DEBUG
#endif
#define NS_PAGEMGR_PAGE_HYSTERESIS /* undef if you want to compare */
//#define NS_PAGEMGR_COMMIT_TRACE
#ifdef NS_PAGEMGR_DEBUG
#define NS_PAGEMGR_VERIFYCLUSTERS
#define NS_PAGEMGR_DBG_MEMSET
#endif
#define NS_PAGEMGR_MIN_PAGES 32 // XXX bogus -- this should be a runtime parameter
#define NS_PAGEMGR_MAX_PAGES 2560 // 10 meg XXX bogus -- this should be a runtime parameter
/******************************************************************************/
#ifdef NS_PAGEMGR_DBG_MEMSET
#include <string.h> /* for memset */
#include <stdio.h>
#define DBG_MEMSET(dest, pattern, size) memset(dest, pattern, size)
#define NS_PAGEMGR_PAGE_ALLOC_PATTERN 0xCB
#define NS_PAGEMGR_PAGE_FREE_PATTERN 0xCD
#else
#define DBG_MEMSET(dest, pattern, size) ((void)0)
#endif
#define NS_PAGEMGR_ALIGN(p, nBits) ((PRWord)(p) & ~((1 << nBits) - 1))
#define NS_PAGEMGR_IS_ALIGNED(p, nBits) ((PRWord)(p) == NS_PAGEMGR_ALIGN(p, nBits))
/*******************************************************************************
* Test for overlapping (one-dimensional) regions
******************************************************************************/
inline PRBool nsOverlapping(char* min1, char* max1, char* min2, char* max2)
{
PR_ASSERT(min1 < max1);
PR_ASSERT(min2 < max2);
return (min1 < max2 && max1 > min2);
}
/*******************************************************************************
* Types
******************************************************************************/
typedef PRUint8 nsPage[NS_PAGEMGR_PAGE_SIZE];
typedef PRUword nsPageCount; /* int big enough to count pages */
/*******************************************************************************
* Macros
******************************************************************************/
#define NS_PAGEMGR_PAGE_ROUNDDN(addr) ((nsPage*)NS_PAGEMGR_ALIGN((PRUword)(addr), NS_PAGEMGR_PAGE_BITS))
#define NS_PAGEMGR_PAGE_ROUNDUP(addr) NS_PAGEMGR_PAGE_ROUNDDN((PRUword)(addr) + NS_PAGEMGR_PAGE_SIZE)
/*******************************************************************************
* Page Manager
******************************************************************************/
class nsPageMgr : public nsIPageManager, public nsIAllocator {
public:
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
// nsIPageManager methods:
NS_IMETHOD AllocPages(PRUint32 pageCount, void* *result);
NS_IMETHOD DeallocPages(PRUint32 pageCount, void* pages);
// nsIAllocator methods:
NS_IMETHOD_(void*) Alloc(PRUint32 size);
NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size);
NS_IMETHOD Free(void* ptr);
NS_IMETHOD HeapMinimize(void);
// nsPageMgr methods:
nsPageMgr();
virtual ~nsPageMgr();
nsresult Init(nsPageCount minPages = NS_PAGEMGR_MIN_PAGES,
nsPageCount maxPages = NS_PAGEMGR_MAX_PAGES);
struct nsClusterDesc {
nsClusterDesc* mNext; /* Link to next cluster of free pages */
nsPage* mAddr; /* First page in cluster of free pages */
nsPageCount mPageCount; /* Total size of cluster of free pages in bytes */
};
void DeleteFreeClusterDesc(nsClusterDesc *desc);
nsClusterDesc* NewFreeClusterDesc(void);
nsPage* AllocClusterFromFreeList(PRUword nPages);
void AddClusterToFreeList(nsPage* addr, PRWord nPages);
#ifdef NS_PAGEMGR_VERIFYCLUSTERS
void VerifyClusters(PRWord nPagesDelta);
#endif
#if defined(XP_PC) && defined(NS_PAGEMGR_DEBUG)
void* NS_PAGEMGR_COMMIT_CLUSTER(void* addr, PRUword size);
int NS_PAGEMGR_DECOMMIT_CLUSTER(void* addr, PRUword size);
#endif
// Managing Pages:
PRStatus InitPages(nsPageCount minPages, nsPageCount maxPages);
void FinalizePages();
nsPage* NewCluster(nsPageCount nPages);
void DestroyCluster(nsPage* basePage, nsPageCount nPages);
protected:
nsClusterDesc* mUnusedClusterDescs;
nsClusterDesc* mFreeClusters;
nsClusterDesc* mInUseClusters; // used by nsIAllocator methods
PRMonitor* mMonitor;
nsPage* mMemoryBase;
nsPage* mBoundary;
nsPageCount mPageCount;
#ifdef XP_PC
/* one-page hysteresis */
void* mLastPageFreed;
PRUword mLastPageFreedSize;
void* mLastPageTemp;
PRUword mLastPageTempSize;
# ifdef NS_PAGEMGR_DEBUG
PRUword mLastPageAllocTries;
PRUword mLastPageAllocHits;
PRUword mLastPageFreeTries;
PRUword mLastPageFreeHits;
# endif
#endif
#if defined(XP_MAC)
struct nsSegmentDesc {
Handle mHandle;
nsPage* mFirstPage;
nsPage* mLastPage;
};
PRUint8* mSegMap;
nsSegmentDesc* mSegTable;
PRWord mSegTableCount;
#endif
#if defined(XP_BEOS)
area_id mAid;
#endif
#if (! defined(VMS)) && (! defined(XP_BEOS)) && (! defined(XP_MAC)) && (! defined(XP_PC))
int mZero_fd;
#endif
};
/******************************************************************************/
#endif /* nsPageMgr_h__ */

View File

@@ -1,551 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#define NS_IMPL_IDS
#include "nsProperties.h"
#include <iostream.h>
////////////////////////////////////////////////////////////////////////////////
nsProperties::nsProperties(nsISupports* outer)
{
NS_INIT_AGGREGATED(outer);
}
NS_METHOD
nsProperties::Create(nsISupports *outer, REFNSIID aIID, void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
NS_ENSURE_PROPER_AGGREGATION(outer, aIID);
nsProperties* props = new nsProperties(outer);
if (props == NULL)
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = props->AggregatedQueryInterface(aIID, aResult);
if (NS_FAILED(rv))
delete props;
return rv;
}
PRBool
nsProperties::ReleaseValues(nsHashKey* key, void* data, void* closure)
{
nsISupports* value = (nsISupports*)data;
NS_IF_RELEASE(value);
return PR_TRUE;
}
nsProperties::~nsProperties()
{
Enumerate(ReleaseValues);
}
NS_IMPL_AGGREGATED(nsProperties);
NS_METHOD
nsProperties::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID()))
*aInstancePtr = GetInner();
else if (aIID.Equals(nsIProperties::GetIID()))
*aInstancePtr = NS_STATIC_CAST(nsIProperties*, this);
else {
*aInstancePtr = nsnull;
return NS_NOINTERFACE;
}
NS_ADDREF((nsISupports*)*aInstancePtr);
return NS_OK;
}
NS_IMETHODIMP
nsProperties::DefineProperty(const char* prop, nsISupports* initialValue)
{
nsStringKey key(prop);
if (Exists(&key))
return NS_ERROR_FAILURE;
nsISupports* prevValue = (nsISupports*)Put(&key, initialValue);
NS_ASSERTION(prevValue == NULL, "hashtable error");
NS_IF_ADDREF(initialValue);
return NS_OK;
}
NS_IMETHODIMP
nsProperties::UndefineProperty(const char* prop)
{
nsStringKey key(prop);
if (!Exists(&key))
return NS_ERROR_FAILURE;
nsISupports* prevValue = (nsISupports*)Remove(&key);
NS_IF_RELEASE(prevValue);
return NS_OK;
}
NS_IMETHODIMP
nsProperties::GetProperty(const char* prop, nsISupports* *result)
{
nsStringKey key(prop);
if (!Exists(&key))
return NS_ERROR_FAILURE;
nsISupports* value = (nsISupports*)Get(&key);
NS_IF_ADDREF(value);
*result = value;
return NS_OK;
}
NS_IMETHODIMP
nsProperties::SetProperty(const char* prop, nsISupports* value)
{
nsStringKey key(prop);
if (!Exists(&key))
return NS_ERROR_FAILURE;
nsISupports* prevValue = (nsISupports*)Put(&key, value);
NS_IF_RELEASE(prevValue);
NS_IF_ADDREF(value);
return NS_OK;
}
NS_IMETHODIMP
nsProperties::HasProperty(const char* prop, nsISupports* expectedValue)
{
nsISupports* value;
nsresult rv = GetProperty(prop, &value);
if (NS_FAILED(rv)) return NS_COMFALSE;
rv = (value == expectedValue) ? NS_OK : NS_COMFALSE;
NS_IF_RELEASE(value);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
nsresult
NS_NewIProperties(nsIProperties* *result)
{
return nsProperties::Create(NULL, nsIProperties::GetIID(), (void**)result);
}
////////////////////////////////////////////////////////////////////////////////
// Persistent Properties (should go in a separate file)
////////////////////////////////////////////////////////////////////////////////
#include "nsID.h"
#include "nsCRT.h"
#include "nsIInputStream.h"
#include "nsIProperties.h"
#include "nsIUnicharInputStream.h"
#include "nsProperties.h"
#include "pratom.h"
static PLHashNumber
HashKey(const PRUnichar *aString)
{
return (PLHashNumber) nsCRT::HashValue(aString);
}
static PRIntn
CompareKeys(const PRUnichar *aStr1, const PRUnichar *aStr2)
{
return nsCRT::strcmp(aStr1, aStr2) == 0;
}
nsPersistentProperties::nsPersistentProperties()
{
NS_INIT_REFCNT();
mIn = nsnull;
mSubclass = NS_STATIC_CAST(nsIPersistentProperties*, this);
mTable = PL_NewHashTable(8, (PLHashFunction) HashKey,
(PLHashComparator) CompareKeys,
(PLHashComparator) nsnull, nsnull, nsnull);
}
PR_STATIC_CALLBACK(PRIntn)
FreeHashEntries(PLHashEntry* he, PRIntn i, void* arg)
{
nsCRT::free((PRUnichar*)he->key);
nsCRT::free((PRUnichar*)he->value);
return HT_ENUMERATE_REMOVE;
}
nsPersistentProperties::~nsPersistentProperties()
{
if (mTable) {
// Free the PRUnicode* pointers contained in the hash table entries
PL_HashTableEnumerateEntries(mTable, FreeHashEntries, 0);
PL_HashTableDestroy(mTable);
mTable = nsnull;
}
}
NS_METHOD
nsPersistentProperties::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsPersistentProperties* props = new nsPersistentProperties();
if (props == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(props);
nsresult rv = props->QueryInterface(aIID, aResult);
NS_RELEASE(props);
return rv;
}
NS_IMPL_ISUPPORTS2(nsPersistentProperties, nsIPersistentProperties, nsIProperties)
NS_IMETHODIMP
nsPersistentProperties::Load(nsIInputStream *aIn)
{
PRInt32 c;
nsresult ret;
nsAutoString uesc("x-u-escaped");
ret = NS_NewConverterStream(&mIn, nsnull, aIn, 0, &uesc);
if (ret != NS_OK) {
#ifdef NS_DEBUG
cout << "NS_NewConverterStream failed" << endl;
#endif
return NS_ERROR_FAILURE;
}
c = Read();
while (1) {
c = SkipWhiteSpace(c);
if (c < 0) {
break;
}
else if ((c == '#') || (c == '!')) {
c = SkipLine(c);
continue;
}
else {
nsAutoString key("");
while ((c >= 0) && (c != '=') && (c != ':')) {
key.Append((PRUnichar) c);
c = Read();
}
if (c < 0) {
break;
}
char *trimThese = " \t";
key.Trim(trimThese, PR_FALSE, PR_TRUE);
c = Read();
nsAutoString value("");
while ((c >= 0) && (c != '\r') && (c != '\n')) {
if (c == '\\') {
c = Read();
if ((c == '\r') || (c == '\n')) {
c = SkipWhiteSpace(c);
}
else {
value.Append('\\');
}
}
value.Append((PRUnichar) c);
c = Read();
}
value.Trim(trimThese, PR_TRUE, PR_TRUE);
nsAutoString oldValue("");
mSubclass->SetStringProperty(key, value, oldValue);
}
}
mIn->Close();
NS_RELEASE(mIn);
NS_ASSERTION(!mIn, "unexpected remaining reference");
return NS_OK;
}
NS_IMETHODIMP
nsPersistentProperties::SetStringProperty(const nsString& aKey, nsString& aNewValue,
nsString& aOldValue)
{
// XXX The ToNewCString() calls allocate memory using "new" so this code
// causes a memory leak...
#if 0
cout << "will add " << aKey.ToNewCString() << "=" << aNewValue.ToNewCString() << endl;
#endif
if (!mTable) {
return NS_ERROR_FAILURE;
}
const PRUnichar *key = aKey.GetUnicode(); // returns internal pointer (not a copy)
PRUint32 len;
PRUint32 hashValue = nsCRT::HashValue(key, &len);
PLHashEntry **hep = PL_HashTableRawLookup(mTable, hashValue, key);
PLHashEntry *he = *hep;
if (he) {
// XXX should we copy the old value to aOldValue, and then remove it?
#ifdef NS_DEBUG
char buf[128];
aKey.ToCString(buf, sizeof(buf));
printf("warning: property %s already exists\n", buf);
#endif
return NS_OK;
}
PL_HashTableRawAdd(mTable, hep, hashValue, aKey.ToNewUnicode(),
aNewValue.ToNewUnicode());
return NS_OK;
}
NS_IMETHODIMP
nsPersistentProperties::Save(nsIOutputStream* aOut, const nsString& aHeader)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsPersistentProperties::Subclass(nsIPersistentProperties* aSubclass)
{
if (aSubclass) {
mSubclass = aSubclass;
}
return NS_OK;
}
NS_IMETHODIMP
nsPersistentProperties::GetStringProperty(const nsString& aKey, nsString& aValue)
{
if (!mTable)
return NS_ERROR_FAILURE;
const PRUnichar *key = aKey.GetUnicode();
if (!mTable) {
return NS_ERROR_FAILURE;
}
PRUint32 len;
PRUint32 hashValue = nsCRT::HashValue(key, &len);
PLHashEntry **hep = PL_HashTableRawLookup(mTable, hashValue, key);
PLHashEntry *he = *hep;
if (he) {
aValue = (const PRUnichar*)he->value;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
PR_STATIC_CALLBACK(PRIntn)
AddElemToArray(PLHashEntry* he, PRIntn i, void* arg)
{
nsISupportsArray *propArray = (nsISupportsArray *) arg;
nsString* keyStr = new nsString((PRUnichar*) he->key);
nsString* valueStr = new nsString((PRUnichar*) he->value);
nsPropertyElement *element = new nsPropertyElement();
if (!element)
return HT_ENUMERATE_STOP;
NS_ADDREF(element);
element->SetKey(keyStr);
element->SetValue(valueStr);
propArray->InsertElementAt(element, i);
return HT_ENUMERATE_NEXT;
}
NS_IMETHODIMP
nsPersistentProperties::EnumerateProperties(nsIBidirectionalEnumerator** aResult)
{
if (!mTable)
return NS_ERROR_FAILURE;
nsISupportsArray* propArray;
nsresult rv = NS_NewISupportsArray(&propArray);
if (rv != NS_OK)
return rv;
// Step through hash entries populating a transient array
PRIntn n = PL_HashTableEnumerateEntries(mTable, AddElemToArray, (void *)propArray);
if ( n < (PRIntn) mTable->nentries )
return NS_ERROR_OUT_OF_MEMORY;
// Convert array into enumerator
rv = NS_NewISupportsArrayEnumerator(propArray, aResult);
if (rv != NS_OK)
return rv;
return NS_OK;
}
PRInt32
nsPersistentProperties::Read()
{
PRUnichar c;
PRUint32 nRead;
nsresult ret;
ret = mIn->Read(&c, 0, 1, &nRead);
if (ret == NS_OK && nRead == 1) {
return c;
}
return -1;
}
#define IS_WHITE_SPACE(c) \
(((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n'))
PRInt32
nsPersistentProperties::SkipWhiteSpace(PRInt32 c)
{
while ((c >= 0) && IS_WHITE_SPACE(c)) {
c = Read();
}
return c;
}
PRInt32
nsPersistentProperties::SkipLine(PRInt32 c)
{
while ((c >= 0) && (c != '\r') && (c != '\n')) {
c = Read();
}
if (c == '\r') {
c = Read();
}
if (c == '\n') {
c = Read();
}
return c;
}
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsPersistentProperties::DefineProperty(const char* prop, nsISupports* initialValue)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsPersistentProperties::UndefineProperty(const char* prop)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsPersistentProperties::GetProperty(const char* prop, nsISupports* *result)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsPersistentProperties::SetProperty(const char* prop, nsISupports* value)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsPersistentProperties::HasProperty(const char* prop, nsISupports* value)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////////
// PropertyElement
////////////////////////////////////////////////////////////////////////////////
nsPropertyElement::nsPropertyElement()
{
NS_INIT_REFCNT();
mKey = nsnull;
mValue = nsnull;
}
nsPropertyElement::~nsPropertyElement()
{
if (mKey)
delete mKey;
if (mValue)
delete mValue;
}
NS_METHOD
nsPropertyElement::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
{
if (aOuter)
return NS_ERROR_NO_AGGREGATION;
nsPropertyElement* propElem = new nsPropertyElement();
if (propElem == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(propElem);
nsresult rv = propElem->QueryInterface(aIID, aResult);
NS_RELEASE(propElem);
return rv;
}
NS_IMPL_ISUPPORTS1(nsPropertyElement, nsIPropertyElement)
NS_IMETHODIMP
nsPropertyElement::GetKey(nsString** aReturnKey)
{
if (aReturnKey)
{
*aReturnKey = mKey;
return NS_OK;
}
return NS_ERROR_INVALID_POINTER;
}
NS_IMETHODIMP
nsPropertyElement::GetValue(nsString** aReturnValue)
{
if (aReturnValue)
{
*aReturnValue = mValue;
return NS_OK;
}
return NS_ERROR_INVALID_POINTER;
}
NS_IMETHODIMP
nsPropertyElement::SetKey(nsString* aKey)
{
mKey = aKey;
return NS_OK;
}
NS_IMETHODIMP
nsPropertyElement::SetValue(nsString* aValue)
{
mValue = aValue;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,113 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef nsProperties_h___
#define nsProperties_h___
#include "nsIProperties.h"
#include "nsHashtable.h"
#include "nsAgg.h"
class nsIUnicharInputStream;
class nsProperties : public nsIProperties, public nsHashtable {
public:
NS_DECL_AGGREGATED
// nsIProperties methods:
NS_IMETHOD DefineProperty(const char* prop, nsISupports* initialValue);
NS_IMETHOD UndefineProperty(const char* prop);
NS_IMETHOD GetProperty(const char* prop, nsISupports* *result);
NS_IMETHOD SetProperty(const char* prop, nsISupports* value);
NS_IMETHOD HasProperty(const char* prop, nsISupports* value);
// nsProperties methods:
nsProperties(nsISupports* outer);
virtual ~nsProperties();
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
static PRBool ReleaseValues(nsHashKey* key, void* data, void* closure);
};
class nsPersistentProperties : public nsIPersistentProperties
{
public:
nsPersistentProperties();
virtual ~nsPersistentProperties();
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
// nsIProperties methods:
NS_IMETHOD DefineProperty(const char* prop, nsISupports* initialValue);
NS_IMETHOD UndefineProperty(const char* prop);
NS_IMETHOD GetProperty(const char* prop, nsISupports* *result);
NS_IMETHOD SetProperty(const char* prop, nsISupports* value);
NS_IMETHOD HasProperty(const char* prop, nsISupports* value);
// nsIPersistentProperties methods:
NS_IMETHOD Load(nsIInputStream* aIn);
NS_IMETHOD Save(nsIOutputStream* aOut, const nsString& aHeader);
NS_IMETHOD Subclass(nsIPersistentProperties* aSubclass);
NS_IMETHOD EnumerateProperties(nsIBidirectionalEnumerator* *aResult);
// XXX these 2 methods will be subsumed by the ones from
// nsIProperties once we figure this all out
NS_IMETHOD GetStringProperty(const nsString& aKey, nsString& aValue);
NS_IMETHOD SetStringProperty(const nsString& aKey, nsString& aNewValue,
nsString& aOldValue);
// nsPersistentProperties methods:
PRInt32 Read();
PRInt32 SkipLine(PRInt32 c);
PRInt32 SkipWhiteSpace(PRInt32 c);
nsIUnicharInputStream* mIn;
nsIPersistentProperties* mSubclass;
struct PLHashTable* mTable;
};
class nsPropertyElement : public nsIPropertyElement
{
public:
nsPropertyElement();
virtual ~nsPropertyElement();
NS_DECL_ISUPPORTS
static NS_METHOD
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
// nsIPropertyElement methods:
NS_IMETHOD GetKey(nsString** aReturnKey);
NS_IMETHOD GetValue(nsString** aReturnValue);
NS_IMETHOD SetKey(nsString* aKey);
NS_IMETHOD SetValue(nsString* aValue);
protected:
nsString* mKey;
nsString* mValue;
};
#endif /* nsProperties_h___ */

View File

@@ -1,186 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* We need this because Solaris' version of qsort is broken and
* causes array bounds reads.
*/
#include <stdlib.h>
#include "prtypes.h"
#include "nsQuickSort.h"
NS_BEGIN_EXTERN_C
#if !defined(DEBUG) && (defined(__cplusplus) || defined(__gcc))
# ifndef INLINE
# define INLINE inline
# endif
#else
# define INLINE
#endif
typedef int cmp_t(const void *, const void *, void *);
static INLINE char *med3(char *, char *, char *, cmp_t *, void *);
static INLINE void swapfunc(char *, char *, int, int);
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE, parmi, parmj, n) { \
long i = (n) / sizeof (TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
static INLINE void
swapfunc(char *a, char *b, int n, int swaptype)
{
if(swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(char, a, b, n)
}
#define swap(a, b) \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc((char *)a, (char*)b, (int)es, swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc((char *)a, (char *)b, (int)n, swaptype)
static INLINE char *
med3(char *a, char *b, char *c, cmp_t* cmp, void *data)
{
return cmp(a, b, data) < 0 ?
(cmp(b, c, data) < 0 ? b : (cmp(a, c, data) < 0 ? c : a ))
:(cmp(b, c, data) > 0 ? b : (cmp(a, c, data) < 0 ? a : c ));
}
void NS_QuickSort (
void *a,
unsigned int n,
unsigned int es,
cmp_t *cmp,
void *data
)
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp, data);
pm = med3(pm - d, pm, pm + d, cmp, data);
pn = med3(pn - 2 * d, pn - d, pn, cmp, data);
}
pm = med3(pl, pm, pn, cmp, data);
}
swap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a, data)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a, data)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm; pl > (char *)a && cmp(pl - es, pl, data) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pn = (char *)a + n * es;
r = PR_MIN(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = PR_MIN(pd - pc, (int)(pn - pd - es));
vecswap(pb, pn - r, r);
if ((r = pb - pa) > (int)es)
NS_QuickSort(a, r / es, es, cmp, data);
if ((r = pd - pc) > (int)es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;
goto loop;
}
/* NS_QuickSort(pn - r, r / es, es, cmp, data);*/
}
NS_END_EXTERN_C

View File

@@ -1,41 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* We need this because Solaris' version of qsort is broken and
* causes array bounds reads.
*/
#ifndef nsQuickSort_h___
#define nsQuickSort_h___
#include "nscore.h"
#include "prtypes.h"
/* Had to pull the following define out of xp_core.h
* to avoid including xp_core.h.
* That brought in too many header file dependencies.
*/
NS_BEGIN_EXTERN_C
PR_EXTERN(void) NS_QuickSort(void *, unsigned int, unsigned int,
int (*)(const void *, const void *, void *),
void *);
NS_END_EXTERN_C
#endif /* nsQuickSort_h___ */

View File

@@ -1,271 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsISizeOfHandler.h"
#include "nsIAtom.h"
#include "plhash.h"
class nsSizeOfHandler : public nsISizeOfHandler {
public:
nsSizeOfHandler();
virtual ~nsSizeOfHandler();
// nsISupports
NS_DECL_ISUPPORTS
// nsISizeOfHandler
NS_IMETHOD Init();
NS_IMETHOD RecordObject(void* aObject, PRBool* aResult);
NS_IMETHOD AddSize(nsIAtom* aKey, PRUint32 aSize);
NS_IMETHOD Report(nsISizeofReportFunc aFunc, void* aArg);
NS_IMETHOD GetTotals(PRUint32* aCountResult, PRUint32* aTotalSizeResult);
protected:
PRUint32 mTotalSize;
PRUint32 mTotalCount;
PLHashTable* mSizeTable;
PLHashTable* mObjectTable;
static PRIntn RemoveObjectEntry(PLHashEntry* he, PRIntn i, void* arg);
static PRIntn RemoveSizeEntry(PLHashEntry* he, PRIntn i, void* arg);
static PRIntn ReportEntry(PLHashEntry* he, PRIntn i, void* arg);
};
class SizeOfDataStats {
public:
SizeOfDataStats(nsIAtom* aType, PRUint32 aSize);
~SizeOfDataStats();
void Update(PRUint32 aSize);
nsIAtom* mType; // type
PRUint32 mCount; // # of objects of this type
PRUint32 mTotalSize; // total size of all objects of this type
PRUint32 mMinSize; // smallest size for this type
PRUint32 mMaxSize; // largest size for this type
};
//----------------------------------------------------------------------
MOZ_DECL_CTOR_COUNTER(SizeOfDataStats);
SizeOfDataStats::SizeOfDataStats(nsIAtom* aType, PRUint32 aSize)
: mType(aType),
mCount(1),
mTotalSize(aSize),
mMinSize(aSize),
mMaxSize(aSize)
{
MOZ_COUNT_CTOR(SizeOfDataStats);
NS_IF_ADDREF(mType);
}
SizeOfDataStats::~SizeOfDataStats()
{
MOZ_COUNT_DTOR(SizeOfDataStats);
NS_IF_RELEASE(mType);
}
void
SizeOfDataStats::Update(PRUint32 aSize)
{
mCount++;
if (aSize < mMinSize) mMinSize = aSize;
if (aSize > mMaxSize) mMaxSize = aSize;
mTotalSize += aSize;
}
//----------------------------------------------------------------------
#define POINTER_HASH_KEY(_atom) ((PLHashNumber) _atom)
static PLHashNumber
PointerHashKey(nsIAtom* key)
{
return POINTER_HASH_KEY(key);
}
static PRIntn
PointerCompareKeys(void* key1, void* key2)
{
return key1 == key2;
}
nsSizeOfHandler::nsSizeOfHandler()
: mTotalSize(0),
mTotalCount(0)
{
NS_INIT_REFCNT();
mTotalSize = 0;
mSizeTable = PL_NewHashTable(32, (PLHashFunction) PointerHashKey,
(PLHashComparator) PointerCompareKeys,
(PLHashComparator) nsnull,
nsnull, nsnull);
mObjectTable = PL_NewHashTable(32, (PLHashFunction) PointerHashKey,
(PLHashComparator) PointerCompareKeys,
(PLHashComparator) nsnull,
nsnull, nsnull);
}
PRIntn
nsSizeOfHandler::RemoveObjectEntry(PLHashEntry* he, PRIntn i, void* arg)
{
// Remove and free this entry and continue enumerating
return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
}
PRIntn
nsSizeOfHandler::RemoveSizeEntry(PLHashEntry* he, PRIntn i, void* arg)
{
if (he->value) {
SizeOfDataStats* stats = (SizeOfDataStats*) he->value;
he->value = nsnull;
delete stats;
}
// Remove and free this entry and continue enumerating
return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
}
nsSizeOfHandler::~nsSizeOfHandler()
{
if (nsnull != mObjectTable) {
PL_HashTableEnumerateEntries(mObjectTable, RemoveObjectEntry, 0);
PL_HashTableDestroy(mObjectTable);
}
if (nsnull != mSizeTable) {
PL_HashTableEnumerateEntries(mSizeTable, RemoveSizeEntry, 0);
PL_HashTableDestroy(mSizeTable);
}
}
NS_IMPL_ISUPPORTS1(nsSizeOfHandler, nsISizeOfHandler)
NS_IMETHODIMP
nsSizeOfHandler::Init()
{
if (mObjectTable) {
PL_HashTableEnumerateEntries(mObjectTable, RemoveObjectEntry, 0);
}
if (mSizeTable) {
PL_HashTableEnumerateEntries(mSizeTable, RemoveSizeEntry, 0);
}
mTotalCount = 0;
mTotalSize = 0;
return NS_OK;
}
NS_IMETHODIMP
nsSizeOfHandler::RecordObject(void* aAddr, PRBool* aResult)
{
if (!aResult) {
return NS_ERROR_NULL_POINTER;
}
PRBool result = PR_TRUE;
if (mObjectTable && aAddr) {
PLHashNumber hashCode = POINTER_HASH_KEY(aAddr);
PLHashEntry** hep = PL_HashTableRawLookup(mObjectTable, hashCode, aAddr);
PLHashEntry* he = *hep;
if (!he) {
// We've never seen it before. Add it to the table
(void) PL_HashTableRawAdd(mObjectTable, hep, hashCode, aAddr, aAddr);
result = PR_FALSE;
}
}
*aResult = result;
return NS_OK;
}
NS_IMETHODIMP
nsSizeOfHandler::AddSize(nsIAtom* aType, PRUint32 aSize)
{
PLHashNumber hashCode = POINTER_HASH_KEY(aType);
PLHashEntry** hep = PL_HashTableRawLookup(mSizeTable, hashCode, aType);
PLHashEntry* he = *hep;
if (he) {
// Stats already exist
SizeOfDataStats* stats = (SizeOfDataStats*) he->value;
stats->Update(aSize);
}
else {
// Make new stats for the new frame type
SizeOfDataStats* newStats = new SizeOfDataStats(aType, aSize);
PL_HashTableRawAdd(mSizeTable, hep, hashCode, aType, newStats);
}
mTotalCount++;
mTotalSize += aSize;
return NS_OK;
}
struct ReportArgs {
nsISizeOfHandler* mHandler;
nsISizeofReportFunc mFunc;
void* mArg;
};
PRIntn
nsSizeOfHandler::ReportEntry(PLHashEntry* he, PRIntn i, void* arg)
{
ReportArgs* ra = (ReportArgs*) arg;
if (he && ra && ra->mFunc) {
SizeOfDataStats* stats = (SizeOfDataStats*) he->value;
if (stats) {
(*ra->mFunc)(ra->mHandler, stats->mType, stats->mCount,
stats->mTotalSize, stats->mMinSize, stats->mMaxSize,
ra->mArg);
}
}
return HT_ENUMERATE_NEXT;
}
NS_IMETHODIMP
nsSizeOfHandler::Report(nsISizeofReportFunc aFunc, void* aArg)
{
ReportArgs ra;
ra.mHandler = this;
ra.mFunc = aFunc;
ra.mArg = aArg;
PL_HashTableEnumerateEntries(mSizeTable, ReportEntry, (void*) &ra);
return NS_OK;
}
NS_IMETHODIMP
nsSizeOfHandler::GetTotals(PRUint32* aTotalCountResult,
PRUint32* aTotalSizeResult)
{
if (!aTotalCountResult || !aTotalSizeResult) {
return NS_ERROR_NULL_POINTER;
}
*aTotalCountResult = mTotalCount;
*aTotalSizeResult = mTotalSize;
return NS_OK;
}
NS_COM nsresult
NS_NewSizeOfHandler(nsISizeOfHandler** aInstancePtrResult)
{
if (!aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
nsISizeOfHandler *it = new nsSizeOfHandler();
if (it == nsnull) {
return NS_ERROR_OUT_OF_MEMORY;
}
return it->QueryInterface(NS_GET_IID(nsISizeOfHandler), (void **) aInstancePtrResult);
}

Some files were not shown because too many files have changed in this diff Show More