Compare commits
2 Commits
STRING_200
...
regalloc_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c43d4984f | ||
|
|
cfe021ff88 |
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal file
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal 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
|
||||
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal file
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal 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
|
||||
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal file
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal 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_
|
||||
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal file
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal 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
|
||||
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal file
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal 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));
|
||||
}
|
||||
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal file
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal 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
|
||||
|
||||
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal 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_
|
||||
20
mozilla/ef/Compiler/RegisterAllocator/HashSet.cpp
Normal file
20
mozilla/ef/Compiler/RegisterAllocator/HashSet.cpp
Normal 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"
|
||||
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal file
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal 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_
|
||||
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal file
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal 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_
|
||||
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal file
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal 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_
|
||||
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal file
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal 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_
|
||||
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal file
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal 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_
|
||||
21
mozilla/ef/Compiler/RegisterAllocator/Liveness.cpp
Normal file
21
mozilla/ef/Compiler/RegisterAllocator/Liveness.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
/* -*- 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 "Liveness.h"
|
||||
|
||||
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal file
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal 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_
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal 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)
|
||||
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal file
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal 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_
|
||||
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal file
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal 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;
|
||||
}
|
||||
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal file
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal 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_
|
||||
|
||||
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal file
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal 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
|
||||
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal file
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal 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_
|
||||
38
mozilla/ef/Compiler/RegisterAllocator/RegisterAssigner.h
Normal file
38
mozilla/ef/Compiler/RegisterAllocator/RegisterAssigner.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* -*- 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_ASSIGNER_H_
|
||||
#define _REGISTER_ASSIGNER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
|
||||
class FastBitMatrix;
|
||||
|
||||
class RegisterAssigner
|
||||
{
|
||||
protected:
|
||||
VirtualRegisterManager& vRegManager;
|
||||
|
||||
public:
|
||||
RegisterAssigner(VirtualRegisterManager& vrMan) : vRegManager(vrMan) {}
|
||||
|
||||
virtual bool assignRegisters(FastBitMatrix& interferenceMatrix) = 0;
|
||||
};
|
||||
|
||||
#endif /* _REGISTER_ASSIGNER_H_ */
|
||||
25
mozilla/ef/Compiler/RegisterAllocator/RegisterClass.h
Normal file
25
mozilla/ef/Compiler/RegisterAllocator/RegisterClass.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* -*- 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_CLASS_H_
|
||||
#define _REGISTER_CLASS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
#endif // _REGISTER_CLASS_H_
|
||||
37
mozilla/ef/Compiler/RegisterAllocator/RegisterPressure.h
Normal file
37
mozilla/ef/Compiler/RegisterAllocator/RegisterPressure.h
Normal 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.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_PRESSURE_H_
|
||||
#define _REGISTER_PRESSURE_H_
|
||||
|
||||
#include "BitSet.h"
|
||||
#include "HashSet.h"
|
||||
|
||||
struct LowRegisterPressure
|
||||
{
|
||||
typedef BitSet Set;
|
||||
static const bool setIsOrdered = true;
|
||||
};
|
||||
|
||||
struct HighRegisterPressure
|
||||
{
|
||||
typedef HashSet Set;
|
||||
static const bool setIsOrdered = false;
|
||||
};
|
||||
|
||||
#endif // _REGISTER_PRESSURE_H_
|
||||
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal file
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal 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_
|
||||
32
mozilla/ef/Compiler/RegisterAllocator/SSATools.cpp
Normal file
32
mozilla/ef/Compiler/RegisterAllocator/SSATools.cpp
Normal 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);
|
||||
}
|
||||
29
mozilla/ef/Compiler/RegisterAllocator/SSATools.h
Normal file
29
mozilla/ef/Compiler/RegisterAllocator/SSATools.h
Normal 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_
|
||||
37
mozilla/ef/Compiler/RegisterAllocator/SparseSet.cpp
Normal file
37
mozilla/ef/Compiler/RegisterAllocator/SparseSet.cpp
Normal 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
|
||||
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal file
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal 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_
|
||||
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal file
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal 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
|
||||
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal file
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal 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_
|
||||
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal file
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal 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_
|
||||
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal file
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal 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();
|
||||
}
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal 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_ */
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.cpp
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* -*- 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 "VirtualRegister.h"
|
||||
#include "Instruction.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegister -
|
||||
|
||||
#ifdef MANUAL_TEMPLATES
|
||||
template class IndexedPool<VirtualRegister>;
|
||||
#endif
|
||||
|
||||
// Set the defining instruction.
|
||||
//
|
||||
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
|
||||
{
|
||||
if (definingInstruction != NULL) {
|
||||
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
|
||||
return;
|
||||
}
|
||||
definingInstruction = &instruction;
|
||||
}
|
||||
|
||||
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal file
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal 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 ®A == ®B;}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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_
|
||||
@@ -1,37 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
#
|
||||
|
||||
DEPTH = ..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src obsolete
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
#DIRS += \
|
||||
# tests
|
||||
#endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,29 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
- The contents of this file are subject to the Mozilla Public
|
||||
- License Version 1.1 (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/MPL/
|
||||
-
|
||||
- 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.
|
||||
-
|
||||
- The Initial Developer of the Original Code is Netscape
|
||||
- Communications. Portions created by Netscape Communications are
|
||||
- Copyright (C) 2001 by Netscape Communications. All
|
||||
- Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Scott Collins <scc@mozilla.org> (original author)
|
||||
-->
|
||||
<body>
|
||||
<h1><span class="LXRSHORTDESC">managing sequences of characters</span></h1>
|
||||
<p>
|
||||
<span class="LXRLONGDESC"></span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,29 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
- The contents of this file are subject to the Mozilla Public
|
||||
- License Version 1.1 (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/MPL/
|
||||
-
|
||||
- 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.
|
||||
-
|
||||
- The Initial Developer of the Original Code is Netscape
|
||||
- Communications. Portions created by Netscape Communications are
|
||||
- Copyright (C) 2001 by Netscape Communications. All
|
||||
- Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Scott Collins <scc@mozilla.org> (original author)
|
||||
-->
|
||||
<body>
|
||||
<h1><span class="LXRSHORTDESC">documentation aimed at programmers who are clients of the string library</span></h1>
|
||||
<p>
|
||||
<span class="LXRLONGDESC"></span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mac build settings for the release string library
|
||||
*/
|
||||
|
||||
#include "MacPrefix.h"
|
||||
|
||||
// while we're still a part of xpcom, make stuff get exported
|
||||
#define _IMPL_NS_COM 1
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mac build settings for the debug string library
|
||||
*/
|
||||
|
||||
#include "MacPrefix_debug.h"
|
||||
|
||||
// while we're still a part of xpcom, make stuff get exported
|
||||
#define _IMPL_NS_COM 1
|
||||
Binary file not shown.
@@ -1,34 +0,0 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
#
|
||||
|
||||
DEPTH=..
|
||||
|
||||
DIRS= public \
|
||||
src \
|
||||
obsolete \
|
||||
#!if !defined(DISABLE_TESTS)
|
||||
# tests \
|
||||
#!endif
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
@@ -1,26 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Scott Collins <scc@mozilla.org> (original author)
|
||||
#
|
||||
|
||||
|
||||
nsStr.h
|
||||
nsString.h
|
||||
nsString2.h
|
||||
@@ -1,58 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = string
|
||||
LIBRARY_NAME = string_obsolete_s
|
||||
|
||||
REQUIRES = unicharutil xpcom
|
||||
|
||||
CPPSRCS = \
|
||||
nsStr.cpp \
|
||||
nsString.cpp \
|
||||
nsString2.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
nsStr.h \
|
||||
nsString.h \
|
||||
nsString2.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
# Force use of PIC
|
||||
FORCE_USE_PIC = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_COM -D_IMPL_NS_BASE
|
||||
@@ -1,35 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
- The contents of this file are subject to the Mozilla Public
|
||||
- License Version 1.1 (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/MPL/
|
||||
-
|
||||
- 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.
|
||||
-
|
||||
- The Initial Developer of the Original Code is Netscape
|
||||
- Communications. Portions created by Netscape Communications are
|
||||
- Copyright (C) 2001 by Netscape Communications. All
|
||||
- Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Scott Collins <scc@mozilla.org> (original author)
|
||||
-->
|
||||
<body>
|
||||
<h1><span class="LXRSHORTDESC">original string implementations soon to be replaced (the names you are using will still be good)</span></h1>
|
||||
<p>
|
||||
<span class="LXRLONGDESC">These are the original string implementations by rickg and others.
|
||||
Most of the code here will be made obsolete by the new shared-buffer string (see bug <a href="http://bugzilla.mozilla.org/show_bug.cgi?id=53065">#53065</a>).
|
||||
For the most part, this change is intended to be transparent to clients.
|
||||
The type names you are using for strings now, e.g., nsString, nsAutoString, nsXPIDLString, will still be good,
|
||||
they will just refer to better, but compatible, implementations.
|
||||
If you're interested in learning how strings work, you probably want to start with
|
||||
<a href="http://lxr.mozilla.org/seamonkey/source/string/public/nsAReadableString.h">nsAReadableString</a>.</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,994 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
|
||||
/* bufferRoutines.h --- rickg's original string manipulation underpinnings;
|
||||
this code will be made obsolete by the new shared-buffer string (see bug #53065)
|
||||
*/
|
||||
|
||||
#ifndef _BUFFERROUTINES_H
|
||||
#define _BUFFERROUTINES_H
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************************
|
||||
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.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
#ifndef XPCOM_STANDALONE
|
||||
#if !defined(RICKG_TESTBED) && !defined(STANDALONE_STRING_TESTS)
|
||||
#include "nsUnicharUtilCIID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsICaseConversion.h"
|
||||
#endif
|
||||
#endif /* XPCOM_STANDALONE */
|
||||
|
||||
#define KSHIFTLEFT (0)
|
||||
#define KSHIFTRIGHT (1)
|
||||
|
||||
// uncomment the following line to caught nsString char* casting problem
|
||||
//#define DEBUG_ILLEGAL_CAST_UP
|
||||
//#define DEBUG_ILLEGAL_CAST_DOWN
|
||||
|
||||
#if defined(DEBUG_ILLEGAL_CAST_UP) || defined(DEBUG_ILLEGAL_CAST_DOWN)
|
||||
|
||||
static PRBool track_illegal = PR_TRUE;
|
||||
static PRBool track_latin1 = PR_TRUE;
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#include "nsTraceRefcnt.h"
|
||||
class CTraceFile {
|
||||
public:
|
||||
CTraceFile() {
|
||||
mFile = fopen("nsStringTrace.txt" , "a+");
|
||||
}
|
||||
~CTraceFile() {
|
||||
fflush(mFile);
|
||||
fclose(mFile);
|
||||
}
|
||||
void ReportCastUp(const char* data, const char* msg)
|
||||
{
|
||||
if(mFile) {
|
||||
fprintf(mFile, "ERRORTEXT= %s\n", msg);
|
||||
fprintf(mFile, "BEGINDATA\n");
|
||||
const char* s=data;
|
||||
while(*s) {
|
||||
if(*s & 0x80) {
|
||||
fprintf(mFile, "[%2X]", (char)*s);
|
||||
} else {
|
||||
fprintf(mFile, "%c", *s);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
fprintf(mFile, "\n");
|
||||
fprintf(mFile, "ENDDATA\n");
|
||||
fprintf(mFile, "BEGINSTACK\n");
|
||||
nsTraceRefcnt::WalkTheStack(mFile);
|
||||
fprintf(mFile, "\n");
|
||||
fprintf(mFile, "ENDSTACK\n");
|
||||
fflush(mFile);
|
||||
}
|
||||
}
|
||||
void ReportCastDown(const PRUnichar* data, const char* msg)
|
||||
{
|
||||
if(mFile) {
|
||||
fprintf(mFile, "ERRORTEXT=%s\n", msg);
|
||||
fprintf(mFile, "BEGINDATA\n");
|
||||
const PRUnichar* s=data;
|
||||
while(*s) {
|
||||
if(*s & 0xFF80) {
|
||||
fprintf(mFile, "\\u%X", *s);
|
||||
} else {
|
||||
fprintf(mFile, "%c", *s);
|
||||
}
|
||||
s++;
|
||||
}
|
||||
fprintf(mFile, "\n");
|
||||
fprintf(mFile, "ENDDATA\n");
|
||||
fprintf(mFile, "BEGINSTACK\n");
|
||||
nsTraceRefcnt::WalkTheStack(mFile);
|
||||
fprintf(mFile, "\n");
|
||||
fprintf(mFile, "ENDSTACK\n");
|
||||
fflush(mFile);
|
||||
}
|
||||
}
|
||||
private:
|
||||
FILE* mFile;
|
||||
};
|
||||
static CTraceFile gTrace;
|
||||
#define TRACE_ILLEGAL_CAST_UP(c, s, m) if(!(c)) gTrace.ReportCastUp(s,m);
|
||||
#define TRACE_ILLEGAL_CAST_DOWN(c, s, m) if(!(c)) gTrace.ReportCastDown(s,m);
|
||||
|
||||
#else // XP_UNIX
|
||||
|
||||
#define TRACE_ILLEGAL_CAST_UP(c, s, m) NS_ASSERTION((c), (m))
|
||||
#define TRACE_ILLEGAL_CAST_DOWN(c, s, m) NS_ASSERTION((c), (m))
|
||||
|
||||
#endif //XP_UNIX
|
||||
|
||||
#endif
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
|
||||
#ifdef DEBUG_ILLEGAL_CAST_UP
|
||||
PRBool illegal= PR_FALSE;
|
||||
#endif
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<last) {
|
||||
*to=(PRUnichar)(*first);
|
||||
#ifdef DEBUG_ILLEGAL_CAST_UP
|
||||
if(track_illegal && track_latin1 && ((*to)& 0x80))
|
||||
illegal= PR_TRUE;
|
||||
#endif
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
#ifdef DEBUG_ILLEGAL_CAST_UP
|
||||
TRACE_ILLEGAL_CAST_UP((!illegal), aSource, "illegal cast up in CopyChars1To2");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
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;
|
||||
|
||||
#ifdef DEBUG_ILLEGAL_CAST_DOWN
|
||||
PRBool illegal= PR_FALSE;
|
||||
#endif
|
||||
//now loop over characters, shifting them left...
|
||||
while(first<last) {
|
||||
if(*first<256)
|
||||
*to=(char)*first;
|
||||
else {
|
||||
*to='.';
|
||||
NS_ASSERTION( (*first < 256), "data in U+0100-U+FFFF will be lost");
|
||||
}
|
||||
#ifdef DEBUG_ILLEGAL_CAST_DOWN
|
||||
if(track_illegal) {
|
||||
if(track_latin1) {
|
||||
if(*first & 0xFF80)
|
||||
illegal = PR_TRUE;
|
||||
} else {
|
||||
if(*first & 0xFF00)
|
||||
illegal = PR_TRUE;
|
||||
} // track_latin1
|
||||
} // track_illegal
|
||||
#endif
|
||||
to++;
|
||||
first++;
|
||||
}
|
||||
#ifdef DEBUG_ILLEGAL_CAST_DOWN
|
||||
TRACE_ILLEGAL_CAST_DOWN((!illegal), theSource, "illegal cast down in CopyChars2To1");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
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 02/17/00
|
||||
* @param aDest is the buffer to be searched
|
||||
* @param aDestLength 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
|
||||
* @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 FindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount) {
|
||||
|
||||
if(anOffset<0)
|
||||
anOffset=0;
|
||||
|
||||
if(aCount<0)
|
||||
aCount = (PRInt32)aDestLength;
|
||||
|
||||
if((aChar<256) && (0<aDestLength) && ((PRUint32)anOffset<aDestLength)) {
|
||||
|
||||
//We'll only search if the given aChar is within the normal ascii a range,
|
||||
//(Since this string is definitely within the ascii range).
|
||||
|
||||
if(0<aCount) {
|
||||
|
||||
const char* left= aDest+anOffset;
|
||||
const char* last= left+aCount;
|
||||
const char* max = aDest+aDestLength;
|
||||
const char* end = (last<max) ? last : max;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
|
||||
char theChar=(char)nsCRT::ToUpper(aChar);
|
||||
while(left<end){
|
||||
if(nsCRT::ToUpper(*left)==theChar)
|
||||
return left-aDest;
|
||||
++left;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
PRInt32 theMax = end-left;
|
||||
if(0<theMax) {
|
||||
unsigned char theChar = (unsigned char) aChar;
|
||||
const char* result=(const char*)memchr(left, (int)theChar, theMax);
|
||||
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 aDestLength 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
|
||||
* @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 FindChar2(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount) {
|
||||
|
||||
if(anOffset<0)
|
||||
anOffset=0;
|
||||
|
||||
if(aCount<0)
|
||||
aCount = (PRInt32)aDestLength;
|
||||
|
||||
if((0<aDestLength) && ((PRUint32)anOffset<aDestLength)) {
|
||||
|
||||
if(0<aCount) {
|
||||
|
||||
const PRUnichar* root = (PRUnichar*)aDest;
|
||||
const PRUnichar* left = root+anOffset;
|
||||
const PRUnichar* last = left+aCount;
|
||||
const PRUnichar* max = root+aDestLength;
|
||||
const PRUnichar* end = (last<max) ? last : max;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
PRUnichar theChar=nsCRT::ToUpper(aChar);
|
||||
while(left<end){
|
||||
if(nsCRT::ToUpper(*left)==theChar)
|
||||
return left-root;
|
||||
++left;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(left<end){
|
||||
if(*left==aChar)
|
||||
return (left-root);
|
||||
++left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This methods cans the given buffer (in reverse) for the given char
|
||||
*
|
||||
* @update gess 02/17/00
|
||||
* @param aDest is the buffer to be searched
|
||||
* @param aDestLength 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
|
||||
* @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
|
||||
inline PRInt32 RFindChar1(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount) {
|
||||
|
||||
if(anOffset<0)
|
||||
anOffset=(PRInt32)aDestLength-1;
|
||||
|
||||
if(aCount<0)
|
||||
aCount = PRInt32(aDestLength);
|
||||
|
||||
if((aChar<256) && (0<aDestLength) && ((PRUint32)anOffset<aDestLength)) {
|
||||
|
||||
//We'll only search if the given aChar is within the normal ascii a range,
|
||||
//(Since this string is definitely within the ascii range).
|
||||
|
||||
if(0<aCount) {
|
||||
|
||||
const char* rightmost = aDest+anOffset;
|
||||
const char* min = rightmost-aCount+1;
|
||||
const char* leftmost = (min<aDest) ? aDest: min;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
|
||||
char theChar=(char)nsCRT::ToUpper(aChar);
|
||||
while(leftmost<rightmost){
|
||||
if(nsCRT::ToUpper(*rightmost)==theChar)
|
||||
return rightmost-aDest;
|
||||
--rightmost;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
char theChar=(char)aChar;
|
||||
while(leftmost<=rightmost){
|
||||
if((*rightmost)==theChar)
|
||||
return rightmost-aDest;
|
||||
--rightmost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 aDestLength 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
|
||||
* @param aCount tells us how many characters to iterate through (which may be different than aLength); -1 means use full length.
|
||||
* @return index of pos if found, else -1 (kNotFound)
|
||||
*/
|
||||
inline PRInt32 RFindChar2(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount) {
|
||||
|
||||
if(anOffset<0)
|
||||
anOffset=(PRInt32)aDestLength-1;
|
||||
|
||||
if(aCount<0)
|
||||
aCount = PRInt32(aDestLength);
|
||||
|
||||
if((0<aDestLength) && ((PRUint32)anOffset<aDestLength)) {
|
||||
|
||||
if(0<aCount) {
|
||||
|
||||
const PRUnichar* root = (PRUnichar*)aDest;
|
||||
const PRUnichar* rightmost = root+anOffset;
|
||||
const PRUnichar* min = rightmost-aCount+1;
|
||||
const PRUnichar* leftmost = (min<root) ? root: min;
|
||||
|
||||
if(aIgnoreCase) {
|
||||
|
||||
PRUnichar theChar=nsCRT::ToUpper(aChar);
|
||||
while(leftmost<rightmost){
|
||||
if(nsCRT::ToUpper(*rightmost)==theChar)
|
||||
return rightmost-root;
|
||||
--rightmost;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
while(leftmost<=rightmost){
|
||||
if((*rightmost)==aChar)
|
||||
return rightmost-root;
|
||||
--rightmost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
typedef PRInt32 (*FindChars)(const char* aDest,PRUint32 aDestLength,PRInt32 anOffset,const PRUnichar aChar,PRBool aIgnoreCase,PRInt32 aCount);
|
||||
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 Compare1To1(const char* aStr1,const char* aStr2,PRUint32 aCount,PRBool aIgnoreCase){
|
||||
PRInt32 result=0;
|
||||
if(aIgnoreCase)
|
||||
result=nsCRT::strncasecmp(aStr1,aStr2,aCount);
|
||||
else result=memcmp(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 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 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 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 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 = chartype('A' + (ch - 'a'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((ch >= 'A') && (ch <= 'Z')) {
|
||||
*cp = chartype('a' + (ch - 'A'));
|
||||
}
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef XPCOM_STANDALONE
|
||||
#if !defined(RICKG_TESTBED) && !defined(STANDALONE_STRING_TESTS)
|
||||
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 nsICaseConversion * gCaseConv = 0;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(HandleCaseConversionShutdown3, nsIShutdownListener);
|
||||
|
||||
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(){
|
||||
HandleCaseConversionShutdown3* listener =
|
||||
new HandleCaseConversionShutdown3();
|
||||
if(listener){
|
||||
nsServiceManager::GetService(kUnicharUtilCID, NS_GET_IID(nsICaseConversion),(nsISupports**) &gCaseConv, listener);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif /* XPCOM_STANDALONE */
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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);
|
||||
PRInt32 ConvertCase2(char* aString,PRUint32 aCount,PRBool aToUpper){
|
||||
PRUnichar* cp = (PRUnichar*)aString;
|
||||
PRUnichar* end = cp + aCount-1;
|
||||
PRInt32 result=0;
|
||||
|
||||
#ifndef XPCOM_STANDALONE
|
||||
#if !defined(RICKG_TESTBED) && !defined(STANDALONE_STRING_TESTS)
|
||||
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
|
||||
#endif /* XPCOM_STANDALONE */
|
||||
|
||||
|
||||
while (cp <= end) {
|
||||
PRUnichar ch = *cp;
|
||||
if(aToUpper) {
|
||||
if ((ch >= 'a') && (ch <= 'z')) {
|
||||
*cp = PRUnichar('A' + (ch - 'a'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((ch >= 'A') && (ch <= 'Z')) {
|
||||
*cp = PRUnichar('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 rickg 03.23.2000
|
||||
* @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);
|
||||
PRInt32 CompressChars1(char* aString,PRUint32 aLength,const char* aSet){
|
||||
|
||||
char* from = aString;
|
||||
char* end = aString + aLength;
|
||||
char* 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) {
|
||||
char theChar = *from++;
|
||||
|
||||
*to++=theChar; //always copy this char...
|
||||
|
||||
if((kNotFound!=FindChar1(aSet,aSetLen,0,theChar,PR_FALSE,aSetLen))){
|
||||
while (from < end) {
|
||||
theChar = *from++;
|
||||
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE,aSetLen)){
|
||||
*to++ = theChar;
|
||||
break;
|
||||
}
|
||||
} //while
|
||||
} //if
|
||||
} //if
|
||||
*to = 0;
|
||||
}
|
||||
return to - aString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This method compresses duplicate runs of a given char from the given buffer
|
||||
*
|
||||
* @update rickg 03.23.2000
|
||||
* @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);
|
||||
PRInt32 CompressChars2(char* aString,PRUint32 aLength,const char* aSet){
|
||||
|
||||
PRUnichar* from = (PRUnichar*)aString;
|
||||
PRUnichar* end = from + aLength;
|
||||
PRUnichar* 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) {
|
||||
PRUnichar theChar = *from++;
|
||||
|
||||
*to++=theChar; //always copy this char...
|
||||
|
||||
if((theChar<256) && (kNotFound!=FindChar1(aSet,aSetLen,0,theChar,PR_FALSE,aSetLen))){
|
||||
while (from < end) {
|
||||
theChar = *from++;
|
||||
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE,aSetLen)){
|
||||
*to++ = theChar;
|
||||
break;
|
||||
}
|
||||
} //while
|
||||
} //if
|
||||
} //if
|
||||
*to = 0;
|
||||
}
|
||||
return to - (PRUnichar*)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);
|
||||
PRInt32 StripChars1(char* aString,PRUint32 aLength,const char* aSet){
|
||||
|
||||
char* to = aString;
|
||||
char* from = aString-1;
|
||||
char* end = aString + aLength;
|
||||
|
||||
if(aSet && aString && (0 < aLength)){
|
||||
PRUint32 aSetLen=strlen(aSet);
|
||||
while (++from < end) {
|
||||
char theChar = *from;
|
||||
if(kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE,aSetLen)){
|
||||
*to++ = theChar;
|
||||
}
|
||||
}
|
||||
*to = 0;
|
||||
}
|
||||
return to - (char*)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);
|
||||
PRInt32 StripChars2(char* aString,PRUint32 aLength,const char* aSet){
|
||||
|
||||
PRUnichar* to = (PRUnichar*)aString;
|
||||
PRUnichar* from = (PRUnichar*)aString-1;
|
||||
PRUnichar* end = to + aLength;
|
||||
|
||||
if(aSet && aString && (0 < aLength)){
|
||||
PRUint32 aSetLen=strlen(aSet);
|
||||
while (++from < end) {
|
||||
PRUnichar theChar = *from;
|
||||
//Note the test for ascii range below. If you have a real unicode char,
|
||||
//and you're searching for chars in the (given) ascii string, there's no
|
||||
//point in doing the real search since it's out of the ascii range.
|
||||
if((255<theChar) || (kNotFound==FindChar1(aSet,aSetLen,0,theChar,PR_FALSE,aSetLen))){
|
||||
*to++ = theChar;
|
||||
}
|
||||
}
|
||||
*to = 0;
|
||||
}
|
||||
return to - (PRUnichar*)aString;
|
||||
}
|
||||
|
||||
|
||||
typedef PRInt32 (*StripChars)(char* aString,PRUint32 aCount,const char* aSet);
|
||||
StripChars gStripChars[]={&StripChars1,&StripChars2};
|
||||
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
#
|
||||
|
||||
DEPTH=..\..
|
||||
|
||||
EXPORTS = \
|
||||
nsStr.h \
|
||||
nsString.h \
|
||||
nsString2.h \
|
||||
$(NULL)
|
||||
|
||||
LIBRARY_NAME=string_obsolete_s
|
||||
LIBRARY=.\$(OBJDIR)\$(LIBRARY_NAME).lib
|
||||
|
||||
LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsStr.obj \
|
||||
.\$(OBJDIR)\nsString.obj \
|
||||
.\$(OBJDIR)\nsString2.obj \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
@@ -1,921 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rick Gessner <rickg@netscape.com> (original author)
|
||||
* Scott Collins <scc@mozilla.org>
|
||||
*/
|
||||
|
||||
#include "nsStr.h"
|
||||
#include "bufferRoutines.h"
|
||||
#include <stdio.h> //only used for printf
|
||||
#include "nsCRT.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
/******************************************************************************************
|
||||
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.
|
||||
|
||||
*******************************************************************************************/
|
||||
|
||||
//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};
|
||||
static PRBool gStringAcquiredMemory = PR_TRUE;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#ifndef NS_USE_OLD_STRING_ALLOCATION_STRATEGY
|
||||
// the new strategy is, allocate exact size, double on grows
|
||||
if ( aDest.mCapacity ) {
|
||||
PRUint32 newCapacity = aDest.mCapacity;
|
||||
while ( newCapacity < aNewLength )
|
||||
newCapacity <<= 1;
|
||||
aNewLength = newCapacity;
|
||||
}
|
||||
#endif
|
||||
|
||||
result=EnsureCapacity(theTempStr,aNewLength);
|
||||
if(result) {
|
||||
if(aDest.mLength) {
|
||||
StrAppend(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::StrAssign(nsStr& aDest,const nsStr& aSource,PRUint32 anOffset,PRInt32 aCount){
|
||||
if(&aDest!=&aSource){
|
||||
StrTruncate(aDest,0);
|
||||
StrAppend(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::StrAppend(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);
|
||||
NSSTR_SEEN(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::StrInsert( 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) {
|
||||
StrAppend(theTempStr,aDest,0,aDestOffset); //first copy leftmost data...
|
||||
}
|
||||
|
||||
StrAppend(theTempStr,aSource,0,aSource.mLength); //next copy inserted (new) data
|
||||
|
||||
PRUint32 theRemains=aDest.mLength-aDestOffset;
|
||||
if(theRemains) {
|
||||
StrAppend(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);
|
||||
NSSTR_SEEN(aDest);
|
||||
}//if
|
||||
//else nothing to do!
|
||||
}
|
||||
else StrAppend(aDest,aSource,0,aCount);
|
||||
}
|
||||
else StrAppend(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);
|
||||
NSSTR_SEEN(aDest);
|
||||
}
|
||||
else StrTruncate(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::StrTruncate(nsStr& aDest,PRUint32 aDestOffset){
|
||||
if(aDest.mCapacity && aDestOffset<=aDest.mCapacity){
|
||||
aDest.mLength=aDestOffset;
|
||||
AddNullTerminator(aDest);
|
||||
NSSTR_SEEN(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removes characters from the given set from this string.
|
||||
* NOTE: aSet is a char*, and it's length is computed using strlen, which assumes null termination.
|
||||
*
|
||||
* @update gess 11/7/99
|
||||
* @param aDest
|
||||
* @param aSet
|
||||
* @param aEliminateLeading
|
||||
* @param aEliminateTrailing
|
||||
* @return nothing
|
||||
*/
|
||||
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,theSetLen);
|
||||
if(kNotFound==thePos)
|
||||
break;
|
||||
}
|
||||
if(0<theIndex) {
|
||||
if(theIndex<theMax) {
|
||||
Delete(aDest,0,theIndex);
|
||||
}
|
||||
else StrTruncate(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,theSetLen);
|
||||
if(kNotFound<thePos)
|
||||
theNewLen=theIndex;
|
||||
else break;
|
||||
}
|
||||
if(theNewLen<theMax) {
|
||||
StrTruncate(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;
|
||||
NSSTR_SEEN(aDest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
NSSTR_SEEN(aDest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
Searching methods...
|
||||
**************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest for a given substring
|
||||
*
|
||||
* @update gess 2/04/00: added aCount argument to restrict search
|
||||
* @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
|
||||
* @param aCount tells us how many iterations to make from offset; -1 means the full length of the string
|
||||
* @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,PRInt32 aCount) {
|
||||
PRInt32 theMaxPos = aDest.mLength-aTarget.mLength; //this is the last pos that is feasible for starting the search, with given lengths...
|
||||
|
||||
if(0<=theMaxPos) {
|
||||
|
||||
if(anOffset<0)
|
||||
anOffset=0;
|
||||
|
||||
if((0<aDest.mLength) && (anOffset<=theMaxPos) && (aTarget.mLength)) {
|
||||
|
||||
if(aCount<0)
|
||||
aCount = MaxInt(theMaxPos,1);
|
||||
|
||||
if(0<aCount) {
|
||||
|
||||
PRInt32 aDelta= (aDest.mCharSize == eOneByte) ? 1 : 2;
|
||||
const char* root = aDest.mStr;
|
||||
const char* left = root+(anOffset*aDelta);
|
||||
const char* last = left+((aCount)*aDelta);
|
||||
const char* max = root+(theMaxPos*aDelta);
|
||||
const char* right = (last<max) ? last : max;
|
||||
|
||||
while(left<=right){
|
||||
PRInt32 cmp=(*gCompare[aDest.mCharSize][aTarget.mCharSize])(left,aTarget.mStr,aTarget.mLength,aIgnoreCase);
|
||||
if(0==cmp) {
|
||||
return (left-root)/aDelta;
|
||||
}
|
||||
left+=aDelta;
|
||||
} //while
|
||||
|
||||
} //if
|
||||
}
|
||||
} //if
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest for a given character
|
||||
*
|
||||
* @update gess 2/04/00: added aCount argument to restrict search
|
||||
* @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
|
||||
* @param aCount tell us how many chars to search from offset
|
||||
* @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 aCount) {
|
||||
return gFindChars[aDest.mCharSize](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase,aCount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,aSet.mLength);
|
||||
if(kNotFound!=thePos)
|
||||
return index;
|
||||
} //while
|
||||
}
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Reverse Searching methods...
|
||||
**************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest (in reverse) for a given substring
|
||||
*
|
||||
* @update gess 2/18/00
|
||||
* @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)
|
||||
* @param aCount tell us how many iterations to perform from offset
|
||||
* @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,PRInt32 aCount) {
|
||||
if(anOffset<0)
|
||||
anOffset=(PRInt32)aDest.mLength-1;
|
||||
|
||||
if(aCount<0)
|
||||
aCount = aDest.mLength;
|
||||
|
||||
if((0<aDest.mLength) && ((PRUint32)anOffset<aDest.mLength) && (aTarget.mLength)) {
|
||||
|
||||
if(0<aCount) {
|
||||
|
||||
PRInt32 aDelta = (aDest.mCharSize == eOneByte) ? 1 : 2;
|
||||
const char* root = aDest.mStr;
|
||||
const char* destLast = root+(aDest.mLength*aDelta); //pts to last char in aDest (likely null)
|
||||
|
||||
const char* rightmost = root+(anOffset*aDelta);
|
||||
const char* min = rightmost-((aCount-1)*aDelta);
|
||||
|
||||
const char* leftmost = (min<root) ? root: min;
|
||||
|
||||
while(leftmost<=rightmost) {
|
||||
//don't forget to divide by delta in next text (bug found by rhp)...
|
||||
if(aTarget.mLength<=PRUint32((destLast-rightmost)/aDelta)) {
|
||||
PRInt32 result=(*gCompare[aDest.mCharSize][aTarget.mCharSize])(rightmost,aTarget.mStr,aTarget.mLength,aIgnoreCase);
|
||||
|
||||
if(0==result) {
|
||||
return (rightmost-root)/aDelta;
|
||||
}
|
||||
} //if
|
||||
rightmost-=aDelta;
|
||||
} //while
|
||||
}
|
||||
}
|
||||
|
||||
return kNotFound;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This searches aDest (in reverse) for a given character
|
||||
*
|
||||
* @update gess 2/04/00
|
||||
* @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; -1 means start at very end (mLength)
|
||||
* @param aCount tell us how many iterations to perform from offset; -1 means use full length.
|
||||
* @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 aCount) {
|
||||
return gRFindChars[aDest.mCharSize](aDest.mStr,aDest.mLength,anOffset,aChar,aIgnoreCase,aCount);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,aSet.mLength);
|
||||
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::StrCompare(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 theCount = (aCount<0) ? minlen: MinInt(aCount,minlen);
|
||||
result=(*gCompare[aDest.mCharSize][aSource.mCharSize])(aDest.mStr,aSource.mStr,theCount,aIgnoreCase);
|
||||
|
||||
if (0==result) {
|
||||
if(-1==aCount) {
|
||||
|
||||
//Since the caller didn't give us a length to test, and minlen characters matched,
|
||||
//we have to assume that the longer string is greater.
|
||||
|
||||
if (aDest.mLength != aSource.mLength) {
|
||||
//we think they match, but we've only compared minlen characters.
|
||||
//if the string lengths are different, then they don't really match.
|
||||
result = (aDest.mLength<aSource.mLength) ? -1 : 1;
|
||||
}
|
||||
} //if
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the contents of dest at offset with contents of aSource
|
||||
*
|
||||
* @param aDest is the first str to compare
|
||||
* @param aSource is the second str to compare
|
||||
* @param aDestOffset is the offset within aDest where source should be copied
|
||||
* @return error code
|
||||
*/
|
||||
void nsStr::Overwrite(nsStr& aDest,const nsStr& aSource,PRInt32 aDestOffset) {
|
||||
if(aDest.mLength && aSource.mLength) {
|
||||
if((aDest.mLength-aDestOffset)>=aSource.mLength) {
|
||||
//if you're here, then both dest and source have valid lengths
|
||||
//and there's enough room in dest (at offset) to contain source.
|
||||
(*gCopyChars[aSource.mCharSize][aDest.mCharSize])(aDest.mStr,aDestOffset,aSource.mStr,0,aSource.mLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
PRBool nsStr::Alloc(nsStr& aDest,PRUint32 aCount) {
|
||||
|
||||
static int mAllocCount=0;
|
||||
mAllocCount++;
|
||||
|
||||
#ifdef NS_USE_OLD_STRING_ALLOCATION_STRATEGY
|
||||
//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*)nsMemory::Alloc(theSize);
|
||||
#else
|
||||
// the new strategy is, allocate exact size, double on grows
|
||||
aDest.mCapacity = aCount;
|
||||
aDest.mStr = (char*)nsMemory::Alloc((aCount+1)<<aDest.mCharSize);
|
||||
#endif
|
||||
|
||||
if(aDest.mStr) {
|
||||
aDest.mOwnsBuffer=1;
|
||||
gStringAcquiredMemory=PR_TRUE;
|
||||
}
|
||||
else gStringAcquiredMemory=PR_FALSE;
|
||||
return gStringAcquiredMemory;
|
||||
}
|
||||
|
||||
PRBool nsStr::Free(nsStr& aDest){
|
||||
if(aDest.mStr){
|
||||
if(aDest.mOwnsBuffer){
|
||||
nsMemory::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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve last memory error
|
||||
*
|
||||
* @update gess 10/11/99
|
||||
* @return memory error (usually returns PR_TRUE)
|
||||
*/
|
||||
PRBool nsStr::DidAcquireMemory(void) {
|
||||
return gStringAcquiredMemory;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
PRUint32
|
||||
nsStr::HashCode(const nsStr& aDest)
|
||||
{
|
||||
if (aDest.mCharSize == eTwoByte)
|
||||
return nsCRT::HashCode(aDest.mUStr);
|
||||
else
|
||||
return nsCRT::HashCode(aDest.mStr);
|
||||
}
|
||||
|
||||
#ifdef NS_STR_STATS
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef XP_MAC
|
||||
#define isascii(c) ((unsigned)(c) < 0x80)
|
||||
#endif
|
||||
|
||||
void
|
||||
nsStr::Print(const nsStr& aDest, FILE* out, PRBool truncate)
|
||||
{
|
||||
PRInt32 printLen = (PRInt32)aDest.mLength;
|
||||
|
||||
if (aDest.mCharSize == eOneByte) {
|
||||
const char* chars = aDest.mStr;
|
||||
while (printLen-- && (!truncate || *chars != '\n')) {
|
||||
fputc(*chars++, out);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const PRUnichar* chars = aDest.mUStr;
|
||||
while (printLen-- && (!truncate || *chars != '\n')) {
|
||||
if (isascii(*chars))
|
||||
fputc((char)(*chars++), out);
|
||||
else
|
||||
fputc('-', out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// String Usage Statistics Routines
|
||||
|
||||
static PLHashTable* gStringInfo = nsnull;
|
||||
PRLock* gStringInfoLock = nsnull;
|
||||
PRBool gNoStringInfo = PR_FALSE;
|
||||
|
||||
nsStringInfo::nsStringInfo(nsStr& str)
|
||||
: mCount(0)
|
||||
{
|
||||
nsStr::Initialize(mStr, str.mCharSize);
|
||||
nsStr::StrAssign(mStr, str, 0, -1);
|
||||
// nsStr::Print(mStr, stdout);
|
||||
// fputc('\n', stdout);
|
||||
}
|
||||
|
||||
PR_EXTERN(PRHashNumber)
|
||||
nsStr_Hash(const void* key)
|
||||
{
|
||||
nsStr* str = (nsStr*)key;
|
||||
return nsStr::HashCode(*str);
|
||||
}
|
||||
|
||||
PR_EXTERN(PRIntn)
|
||||
nsStr_Compare(const void *v1, const void *v2)
|
||||
{
|
||||
nsStr* str1 = (nsStr*)v1;
|
||||
nsStr* str2 = (nsStr*)v2;
|
||||
return nsStr::StrCompare(*str1, *str2, -1, PR_FALSE) == 0;
|
||||
}
|
||||
|
||||
nsStringInfo*
|
||||
nsStringInfo::GetInfo(nsStr& str)
|
||||
{
|
||||
if (gStringInfo == nsnull) {
|
||||
gStringInfo = PL_NewHashTable(1024,
|
||||
nsStr_Hash,
|
||||
nsStr_Compare,
|
||||
PL_CompareValues,
|
||||
NULL, NULL);
|
||||
gStringInfoLock = PR_NewLock();
|
||||
}
|
||||
PR_Lock(gStringInfoLock);
|
||||
nsStringInfo* info =
|
||||
(nsStringInfo*)PL_HashTableLookup(gStringInfo, &str);
|
||||
if (info == NULL) {
|
||||
gNoStringInfo = PR_TRUE;
|
||||
info = new nsStringInfo(str);
|
||||
if (info) {
|
||||
PLHashEntry* e = PL_HashTableAdd(gStringInfo, &info->mStr, info);
|
||||
if (e == NULL) {
|
||||
delete info;
|
||||
info = NULL;
|
||||
}
|
||||
}
|
||||
gNoStringInfo = PR_FALSE;
|
||||
}
|
||||
PR_Unlock(gStringInfoLock);
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
nsStringInfo::Seen(nsStr& str)
|
||||
{
|
||||
if (!gNoStringInfo) {
|
||||
nsStringInfo* info = GetInfo(str);
|
||||
info->mCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsStringInfo::Report(FILE* out)
|
||||
{
|
||||
if (gStringInfo) {
|
||||
fprintf(out, "\n== String Stats\n");
|
||||
PL_HashTableEnumerateEntries(gStringInfo, nsStringInfo::ReportEntry, out);
|
||||
}
|
||||
}
|
||||
|
||||
PRIntn
|
||||
nsStringInfo::ReportEntry(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsStringInfo* entry = (nsStringInfo*)he->value;
|
||||
FILE* out = (FILE*)arg;
|
||||
|
||||
fprintf(out, "%d ==> (%d) ", entry->mCount, entry->mStr.mLength);
|
||||
nsStr::Print(entry->mStr, out, PR_TRUE);
|
||||
fputc('\n', out);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
#endif // NS_STR_STATS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1,532 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rick Gessner <rickg@netscape.com> (original author)
|
||||
* Scott Collins <scc@mozilla.org>
|
||||
*/
|
||||
|
||||
/* nsStr.h --- the underlying buffer for rickg's original string implementations;
|
||||
these classes will be replaced by the new shared-buffer string (see bug #53065)
|
||||
*/
|
||||
|
||||
#ifndef _nsStr
|
||||
#define _nsStr
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
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. However,
|
||||
since it maintains a length byte, you can store NULL's inside
|
||||
the string. Just be careful passing such buffers to 3rd party
|
||||
API's that assume that NULL always terminate the buffer.
|
||||
|
||||
2. nsCStrings can be upsampled into nsString without data loss
|
||||
|
||||
3. Char searching is faster than string searching. Use char interfaces
|
||||
if your needs will allow it.
|
||||
|
||||
4. It's easy to use the stack for nsAutostring buffer storage (fast too!).
|
||||
See the CBufDescriptor class in this file.
|
||||
|
||||
5. If you don't provide the optional count argument to Append() and Insert(),
|
||||
the method will assume that the given buffer is terminated by the first
|
||||
NULL it encounters.
|
||||
|
||||
6. Downsampling from nsString to nsCString can be lossy -- avoid it if possible!
|
||||
|
||||
7. Calls to ToNewCString() and ToNewUnicode() should be matched with calls to nsMemory::Free().
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
|
||||
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 nsMemory
|
||||
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.
|
||||
|
||||
|
||||
--- FAQ ---
|
||||
|
||||
Q. When should I use nsCString instead of nsString?
|
||||
|
||||
A. You should really try to stick with nsString, so that we stay as unicode
|
||||
compliant as possible. But there are cases where an interface you use requires
|
||||
a char*. In such cases, it's fair to use nsCString.
|
||||
|
||||
Q. I know that my string is going to be a certain size. Can I pre-size my nsString?
|
||||
|
||||
A. Yup, here's how:
|
||||
|
||||
{
|
||||
nsString mBuffer;
|
||||
mBuffer.SetCapacity(aReasonableSize);
|
||||
}
|
||||
|
||||
Q. Should nsAutoString or nsCAutoString ever live on the heap?
|
||||
|
||||
A. That would be counterproductive. The point of nsAutoStrings is to preallocate your
|
||||
buffers, and to auto-destroy the string when it goes out of scope.
|
||||
|
||||
Q. I already have a char*. Can I use the nsString functionality on that buffer?
|
||||
|
||||
A. Yes you can -- by using an intermediate class called CBufDescriptor.
|
||||
The CBufDescriptor class is used to tell nsString about an external buffer (heap or stack) to use
|
||||
instead of it's own internal buffers. Here's an example:
|
||||
|
||||
{
|
||||
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.
|
||||
|
||||
|
||||
Q. What is the simplest way to get from a char* to PRUnichar*?
|
||||
|
||||
A. The simplest way is by construction (or assignment):
|
||||
|
||||
{
|
||||
char* theBuf = "hello there";
|
||||
nsAutoString foo(theBuf);
|
||||
}
|
||||
|
||||
If you don't want the char* to be copied into the nsAutoString, the use a
|
||||
CBufDescriptor instead.
|
||||
|
||||
|
||||
**********************************************************************************/
|
||||
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsMemory.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "plhash.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------
|
||||
|
||||
enum eCharSize {eOneByte=0,eTwoByte=1};
|
||||
#define kDefaultCharSize eTwoByte
|
||||
#define kRadix10 (10)
|
||||
#define kRadix16 (16)
|
||||
#define kAutoDetect (100)
|
||||
#define kRadixUnknown (kAutoDetect+1)
|
||||
#define IGNORE_CASE (PR_TRUE)
|
||||
|
||||
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 StrAppend(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 StrAssign(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 StrInsert( 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 StrTruncate(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 StrCompare(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,PRInt32 aCount);
|
||||
static PRInt32 FindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset,PRInt32 aCount);
|
||||
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,PRInt32 aCount);
|
||||
static PRInt32 RFindChar(const nsStr& aDest,PRUnichar aChar, PRBool aIgnoreCase,PRInt32 anOffset,PRInt32 aCount);
|
||||
static PRInt32 RFindCharInSet(const nsStr& aDest,const nsStr& aSet,PRBool aIgnoreCase,PRInt32 anOffset);
|
||||
|
||||
static void Overwrite(nsStr& aDest,const nsStr& aSource,PRInt32 anOffset);
|
||||
|
||||
static PRBool DidAcquireMemory(void);
|
||||
|
||||
/**
|
||||
* Returns a hash code for the string for use in a PLHashTable.
|
||||
*/
|
||||
static PRUint32 HashCode(const nsStr& aDest);
|
||||
|
||||
#ifdef NS_STR_STATS
|
||||
/**
|
||||
* Prints an nsStr. If truncate is true, the string is only printed up to
|
||||
* the first newline. (Note: The current implementation doesn't handle
|
||||
* non-ascii unicode characters.)
|
||||
*/
|
||||
static void Print(const nsStr& aDest, FILE* out, PRBool truncate = PR_FALSE);
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated: don't use |Recycle|, just call |nsMemory::Free| directly
|
||||
*
|
||||
* Return the given buffer to the heap manager. Calls allocator::Free()
|
||||
* @return string length
|
||||
*/
|
||||
inline void Recycle( char* aBuffer) { nsMemory::Free(aBuffer); }
|
||||
inline void Recycle( PRUnichar* aBuffer) { nsMemory::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] : (PRUnichar)aDest.mStr[anIndex];
|
||||
}//if
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef NS_STR_STATS
|
||||
|
||||
class nsStringInfo {
|
||||
public:
|
||||
nsStringInfo(nsStr& str);
|
||||
~nsStringInfo() {}
|
||||
|
||||
static nsStringInfo* GetInfo(nsStr& str);
|
||||
|
||||
static void Seen(nsStr& str);
|
||||
|
||||
static void Report(FILE* out = stdout);
|
||||
|
||||
static PRIntn ReportEntry(PLHashEntry *he, PRIntn i, void *arg);
|
||||
|
||||
protected:
|
||||
nsStr mStr;
|
||||
PRUint32 mCount;
|
||||
};
|
||||
|
||||
#define NSSTR_SEEN(str) nsStringInfo::Seen(str)
|
||||
|
||||
#else // !NS_STR_STATS
|
||||
|
||||
#define NSSTR_SEEN(str) /* nothing */
|
||||
|
||||
#endif // !NS_STR_STATS
|
||||
|
||||
#endif // _nsStr
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,551 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rick Gessner <rickg@netscape.com> (original author)
|
||||
* Scott Collins <scc@mozilla.org>
|
||||
*/
|
||||
|
||||
/* nsString.h --- rickg's original strings of 1-byte chars, |nsCString| and |nsCAutoString|;
|
||||
these classes will be replaced by the new shared-buffer string (see bug #53065)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _nsCString_
|
||||
#define _nsCString_
|
||||
|
||||
/***********************************************************************
|
||||
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
|
||||
***********************************************************************/
|
||||
|
||||
#include "nsString2.h"
|
||||
#include "prtypes.h"
|
||||
#include "nscore.h"
|
||||
#include <stdio.h>
|
||||
#include "nsStr.h"
|
||||
#include "nsIAtom.h"
|
||||
|
||||
#include "nsAString.h"
|
||||
#include "nsXPIDLString.h"
|
||||
|
||||
/* this file will one day be _only_ a compatibility header for clients using the names
|
||||
|ns[C]String| et al ... which we probably want to support forever.
|
||||
In the mean time, people are used to getting the names |nsAReadable[C]String| and friends
|
||||
from here as well; so we must continue to include the other compatibility headers
|
||||
even though we don't use them ourself.
|
||||
*/
|
||||
|
||||
#include "nsAWritableString.h"
|
||||
// for compatibility
|
||||
|
||||
|
||||
class NS_COM nsCString :
|
||||
public nsAFlatCString,
|
||||
public nsStr {
|
||||
|
||||
protected:
|
||||
virtual const nsBufferHandle<char>* GetFlatBufferHandle() const;
|
||||
virtual const char* GetReadableFragment( nsReadableFragment<char>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char* GetWritableFragment( nsWritableFragment<char>&, nsFragmentRequest, PRUint32 );
|
||||
|
||||
public:
|
||||
virtual const char* get() const { return mStr; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
nsCString();
|
||||
|
||||
/**
|
||||
* This is our copy constructor
|
||||
* @param reference to another nsCString
|
||||
*/
|
||||
nsCString(const nsCString& aString);
|
||||
|
||||
explicit nsCString( const nsACString& );
|
||||
|
||||
explicit nsCString(const char*);
|
||||
nsCString(const char*, PRInt32);
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
*/
|
||||
virtual ~nsCString();
|
||||
|
||||
/**
|
||||
* Retrieve the length of this string
|
||||
* @return string length
|
||||
*/
|
||||
virtual PRUint32 Length() const { return 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);
|
||||
|
||||
/**
|
||||
* Sets the new length of the string.
|
||||
* @param aLength is new string length.
|
||||
* @return nada
|
||||
*/
|
||||
void SetCapacity(PRUint32 aLength);
|
||||
|
||||
/**********************************************************************
|
||||
Accessor methods...
|
||||
*********************************************************************/
|
||||
|
||||
PRBool SetCharAt(PRUnichar aChar,PRUint32 anIndex);
|
||||
|
||||
/**********************************************************************
|
||||
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
|
||||
*/
|
||||
void StripChars(const char* aSet);
|
||||
void StripChar(PRUnichar aChar,PRInt32 anOffset=0);
|
||||
void StripChar(char aChar,PRInt32 anOffset=0) { StripChar((PRUnichar) (unsigned char)aChar,anOffset); }
|
||||
|
||||
/**
|
||||
* This method strips whitespace throughout the string
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
void StripWhitespace();
|
||||
|
||||
/**
|
||||
* swaps occurence of 1 string for another
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
void ReplaceChar(PRUnichar aOldChar,PRUnichar aNewChar);
|
||||
void ReplaceChar(const char* aSet,PRUnichar aNewChar);
|
||||
|
||||
void ReplaceSubstring(const nsCString& aTarget,const nsCString& aNewValue);
|
||||
void ReplaceSubstring(const char* aTarget,const char* aNewValue);
|
||||
|
||||
/**
|
||||
* This method trims characters found in aTrimSet from
|
||||
* either end of the underlying string.
|
||||
*
|
||||
* @param aTrimSet -- contains chars to be trimmed from
|
||||
* both ends
|
||||
* @param aEliminateLeading
|
||||
* @param aEliminateTrailing
|
||||
* @param aIgnoreQuotes
|
||||
* @return this
|
||||
*/
|
||||
void Trim(const char* aSet,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE,PRBool aIgnoreQuotes=PR_FALSE);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void 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
|
||||
*/
|
||||
void CompressWhitespace( PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE);
|
||||
|
||||
/**********************************************************************
|
||||
string conversion methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* 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
|
||||
* |nsMemory::Free|.
|
||||
* @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
|
||||
* |nsMemory::Free|.
|
||||
* @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;
|
||||
|
||||
|
||||
/**
|
||||
* Perform string to int conversion.
|
||||
* @param aErrorCode will contain error if one occurs
|
||||
* @param aRadix tells us which radix to assume; kAutoDetect tells us to determine the radix for you.
|
||||
* @return int rep of string value, and possible (out) error code
|
||||
*/
|
||||
PRInt32 ToInteger(PRInt32* aErrorCode,PRUint32 aRadix=kRadix10) const;
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
String manipulation methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* assign given string to this string
|
||||
* @param aStr: buffer to be assigned to this
|
||||
* @param aCount is the length of the given str (or -1) if you want me to determine its length
|
||||
* NOTE: IFF you pass -1 as aCount, then your buffer must be null terminated.
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
|
||||
nsCString& operator=( const nsCString& aString ) { Assign(aString); return *this; }
|
||||
nsCString& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; }
|
||||
//nsCString& operator=( const nsPromiseReadable<char>& aReadable ) { Assign(aReadable); return *this; }
|
||||
nsCString& operator=( const char* aPtr ) { Assign(aPtr); return *this; }
|
||||
nsCString& operator=( char aChar ) { Assign(aChar); return *this; }
|
||||
|
||||
void AssignWithConversion(const PRUnichar*,PRInt32=-1);
|
||||
void AssignWithConversion( const nsString& aString );
|
||||
void AssignWithConversion( const nsAString& aString );
|
||||
void AssignWithConversion(PRUnichar);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* NOTE: IFF you pass -1 as aCount, then your buffer must be null terminated.
|
||||
*
|
||||
* @return number of chars copied
|
||||
*/
|
||||
|
||||
void AppendWithConversion(const nsString&, PRInt32=-1);
|
||||
void AppendWithConversion(PRUnichar aChar);
|
||||
void AppendWithConversion( const nsAString& aString );
|
||||
void AppendWithConversion(const PRUnichar*, PRInt32=-1);
|
||||
// Why no |AppendWithConversion(const PRUnichar*, PRInt32)|? --- now I know, because implicit construction hid the need for this routine
|
||||
void AppendInt(PRInt32 aInteger,PRInt32 aRadix=10); //radix=8,10 or 16
|
||||
void AppendFloat( double aFloat );
|
||||
|
||||
|
||||
void InsertWithConversion(PRUnichar aChar,PRUint32 anOffset);
|
||||
// Why no |InsertWithConversion(PRUnichar*)|?
|
||||
|
||||
#if 0
|
||||
virtual void do_AppendFromReadable( const nsACString& );
|
||||
virtual void do_InsertFromReadable( const nsACString&, PRUint32 );
|
||||
#endif
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Searching methods...
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param aCount tells us how many iterations to make starting at the given offset
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 Find(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-1) const;
|
||||
PRInt32 Find(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-1) const;
|
||||
PRInt32 Find(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-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
|
||||
* @param aCount tells us how many iterations to make starting at the given offset
|
||||
* @return find pos in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 FindChar(PRUnichar aChar,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-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=0) const;
|
||||
PRInt32 FindCharInSet(const PRUnichar* aString,PRInt32 anOffset=0) const;
|
||||
PRInt32 FindCharInSet(const nsStr& aString,PRInt32 anOffset=0) 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 aCount tells us how many iterations to make starting at the given offset
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 RFind(const char* aCString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-1) const;
|
||||
PRInt32 RFind(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-1) const;
|
||||
PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-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,PRInt32 aCount=-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
|
||||
*/
|
||||
PRInt32 CompareWithConversion(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRInt32 CompareWithConversion(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
|
||||
PRBool EqualsWithConversion(const nsString &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsWithConversion(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsWithConversion(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
/* a hack to make sure things that used to compile continue to compile
|
||||
even on compilers that don't have proper |explicit| support */
|
||||
inline PRBool
|
||||
EqualsWithConversion(const nsXPIDLString &aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aCount=-1) const
|
||||
{
|
||||
return EqualsWithConversion(aString.get(), aIgnoreCase, aCount);
|
||||
}
|
||||
|
||||
PRBool EqualsIgnoreCase(const char* aString,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsIgnoreCase(const PRUnichar* aString,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsIgnoreCase(const nsAFlatCString& aString) const
|
||||
{
|
||||
return EqualsIgnoreCase(aString.get(), aString.Length());
|
||||
}
|
||||
|
||||
PRBool EqualsIgnoreCase(const nsAFlatCString& aString, PRInt32 aCount) const
|
||||
{
|
||||
return EqualsIgnoreCase(aString.get(), aCount);
|
||||
}
|
||||
|
||||
void DebugDump(void) const;
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
// these signatures help clients not accidentally call the wrong thing helped by C++ automatic integral promotion
|
||||
void operator=( PRUnichar );
|
||||
void AssignWithConversion( char );
|
||||
void AssignWithConversion( const char*, PRInt32=-1 );
|
||||
void AppendWithConversion( char );
|
||||
void InsertWithConversion( char, PRUint32 );
|
||||
};
|
||||
|
||||
// NS_DEF_STRING_COMPARISON_OPERATORS(nsCString, char)
|
||||
// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCString, char)
|
||||
|
||||
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:
|
||||
|
||||
virtual ~nsCAutoString();
|
||||
|
||||
nsCAutoString();
|
||||
explicit nsCAutoString(const nsCString& );
|
||||
explicit nsCAutoString(const nsACString& aString);
|
||||
explicit nsCAutoString(const char* aString);
|
||||
nsCAutoString(const char* aString,PRInt32 aLength);
|
||||
explicit nsCAutoString(const CBufDescriptor& aBuffer);
|
||||
|
||||
nsCAutoString& operator=( const nsCAutoString& aString ) { Assign(aString); return *this; }
|
||||
private:
|
||||
void operator=( PRUnichar ); // NOT TO BE IMPLEMENTED
|
||||
public:
|
||||
nsCAutoString& operator=( const nsACString& aReadable ) { Assign(aReadable); return *this; }
|
||||
// nsCAutoString& operator=( const nsPromiseReadable<char>& aReadable ) { Assign(aReadable); return *this; }
|
||||
nsCAutoString& operator=( const char* aPtr ) { Assign(aPtr); return *this; }
|
||||
nsCAutoString& operator=( char aChar ) { Assign(aChar); return *this; }
|
||||
|
||||
/**
|
||||
* Retrieve the size of this string
|
||||
* @return string length
|
||||
*/
|
||||
virtual void SizeOf(nsISizeOfHandler* aHandler, PRUint32* aResult) const;
|
||||
|
||||
char mBuffer[kDefaultStringSize];
|
||||
};
|
||||
|
||||
// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsCAutoString, char)
|
||||
|
||||
/**
|
||||
* A helper class that converts a UCS2 string to UTF8
|
||||
*/
|
||||
class NS_COM NS_ConvertUCS2toUTF8
|
||||
: public nsCAutoString
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
NS_ConvertUCS2toUTF8( const PRUnichar* aString )
|
||||
{
|
||||
Append( aString, ~PRUint32(0) /* MAXINT */);
|
||||
}
|
||||
|
||||
NS_ConvertUCS2toUTF8( const PRUnichar* aString, PRUint32 aLength )
|
||||
{
|
||||
Append( aString, aLength );
|
||||
}
|
||||
|
||||
explicit
|
||||
NS_ConvertUCS2toUTF8( PRUnichar aChar )
|
||||
{
|
||||
Append( &aChar, 1 );
|
||||
}
|
||||
|
||||
explicit NS_ConvertUCS2toUTF8( const nsAString& aString );
|
||||
|
||||
protected:
|
||||
void Append( const PRUnichar* aString, PRUint32 aLength );
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
NS_ConvertUCS2toUTF8( char );
|
||||
operator const char*() const; // use |get()|
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,681 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rick Gessner <rickg@netscape.com> (original author)
|
||||
* Scott Collins <scc@mozilla.org>
|
||||
*/
|
||||
|
||||
/* nsString2.h --- rickg's original strings of 2-byte chars, |nsString| and |nsAutoString|;
|
||||
these classes will be replaced by the new shared-buffer string (see bug #53065)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _nsString_
|
||||
#define _nsString_
|
||||
|
||||
/***********************************************************************
|
||||
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
|
||||
***********************************************************************/
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nscore.h"
|
||||
#include <stdio.h>
|
||||
#include "nsString.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsStr.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#ifndef nsAFlatString_h___
|
||||
#include "nsAFlatString.h"
|
||||
#endif
|
||||
#include "nsXPIDLString.h"
|
||||
|
||||
#ifdef STANDALONE_MI_STRING_TESTS
|
||||
class nsAFlatString { public: virtual ~nsAString() { } };
|
||||
#endif
|
||||
|
||||
class nsISizeOfHandler;
|
||||
|
||||
#define nsString2 nsString
|
||||
#define nsAutoString2 nsAutoString
|
||||
|
||||
class NS_COM nsString :
|
||||
public nsAFlatString,
|
||||
public nsStr {
|
||||
|
||||
protected:
|
||||
virtual const nsBufferHandle<PRUnichar>* GetFlatBufferHandle() const;
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 );
|
||||
|
||||
public:
|
||||
virtual const PRUnichar* get() const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
nsString();
|
||||
|
||||
/**
|
||||
* This is our copy constructor
|
||||
* @param reference to another nsString
|
||||
*/
|
||||
nsString(const nsString& aString);
|
||||
|
||||
explicit nsString(const nsAString&);
|
||||
|
||||
explicit nsString(const PRUnichar*);
|
||||
nsString(const PRUnichar*, PRInt32);
|
||||
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
*/
|
||||
virtual ~nsString();
|
||||
|
||||
/**
|
||||
* Retrieve the length of this string
|
||||
* @return string length
|
||||
*/
|
||||
virtual PRUint32 Length() const { return 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);
|
||||
|
||||
/**
|
||||
* Sets the new length of the string.
|
||||
* @param aLength is new string length.
|
||||
* @return nada
|
||||
*/
|
||||
void SetCapacity(PRUint32 aLength);
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Getters/Setters...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* Retrieve const ptr to internal buffer; DO NOT TRY TO FREE IT!
|
||||
*/
|
||||
const char* GetBuffer(void) const;
|
||||
|
||||
/**
|
||||
* Set nth character.
|
||||
*/
|
||||
PRBool SetCharAt(PRUnichar aChar,PRUint32 anIndex);
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
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
|
||||
*/
|
||||
void StripChars( const char* aSet );
|
||||
void StripChar( PRUnichar aChar, PRInt32 anOffset=0 );
|
||||
void StripChar( char aChar, PRInt32 anOffset=0 ) { StripChar((PRUnichar) (unsigned char)aChar,anOffset); }
|
||||
void StripChar( PRInt32 anInt, PRInt32 anOffset=0 ) { StripChar((PRUnichar)anInt,anOffset); }
|
||||
|
||||
/**
|
||||
* This method strips whitespace throughout the string
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
void StripWhitespace();
|
||||
|
||||
/**
|
||||
* swaps occurence of 1 string for another
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
void ReplaceChar( PRUnichar anOldChar, PRUnichar aNewChar );
|
||||
void ReplaceChar( const char* aSet, PRUnichar aNewChar );
|
||||
|
||||
void ReplaceSubstring( const nsString& aTarget, const nsString& aNewValue );
|
||||
void ReplaceSubstring( const PRUnichar* aTarget, const PRUnichar* aNewValue );
|
||||
|
||||
/**
|
||||
* This method trims characters found in aTrimSet from
|
||||
* either end of the underlying string.
|
||||
*
|
||||
* @param aTrimSet -- contains chars to be trimmed from
|
||||
* both ends
|
||||
* @param aEliminateLeading
|
||||
* @param aEliminateTrailing
|
||||
* @param aIgnoreQuotes
|
||||
* @return this
|
||||
*/
|
||||
void Trim(const char* aSet,PRBool aEliminateLeading=PR_TRUE,PRBool aEliminateTrailing=PR_TRUE,PRBool aIgnoreQuotes=PR_FALSE);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void 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
|
||||
*/
|
||||
void 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
|
||||
* |nsMemory::Free|.
|
||||
* @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
|
||||
* |nsMemory::Free|.
|
||||
* @return ptr to new null-terminated UTF8 string
|
||||
*/
|
||||
char* ToNewUTF8String() const;
|
||||
|
||||
/**
|
||||
* Creates a unicode clone of this string
|
||||
* Note that calls to this method should be matched with calls to
|
||||
* |nsMemory::Free|.
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Perform string to int conversion.
|
||||
* @param aErrorCode will contain error if one occurs
|
||||
* @param aRadix tells us which radix to assume; kAutoDetect tells us to determine the radix for you.
|
||||
* @return int rep of string value, and possible (out) error code
|
||||
*/
|
||||
PRInt32 ToInteger(PRInt32* aErrorCode,PRUint32 aRadix=kRadix10) const;
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
String manipulation methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* assign given string to this string
|
||||
* @param aStr: buffer to be assigned to this
|
||||
* @param aCount is the length of the given str (or -1) if you want me to determine its length
|
||||
* NOTE: IFF you pass -1 as aCount, then your buffer must be null terminated.
|
||||
|
||||
* @return this
|
||||
*/
|
||||
|
||||
nsString& operator=( const nsString& aString ) { Assign(aString); return *this; }
|
||||
nsString& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; }
|
||||
//nsString& operator=( const nsPromiseReadable<PRUnichar>& aReadable ) { Assign(aReadable); return *this; }
|
||||
nsString& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; }
|
||||
nsString& operator=( PRUnichar aChar ) { Assign(aChar); return *this; }
|
||||
|
||||
void AssignWithConversion(char);
|
||||
void AssignWithConversion(const char*);
|
||||
void AssignWithConversion(const char*, PRInt32);
|
||||
|
||||
void AssignWithConversion(const nsAFlatCString& aCString)
|
||||
{
|
||||
AssignWithConversion(aCString.get(), aCString.Length());
|
||||
}
|
||||
|
||||
void AssignWithConversion(const nsAFlatCString& aCString, PRInt32 aCount)
|
||||
{
|
||||
AssignWithConversion(aCString.get(), aCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
void AppendInt(PRInt32, PRInt32=10); //radix=8,10 or 16
|
||||
void AppendFloat(double);
|
||||
void AppendWithConversion(const char*, PRInt32=-1);
|
||||
void AppendWithConversion(char);
|
||||
|
||||
void AppendWithConversion(const nsAFlatCString& aCString)
|
||||
{
|
||||
AppendWithConversion(aCString.get(), aCString.Length());
|
||||
}
|
||||
|
||||
void AppendWithConversion(const nsAFlatCString& aCString, PRInt32 aCount)
|
||||
{
|
||||
AppendWithConversion(aCString.get(), aCount);
|
||||
}
|
||||
|
||||
virtual void do_AppendFromElement( PRUnichar );
|
||||
|
||||
|
||||
//void InsertWithConversion(char);
|
||||
void InsertWithConversion(const char*, PRUint32, PRInt32=-1);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Searching methods...
|
||||
*********************************************************************/
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param aCount tells us how many iterations to make starting at the given offset
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 Find(const nsString& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-1) const;
|
||||
PRInt32 Find(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-1) const;
|
||||
PRInt32 Find(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-1) const;
|
||||
PRInt32 Find(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=0,PRInt32 aCount=-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
|
||||
* @param aCount tells us how many iterations to make starting at the given offset
|
||||
* @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=0,PRInt32 aCount=-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=0) const;
|
||||
PRInt32 FindCharInSet(const PRUnichar* aString,PRInt32 anOffset=0) const;
|
||||
PRInt32 FindCharInSet(const nsStr& aString,PRInt32 anOffset=0) 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)
|
||||
* @param aCount tells us how many iterations to make starting at the given offset
|
||||
* @return offset in string, or -1 (kNotFound)
|
||||
*/
|
||||
PRInt32 RFind(const char* aCString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-1) const;
|
||||
PRInt32 RFind(const nsString& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-1) const;
|
||||
PRInt32 RFind(const nsStr& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-1) const;
|
||||
PRInt32 RFind(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 anOffset=-1,PRInt32 aCount=-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
|
||||
* @param aCount tells us how many iterations to make starting at the given offset
|
||||
* @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,PRInt32 aCount=-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
|
||||
*/
|
||||
|
||||
PRInt32 CompareWithConversion(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRInt32 CompareWithConversion(const nsString& aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRInt32 CompareWithConversion(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
/* a hack to make sure things that used to compile continue to compile
|
||||
even on compilers that don't have proper |explicit| support */
|
||||
inline PRInt32
|
||||
CompareWithConversion(const nsXPIDLString& aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aCount=-1) const
|
||||
{
|
||||
return CompareWithConversion(aString.get(), aIgnoreCase, aCount);
|
||||
}
|
||||
|
||||
PRBool EqualsWithConversion(const nsString &aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsWithConversion(const char* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsWithConversion(const PRUnichar* aString,PRBool aIgnoreCase=PR_FALSE,PRInt32 aCount=-1) const;
|
||||
/* a hack to make sure things that used to compile continue to compile
|
||||
even on compilers that don't have proper |explicit| support */
|
||||
inline PRBool
|
||||
EqualsWithConversion(const nsXPIDLString &aString, PRBool aIgnoreCase=PR_FALSE, PRInt32 aCount=-1) const
|
||||
{
|
||||
return EqualsWithConversion(aString.get(), aIgnoreCase, aCount);
|
||||
}
|
||||
|
||||
|
||||
PRBool EqualsAtom(/*FIX: const */nsIAtom* anAtom,PRBool aIgnoreCase) const;
|
||||
|
||||
PRBool EqualsIgnoreCase(const nsString& aString) const;
|
||||
PRBool EqualsIgnoreCase(const char* aString,PRInt32 aCount=-1) const;
|
||||
PRBool EqualsIgnoreCase(/*FIX: const */nsIAtom *aAtom) 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);
|
||||
|
||||
void DebugDump(void) const;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
// these signatures help clients not accidentally call the wrong thing helped by C++ automatic integral promotion
|
||||
void operator=( char );
|
||||
void AssignWithConversion( PRUnichar );
|
||||
void AssignWithConversion( const PRUnichar*, PRInt32=-1 );
|
||||
void AppendWithConversion( PRUnichar );
|
||||
void AppendWithConversion( const PRUnichar*, PRInt32=-1 );
|
||||
void InsertWithConversion( const PRUnichar*, PRUint32, PRInt32=-1 );
|
||||
};
|
||||
|
||||
// NS_DEF_STRING_COMPARISON_OPERATORS(nsString, PRUnichar)
|
||||
// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsString, PRUnichar)
|
||||
|
||||
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:
|
||||
|
||||
virtual ~nsAutoString();
|
||||
nsAutoString();
|
||||
nsAutoString(const nsAutoString& aString);
|
||||
explicit nsAutoString(const nsAString& aString);
|
||||
explicit nsAutoString(const nsString& aString);
|
||||
explicit nsAutoString(const PRUnichar* aString);
|
||||
nsAutoString(const PRUnichar* aString,PRInt32 aLength);
|
||||
explicit nsAutoString(PRUnichar aChar);
|
||||
explicit nsAutoString(const CBufDescriptor& aBuffer);
|
||||
|
||||
nsAutoString& operator=( const nsAutoString& aString ) { Assign(aString); return *this; }
|
||||
private:
|
||||
void operator=( char ); // NOT TO BE IMPLEMENTED
|
||||
public:
|
||||
nsAutoString& operator=( const nsAString& aReadable ) { Assign(aReadable); return *this; }
|
||||
// nsAutoString& operator=( const nsPromiseReadable<PRUnichar>& aReadable ) { Assign(aReadable); return *this; }
|
||||
nsAutoString& operator=( const PRUnichar* aPtr ) { Assign(aPtr); return *this; }
|
||||
nsAutoString& operator=( PRUnichar aChar ) { 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];
|
||||
};
|
||||
|
||||
// NS_DEF_DERIVED_STRING_OPERATOR_PLUS(nsAutoString, PRUnichar)
|
||||
|
||||
class NS_COM NS_ConvertASCIItoUCS2
|
||||
: public nsAutoString
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
NS_ConvertASCIItoUCS2( const nsACString& aCString );
|
||||
|
||||
explicit
|
||||
NS_ConvertASCIItoUCS2( const nsAFlatCString& aCString )
|
||||
{
|
||||
Init( aCString.get(), aCString.Length() );
|
||||
}
|
||||
|
||||
explicit
|
||||
NS_ConvertASCIItoUCS2( const char* aCString )
|
||||
{
|
||||
Init( aCString, ~PRUint32(0) /* MAXINT */ );
|
||||
}
|
||||
|
||||
NS_ConvertASCIItoUCS2( const char* aCString, PRUint32 aLength )
|
||||
{
|
||||
Init( aCString, aLength );
|
||||
}
|
||||
|
||||
explicit
|
||||
NS_ConvertASCIItoUCS2( char );
|
||||
|
||||
#if 0
|
||||
operator const nsDependentString() const
|
||||
{
|
||||
return nsDependentString(mUStr, mLength);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void Init( const char* aCString, PRUint32 aLength );
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
NS_ConvertASCIItoUCS2( PRUnichar );
|
||||
};
|
||||
|
||||
class NS_COM NS_ConvertUTF8toUCS2
|
||||
: public nsAutoString
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
NS_ConvertUTF8toUCS2( const nsACString& aCString );
|
||||
|
||||
explicit
|
||||
NS_ConvertUTF8toUCS2( const nsAFlatCString& aCString )
|
||||
{
|
||||
Init( aCString.get(), aCString.Length() );
|
||||
}
|
||||
|
||||
explicit
|
||||
NS_ConvertUTF8toUCS2( const char* aCString )
|
||||
{
|
||||
Init( aCString, ~PRUint32(0) /* MAXINT */ );
|
||||
}
|
||||
|
||||
NS_ConvertUTF8toUCS2( const char* aCString, PRUint32 aLength )
|
||||
{
|
||||
Init( aCString, aLength );
|
||||
}
|
||||
|
||||
explicit
|
||||
NS_ConvertUTF8toUCS2( char aChar )
|
||||
{
|
||||
Init( &aChar, 1 );
|
||||
}
|
||||
|
||||
protected:
|
||||
void Init( const char* aCString, PRUint32 aLength );
|
||||
|
||||
private:
|
||||
NS_ConvertUTF8toUCS2( PRUnichar );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,72 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsDebug.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "plstr.h"
|
||||
|
||||
// If the allocator changes, fix it here.
|
||||
#define XPIDL_STRING_ALLOC(__len) ((PRUnichar*) nsMemory::Alloc((__len) * sizeof(PRUnichar)))
|
||||
#define XPIDL_CSTRING_ALLOC(__len) ((char*) nsMemory::Alloc((__len) * sizeof(char)))
|
||||
#define XPIDL_FREE(__ptr) (nsMemory::Free(__ptr))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLString
|
||||
|
||||
nsXPIDLString::~nsXPIDLString()
|
||||
{
|
||||
if (mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
}
|
||||
|
||||
|
||||
PRUnichar**
|
||||
nsXPIDLString::StartAssignmentByValue()
|
||||
{
|
||||
if (mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
mBuf = 0;
|
||||
return &mBuf;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLCString
|
||||
|
||||
nsXPIDLCString::~nsXPIDLCString()
|
||||
{
|
||||
if (mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
}
|
||||
|
||||
|
||||
char**
|
||||
nsXPIDLCString::StartAssignmentByValue()
|
||||
{
|
||||
if (mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
mBuf = 0;
|
||||
return &mBuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,323 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
/* nsXPIDLString.h --- an `|auto_ptr|' for character buffers, this functionality will be replaced
|
||||
by the new shared-buffer string (see bug #53065)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef nsXPIDLString_h__
|
||||
#define nsXPIDLString_h__
|
||||
|
||||
/*
|
||||
|
||||
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);
|
||||
nsMemory::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 nsMemory::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 `getter_Copies()'
|
||||
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 where the
|
||||
callee is returning a const reference to `the real deal' (this can
|
||||
be done using the [shared] attribute in XPIDL) you can just use
|
||||
a |const char*|.
|
||||
|
||||
*/
|
||||
|
||||
#include "nscore.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()|
|
||||
// helper function, this can be used instead of
|
||||
// the "naked" |PRUnichar*| interface for |wstring| parameters in
|
||||
// XPIDL interfaces.
|
||||
//
|
||||
|
||||
class NS_COM nsXPIDLString {
|
||||
private:
|
||||
PRUnichar* mBuf;
|
||||
|
||||
PRUnichar** StartAssignmentByValue();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new, uninitialized wrapper for a Unicode string.
|
||||
*/
|
||||
nsXPIDLString() : mBuf(0) {}
|
||||
|
||||
~nsXPIDLString();
|
||||
|
||||
/**
|
||||
* Return a reference to the immutable Unicode string.
|
||||
*/
|
||||
operator const PRUnichar*() const { return get(); }
|
||||
|
||||
/**
|
||||
* Return a reference to the immutable Unicode string.
|
||||
*/
|
||||
const PRUnichar* get() const { return mBuf; }
|
||||
|
||||
// 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;
|
||||
|
||||
inline void Adopt( PRUnichar* );
|
||||
|
||||
private:
|
||||
// not to be implemented
|
||||
nsXPIDLString(nsXPIDLString& /* aXPIDLString */) {}
|
||||
void operator=(nsXPIDLString& /* aXPIDLString */) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsXPIDLString::Adopt( PRUnichar* aNewValue )
|
||||
{
|
||||
*StartAssignmentByValue() = aNewValue;
|
||||
}
|
||||
|
||||
// XXX THESE ARE NOT strcmp()! DON'T TRY TO USE THEM AS SUCH!
|
||||
inline
|
||||
PRBool
|
||||
operator==(const PRUnichar* lhs, const nsXPIDLString& rhs)
|
||||
{
|
||||
return lhs == rhs.get();
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==(const nsXPIDLString& lhs, const PRUnichar* rhs)
|
||||
{
|
||||
return lhs.get() == rhs;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==(int lhs, const nsXPIDLString& rhs)
|
||||
{
|
||||
return NS_REINTERPRET_CAST(PRUnichar*, lhs) == NS_STATIC_CAST(const PRUnichar*, rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==(const nsXPIDLString& lhs, int rhs)
|
||||
{
|
||||
return NS_STATIC_CAST(const PRUnichar*, lhs) == NS_REINTERPRET_CAST(PRUnichar*, rhs);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLCString
|
||||
//
|
||||
// A wrapper for Unicode strings. With the |getter_Copies()|
|
||||
// helper function, this can be used instead of
|
||||
// the "naked" |char*| interface for |string| parameters in XPIDL
|
||||
// interfaces.
|
||||
//
|
||||
|
||||
class NS_COM nsXPIDLCString {
|
||||
private:
|
||||
char* mBuf;
|
||||
|
||||
char** StartAssignmentByValue();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new, uninitialized wrapper for a single-byte string.
|
||||
*/
|
||||
nsXPIDLCString() : mBuf(0) {}
|
||||
|
||||
~nsXPIDLCString();
|
||||
|
||||
/**
|
||||
* Return a reference to the immutable single-byte string.
|
||||
*/
|
||||
operator const char*() const { return get(); }
|
||||
|
||||
/**
|
||||
* Return a reference to the immutable single-byte string.
|
||||
*/
|
||||
const char* get() const { return mBuf; }
|
||||
|
||||
// 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;
|
||||
|
||||
inline void Adopt( char* );
|
||||
|
||||
private:
|
||||
// not to be implemented
|
||||
nsXPIDLCString(nsXPIDLCString& /* aXPIDLString */) {}
|
||||
void operator=(nsXPIDLCString& /* aXPIDLCString */) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsXPIDLCString::Adopt( char* aNewValue )
|
||||
{
|
||||
*StartAssignmentByValue() = aNewValue;
|
||||
}
|
||||
|
||||
// XXX THESE ARE NOT strcmp()! DON'T TRY TO USE THEM AS SUCH!
|
||||
inline
|
||||
PRBool
|
||||
operator==(const char* lhs, const nsXPIDLCString& rhs)
|
||||
{
|
||||
return lhs == rhs.get();
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==(const nsXPIDLCString& lhs, const char* rhs)
|
||||
{
|
||||
return lhs.get() == rhs;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==(int lhs, const nsXPIDLCString& rhs)
|
||||
{
|
||||
return NS_REINTERPRET_CAST(char*, lhs) == NS_STATIC_CAST(const char*, rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==(const nsXPIDLCString& lhs, int rhs)
|
||||
{
|
||||
return NS_STATIC_CAST(const char*, lhs) == NS_REINTERPRET_CAST(char*, rhs);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // nsXPIDLString_h__
|
||||
@@ -1,52 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Scott Collins <scc@mozilla.org> (original author)
|
||||
#
|
||||
|
||||
|
||||
nsAFlatString.h
|
||||
nsAlgorithm.h
|
||||
nsAPromiseString.h
|
||||
nsAReadableString.h
|
||||
nsAString.h
|
||||
nsAStringGenerator.h
|
||||
nsAWritableString.h
|
||||
nsBufferHandle.h
|
||||
nsBufferHandleUtils.h
|
||||
nsCharTraits.h
|
||||
nsDependentConcatenation.h
|
||||
nsDependentString.h
|
||||
nsDependentSubstring.h
|
||||
nsFragmentedString.h
|
||||
nsLiteralString.h
|
||||
nsPrintfCString.h
|
||||
nsPrivateSharableString.h
|
||||
nsPromiseFlatString.h
|
||||
nsReadableUtils.h
|
||||
nsSharableString.h
|
||||
nsSharedBufferList.h
|
||||
nsSlidingString.h
|
||||
nsStringDefines.h
|
||||
nsStringFragment.h
|
||||
nsStringFwd.h
|
||||
nsStringIterator.h
|
||||
nsStringIteratorUtils.h
|
||||
nsStringTraits.h
|
||||
nsXPIDLString.h
|
||||
@@ -1,67 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
# Scott Collins <scc@mozilla.org>
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = string
|
||||
|
||||
EXPORTS = \
|
||||
nsAFlatString.h \
|
||||
nsAlgorithm.h \
|
||||
nsAPromiseString.h \
|
||||
nsAReadableString.h \
|
||||
nsAString.h \
|
||||
nsAStringGenerator.h \
|
||||
nsAWritableString.h \
|
||||
nsBufferHandle.h \
|
||||
nsBufferHandleUtils.h \
|
||||
nsCharTraits.h \
|
||||
nsDependentConcatenation.h \
|
||||
nsDependentString.h \
|
||||
nsDependentSubstring.h \
|
||||
nsFragmentedString.h \
|
||||
nsLiteralString.h \
|
||||
nsPrintfCString.h \
|
||||
nsPrivateSharableString.h \
|
||||
nsPromiseFlatString.h \
|
||||
nsReadableUtils.h \
|
||||
nsSharableString.h \
|
||||
nsSharedBufferList.h \
|
||||
nsSlidingString.h \
|
||||
nsStringDefines.h \
|
||||
nsStringFragment.h \
|
||||
nsStringFwd.h \
|
||||
nsStringIterator.h \
|
||||
nsStringIteratorUtils.h \
|
||||
nsStringTraits.h \
|
||||
nsXPIDLString.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
@@ -1,59 +0,0 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
# Scott Collins <scc@mozilla.org>
|
||||
#
|
||||
|
||||
DEPTH=..\..
|
||||
|
||||
EXPORTS = \
|
||||
nsAFlatString.h \
|
||||
nsAlgorithm.h \
|
||||
nsAPromiseString.h \
|
||||
nsAReadableString.h \
|
||||
nsAString.h \
|
||||
nsAStringGenerator.h \
|
||||
nsAWritableString.h \
|
||||
nsBufferHandle.h \
|
||||
nsBufferHandleUtils.h \
|
||||
nsCharTraits.h \
|
||||
nsDependentConcatenation.h \
|
||||
nsDependentString.h \
|
||||
nsDependentSubstring.h \
|
||||
nsFragmentedString.h \
|
||||
nsLiteralString.h \
|
||||
nsPrintfCString.h \
|
||||
nsPrivateSharableString.h \
|
||||
nsPromiseFlatString.h \
|
||||
nsReadableUtils.h \
|
||||
nsSharableString.h \
|
||||
nsSharedBufferList.h \
|
||||
nsSlidingString.h \
|
||||
nsStringDefines.h \
|
||||
nsStringFragment.h \
|
||||
nsStringFwd.h \
|
||||
nsStringIterator.h \
|
||||
nsStringIteratorUtils.h \
|
||||
nsStringTraits.h \
|
||||
nsXPIDLString.h \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
@@ -1,85 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsAFlatString.h --- */
|
||||
|
||||
#ifndef nsAFlatString_h___
|
||||
#define nsAFlatString_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
class NS_COM nsAFlatString
|
||||
: public nsAString
|
||||
{
|
||||
public:
|
||||
// don't really want this to be virtual, and won't after |obsolete_nsString| is really dead
|
||||
virtual const PRUnichar* get() const;
|
||||
PRUnichar operator[]( PRUint32 i ) const { return get()[ i ]; }
|
||||
PRUnichar CharAt( PRUint32 ) const;
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
|
||||
// protected: // can't hide these (yet), since I call them from forwarding routines in |nsPromiseFlatString|
|
||||
public:
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 );
|
||||
};
|
||||
|
||||
class NS_COM nsAFlatCString
|
||||
: public nsACString
|
||||
{
|
||||
public:
|
||||
// don't really want this to be virtual, and won't after |obsolete_nsCString| is really dead
|
||||
virtual const char* get() const;
|
||||
char operator[]( PRUint32 i ) const { return get()[ i ]; }
|
||||
char CharAt( PRUint32 ) const;
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
|
||||
// protected: // can't hide these (yet), since I call them from forwarding routines in |nsPromiseFlatCString|
|
||||
public:
|
||||
virtual const char* GetReadableFragment( nsReadableFragment<char>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char* GetWritableFragment( nsWritableFragment<char>&, nsFragmentRequest, PRUint32 );
|
||||
};
|
||||
|
||||
inline
|
||||
PRUnichar
|
||||
nsAFlatString::CharAt( PRUint32 i ) const
|
||||
{
|
||||
NS_ASSERTION(i<Length(), "|CharAt| out-of-range");
|
||||
return operator[](i);
|
||||
}
|
||||
|
||||
inline
|
||||
char
|
||||
nsAFlatCString::CharAt( PRUint32 i ) const
|
||||
{
|
||||
NS_ASSERTION(i<Length(), "|CharAt| out-of-range");
|
||||
return operator[](i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* !defined(nsAFlatString_h___) */
|
||||
@@ -1,38 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsAPromiseString.h --- abstract base class for strings don't actually own their own characters, but proxy data from other strings */
|
||||
|
||||
#ifndef nsAPromiseString_h___
|
||||
#define nsAPromiseString_h___
|
||||
|
||||
/**
|
||||
* Don't |#include| this file yourself. You will get it automatically if you need it.
|
||||
*
|
||||
* Why is it a separate file? To make it easier to find the classes in your local tree.
|
||||
*/
|
||||
|
||||
class NS_COM nsAPromiseString : public nsAString { };
|
||||
class NS_COM nsAPromiseCString : public nsACString { };
|
||||
|
||||
#endif /* !defined(nsAPromiseString_h___) */
|
||||
@@ -1,54 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsAReadableString.h --- a compatibility header for clients still using the names |nsAReadable[C]String| et al */
|
||||
|
||||
#ifndef nsAReadableString_h___
|
||||
#define nsAReadableString_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
typedef const nsAString nsAReadableString;
|
||||
typedef const nsACString nsAReadableCString;
|
||||
|
||||
#ifndef nsLiteralString_h___
|
||||
#include "nsLiteralString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nDependentSubstring_h___
|
||||
#include "nsDependentSubstring.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsPromiseFlatString_h___
|
||||
#include "nsPromiseFlatString.h"
|
||||
#endif
|
||||
|
||||
#ifdef NEED_CPP_TEMPLATE_CAST_TO_BASE
|
||||
#define NS_READABLE_CAST(CharT, expr) (NS_STATIC_CAST(const nsStringTraits<CharT>::abstract_string_type&, (expr)))
|
||||
#else
|
||||
#define NS_READABLE_CAST(CharT, expr) (expr)
|
||||
#endif
|
||||
|
||||
#endif // !defined(nsAReadableString_h___)
|
||||
@@ -1,813 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#define nsAString_h___
|
||||
|
||||
#ifndef nsStringFwd_h___
|
||||
#include "nsStringFwd.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsPrivateSharableString_h___
|
||||
#include "nsPrivateSharableString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsCharTraits_h___
|
||||
#include "nsCharTraits.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsStringIterator_h___
|
||||
#include "nsStringIterator.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
class NS_COM nsAString
|
||||
: public nsPrivateSharableString
|
||||
{
|
||||
public:
|
||||
typedef nsAString self_type;
|
||||
typedef nsAPromiseString promise_type;
|
||||
typedef PRUnichar char_type;
|
||||
typedef char incompatible_char_type;
|
||||
|
||||
|
||||
typedef nsReadingIterator<char_type> const_iterator;
|
||||
typedef nsWritingIterator<char_type> iterator;
|
||||
|
||||
typedef PRUint32 size_type;
|
||||
typedef PRUint32 index_type;
|
||||
|
||||
|
||||
|
||||
|
||||
// nsAString(); // auto-generated default constructor OK (we're abstract anyway)
|
||||
// nsAString( const self_type& ); // auto-generated copy-constructor OK (again, only because we're abstract)
|
||||
virtual ~nsAString() { } // ...yes, I expect to be sub-classed
|
||||
|
||||
inline const_iterator& BeginReading( const_iterator& ) const;
|
||||
inline const_iterator& EndReading( const_iterator& ) const;
|
||||
|
||||
inline iterator& BeginWriting( iterator& );
|
||||
inline iterator& EndWriting( iterator& );
|
||||
|
||||
virtual size_type Length() const = 0;
|
||||
PRBool IsEmpty() const { return Length() == 0; }
|
||||
|
||||
inline PRBool Equals( const self_type& ) const;
|
||||
PRBool Equals( const char_type* ) const;
|
||||
|
||||
|
||||
/**
|
||||
* |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations.
|
||||
* These signatures should be pushed down into interfaces that guarantee flat allocation.
|
||||
* Clients at _this_ level should always use iterators.
|
||||
*/
|
||||
char_type First() const;
|
||||
char_type Last() const;
|
||||
|
||||
size_type CountChar( char_type ) const;
|
||||
|
||||
|
||||
/*
|
||||
|Left|, |Mid|, and |Right| are annoying signatures that seem better almost
|
||||
any _other_ way than they are now. Consider these alternatives
|
||||
|
||||
aWritable = aReadable.Left(17); // ...a member function that returns a |Substring|
|
||||
aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring|
|
||||
Left(aReadable, 17, aWritable); // ...a global function that does the assignment
|
||||
|
||||
as opposed to the current signature
|
||||
|
||||
aReadable.Left(aWritable, 17); // ...a member function that does the assignment
|
||||
|
||||
or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality
|
||||
|
||||
aWritable = Substring(aReadable, 0, 17);
|
||||
*/
|
||||
|
||||
size_type Left( self_type&, size_type ) const;
|
||||
size_type Mid( self_type&, PRUint32, PRUint32 ) const;
|
||||
size_type Right( self_type&, size_type ) const;
|
||||
|
||||
// Find( ... ) const;
|
||||
PRInt32 FindChar( char_type, index_type aOffset = 0 ) const;
|
||||
// FindCharInSet( ... ) const;
|
||||
// RFind( ... ) const;
|
||||
// RFindChar( ... ) const;
|
||||
// RFindCharInSet( ... ) const;
|
||||
|
||||
/**
|
||||
* |SetCapacity| is not required to do anything; however, it can be used
|
||||
* as a hint to the implementation to reduce allocations.
|
||||
* |SetCapacity(0)| is a suggestion to discard all associated storage.
|
||||
*/
|
||||
virtual void SetCapacity( size_type ) { }
|
||||
|
||||
/**
|
||||
* |SetLength| is used in two ways:
|
||||
* 1) to |Cut| a suffix of the string;
|
||||
* 2) to prepare to |Append| or move characters around.
|
||||
*
|
||||
* External callers are not allowed to use |SetLength| is this latter capacity.
|
||||
* Should this really be a public operation?
|
||||
* Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you
|
||||
* override the |do_...| routines to not need this facility.
|
||||
*
|
||||
* This distinction makes me think the two different uses should be split into
|
||||
* two distinct functions.
|
||||
*/
|
||||
virtual void SetLength( size_type ) { }
|
||||
|
||||
|
||||
void
|
||||
Truncate( size_type aNewLength=0 )
|
||||
{
|
||||
NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer.");
|
||||
|
||||
if ( aNewLength < this->Length() )
|
||||
SetLength(aNewLength);
|
||||
}
|
||||
|
||||
|
||||
// PRBool SetCharAt( char_type, index_type ) = 0;
|
||||
|
||||
|
||||
|
||||
// void ToLowerCase();
|
||||
// void ToUpperCase();
|
||||
|
||||
// void StripChars( const char_type* aSet );
|
||||
// void StripChar( ... );
|
||||
// void StripWhitespace();
|
||||
// void ReplaceChar( ... );
|
||||
// void ReplaceSubstring( ... );
|
||||
// void Trim( ... );
|
||||
// void CompressSet( ... );
|
||||
// void CompressWhitespace( ... );
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Assign()|, |operator=()|
|
||||
//
|
||||
|
||||
void Assign( const self_type& aReadable ) { AssignFromReadable(aReadable); }
|
||||
inline void Assign( const promise_type& aReadable );
|
||||
void Assign( const char_type* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); }
|
||||
void Assign( const char_type* aPtr, size_type aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); }
|
||||
void Assign( char_type aChar ) { do_AssignFromElement(aChar); }
|
||||
|
||||
// copy-assignment operator. I must define my own if I don't want the compiler to make me one
|
||||
self_type& operator=( const self_type& aReadable ) { Assign(aReadable); return *this; }
|
||||
|
||||
self_type& operator=( const promise_type& aReadable ) { Assign(aReadable); return *this; }
|
||||
self_type& operator=( const char_type* aPtr ) { Assign(aPtr); return *this; }
|
||||
self_type& operator=( char_type aChar ) { Assign(aChar); return *this; }
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Append()|, |operator+=()|
|
||||
//
|
||||
|
||||
void Append( const self_type& aReadable ) { AppendFromReadable(aReadable); }
|
||||
inline void Append( const promise_type& aReadable );
|
||||
void Append( const char_type* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); }
|
||||
void Append( const char_type* aPtr, size_type aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); }
|
||||
void Append( char_type aChar ) { do_AppendFromElement(aChar); }
|
||||
|
||||
self_type& operator+=( const self_type& aReadable ) { Append(aReadable); return *this; }
|
||||
self_type& operator+=( const promise_type& aReadable ) { Append(aReadable); return *this; }
|
||||
self_type& operator+=( const char_type* aPtr ) { Append(aPtr); return *this; }
|
||||
self_type& operator+=( char_type aChar ) { Append(aChar); return *this; }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The following index based routines need to be recast with iterators.
|
||||
*/
|
||||
|
||||
//
|
||||
// |Insert()|
|
||||
// Note: I would really like to move the |atPosition| parameter to the front of the argument list
|
||||
//
|
||||
|
||||
void Insert( const self_type& aReadable, index_type atPosition ) { InsertFromReadable(aReadable, atPosition); }
|
||||
inline void Insert( const promise_type& aReadable, index_type atPosition );
|
||||
void Insert( const char_type* aPtr, index_type atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); }
|
||||
void Insert( const char_type* aPtr, index_type atPosition, size_type aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); }
|
||||
void Insert( char_type aChar, index_type atPosition ) { do_InsertFromElement(aChar, atPosition); }
|
||||
|
||||
|
||||
|
||||
virtual void Cut( index_type cutStart, size_type cutLength );
|
||||
|
||||
|
||||
|
||||
void Replace( index_type cutStart, size_type cutLength, const self_type& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); }
|
||||
// void Replace( index_type cutStart, size_type cutLength, const promise_type& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); }
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
index_type CountChar( incompatible_char_type ) const;
|
||||
void operator= ( incompatible_char_type );
|
||||
void Assign ( incompatible_char_type );
|
||||
void operator+= ( incompatible_char_type );
|
||||
void Append ( incompatible_char_type );
|
||||
void Insert ( incompatible_char_type, index_type );
|
||||
|
||||
|
||||
protected:
|
||||
void AssignFromReadable( const self_type& );
|
||||
void AssignFromPromise( const self_type& );
|
||||
virtual void do_AssignFromReadable( const self_type& );
|
||||
virtual void do_AssignFromElementPtr( const char_type* );
|
||||
virtual void do_AssignFromElementPtrLength( const char_type*, size_type );
|
||||
virtual void do_AssignFromElement( char_type );
|
||||
|
||||
void AppendFromReadable( const self_type& );
|
||||
void AppendFromPromise( const self_type& );
|
||||
virtual void do_AppendFromReadable( const self_type& );
|
||||
virtual void do_AppendFromElementPtr( const char_type* );
|
||||
virtual void do_AppendFromElementPtrLength( const char_type*, size_type );
|
||||
virtual void do_AppendFromElement( char_type );
|
||||
|
||||
void InsertFromReadable( const self_type&, index_type );
|
||||
void InsertFromPromise( const self_type&, index_type );
|
||||
virtual void do_InsertFromReadable( const self_type&, index_type );
|
||||
virtual void do_InsertFromElementPtr( const char_type*, index_type );
|
||||
virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type );
|
||||
virtual void do_InsertFromElement( char_type, index_type );
|
||||
|
||||
void ReplaceFromReadable( index_type, size_type, const self_type& );
|
||||
void ReplaceFromPromise( index_type, size_type, const self_type& );
|
||||
virtual void do_ReplaceFromReadable( index_type, size_type, const self_type& );
|
||||
|
||||
|
||||
// protected:
|
||||
public:
|
||||
virtual const char_type* GetReadableFragment( nsReadableFragment<char_type>&, nsFragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
virtual char_type* GetWritableFragment( nsWritableFragment<char_type>&, nsFragmentRequest, PRUint32 = 0 ) = 0;
|
||||
virtual PRBool IsDependentOn( const self_type& aString ) const { return &aString == this; }
|
||||
};
|
||||
|
||||
class NS_COM nsACString
|
||||
: public nsPrivateSharableCString
|
||||
{
|
||||
public:
|
||||
typedef nsACString self_type;
|
||||
typedef nsAPromiseCString promise_type;
|
||||
typedef char char_type;
|
||||
typedef PRUnichar incompatible_char_type;
|
||||
|
||||
|
||||
typedef nsReadingIterator<char_type> const_iterator;
|
||||
typedef nsWritingIterator<char_type> iterator;
|
||||
|
||||
typedef PRUint32 size_type;
|
||||
typedef PRUint32 index_type;
|
||||
|
||||
|
||||
|
||||
|
||||
// nsACString(); // auto-generated default constructor OK (we're abstract anyway)
|
||||
// nsACString( const self_type& ); // auto-generated copy-constructor OK (again, only because we're abstract)
|
||||
virtual ~nsACString() { } // ...yes, I expect to be sub-classed
|
||||
|
||||
inline const_iterator& BeginReading( const_iterator& ) const;
|
||||
inline const_iterator& EndReading( const_iterator& ) const;
|
||||
|
||||
inline iterator& BeginWriting( iterator& );
|
||||
inline iterator& EndWriting( iterator& );
|
||||
|
||||
virtual size_type Length() const = 0;
|
||||
PRBool IsEmpty() const { return Length() == 0; }
|
||||
|
||||
inline PRBool Equals( const self_type& ) const;
|
||||
PRBool Equals( const char_type* ) const;
|
||||
|
||||
|
||||
/**
|
||||
* |CharAt|, |operator[]|, |First()|, and |Last()| are not guaranteed to be constant-time operations.
|
||||
* These signatures should be pushed down into interfaces that guarantee flat allocation.
|
||||
* Clients at _this_ level should always use iterators.
|
||||
*/
|
||||
char_type First() const;
|
||||
char_type Last() const;
|
||||
|
||||
size_type CountChar( char_type ) const;
|
||||
|
||||
|
||||
/*
|
||||
|Left|, |Mid|, and |Right| are annoying signatures that seem better almost
|
||||
any _other_ way than they are now. Consider these alternatives
|
||||
|
||||
aWritable = aReadable.Left(17); // ...a member function that returns a |Substring|
|
||||
aWritable = Left(aReadable, 17); // ...a global function that returns a |Substring|
|
||||
Left(aReadable, 17, aWritable); // ...a global function that does the assignment
|
||||
|
||||
as opposed to the current signature
|
||||
|
||||
aReadable.Left(aWritable, 17); // ...a member function that does the assignment
|
||||
|
||||
or maybe just stamping them out in favor of |Substring|, they are just duplicate functionality
|
||||
|
||||
aWritable = Substring(aReadable, 0, 17);
|
||||
*/
|
||||
|
||||
size_type Left( self_type&, size_type ) const;
|
||||
size_type Mid( self_type&, PRUint32, PRUint32 ) const;
|
||||
size_type Right( self_type&, size_type ) const;
|
||||
|
||||
// Find( ... ) const;
|
||||
PRInt32 FindChar( char_type, PRUint32 aOffset = 0 ) const;
|
||||
// FindCharInSet( ... ) const;
|
||||
// RFind( ... ) const;
|
||||
// RFindChar( ... ) const;
|
||||
// RFindCharInSet( ... ) const;
|
||||
|
||||
/**
|
||||
* |SetCapacity| is not required to do anything; however, it can be used
|
||||
* as a hint to the implementation to reduce allocations.
|
||||
* |SetCapacity(0)| is a suggestion to discard all associated storage.
|
||||
*/
|
||||
virtual void SetCapacity( size_type ) { }
|
||||
|
||||
/**
|
||||
* |SetLength| is used in two ways:
|
||||
* 1) to |Cut| a suffix of the string;
|
||||
* 2) to prepare to |Append| or move characters around.
|
||||
*
|
||||
* External callers are not allowed to use |SetLength| is this latter capacity.
|
||||
* Should this really be a public operation?
|
||||
* Additionally, your implementation of |SetLength| need not satisfy (2) if and only if you
|
||||
* override the |do_...| routines to not need this facility.
|
||||
*
|
||||
* This distinction makes me think the two different uses should be split into
|
||||
* two distinct functions.
|
||||
*/
|
||||
virtual void SetLength( size_type ) { }
|
||||
|
||||
|
||||
void
|
||||
Truncate( size_type aNewLength=0 )
|
||||
{
|
||||
NS_ASSERTION(aNewLength<=this->Length(), "Can't use |Truncate()| to make a string longer.");
|
||||
|
||||
if ( aNewLength < this->Length() )
|
||||
SetLength(aNewLength);
|
||||
}
|
||||
|
||||
|
||||
// PRBool SetCharAt( char_type, index_type ) = 0;
|
||||
|
||||
|
||||
|
||||
// void ToLowerCase();
|
||||
// void ToUpperCase();
|
||||
|
||||
// void StripChars( const char_type* aSet );
|
||||
// void StripChar( ... );
|
||||
// void StripWhitespace();
|
||||
// void ReplaceChar( ... );
|
||||
// void ReplaceSubstring( ... );
|
||||
// void Trim( ... );
|
||||
// void CompressSet( ... );
|
||||
// void CompressWhitespace( ... );
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Assign()|, |operator=()|
|
||||
//
|
||||
|
||||
void Assign( const self_type& aReadable ) { AssignFromReadable(aReadable); }
|
||||
inline void Assign( const promise_type& aReadable );
|
||||
void Assign( const char_type* aPtr ) { aPtr ? do_AssignFromElementPtr(aPtr) : SetLength(0); }
|
||||
void Assign( const char_type* aPtr, size_type aLength ) { do_AssignFromElementPtrLength(aPtr, aLength); }
|
||||
void Assign( char_type aChar ) { do_AssignFromElement(aChar); }
|
||||
|
||||
// copy-assignment operator. I must define my own if I don't want the compiler to make me one
|
||||
self_type& operator=( const self_type& aReadable ) { Assign(aReadable); return *this; }
|
||||
|
||||
self_type& operator=( const promise_type& aReadable ) { Assign(aReadable); return *this; }
|
||||
self_type& operator=( const char_type* aPtr ) { Assign(aPtr); return *this; }
|
||||
self_type& operator=( char_type aChar ) { Assign(aChar); return *this; }
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Append()|, |operator+=()|
|
||||
//
|
||||
|
||||
void Append( const self_type& aReadable ) { AppendFromReadable(aReadable); }
|
||||
inline void Append( const promise_type& aReadable );
|
||||
void Append( const char_type* aPtr ) { if (aPtr) do_AppendFromElementPtr(aPtr); }
|
||||
void Append( const char_type* aPtr, size_type aLength ) { do_AppendFromElementPtrLength(aPtr, aLength); }
|
||||
void Append( char_type aChar ) { do_AppendFromElement(aChar); }
|
||||
|
||||
self_type& operator+=( const self_type& aReadable ) { Append(aReadable); return *this; }
|
||||
self_type& operator+=( const promise_type& aReadable ) { Append(aReadable); return *this; }
|
||||
self_type& operator+=( const char_type* aPtr ) { Append(aPtr); return *this; }
|
||||
self_type& operator+=( char_type aChar ) { Append(aChar); return *this; }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The following index based routines need to be recast with iterators.
|
||||
*/
|
||||
|
||||
//
|
||||
// |Insert()|
|
||||
// Note: I would really like to move the |atPosition| parameter to the front of the argument list
|
||||
//
|
||||
|
||||
void Insert( const self_type& aReadable, index_type atPosition ) { InsertFromReadable(aReadable, atPosition); }
|
||||
inline void Insert( const promise_type& aReadable, index_type atPosition );
|
||||
void Insert( const char_type* aPtr, index_type atPosition ) { if (aPtr) do_InsertFromElementPtr(aPtr, atPosition); }
|
||||
void Insert( const char_type* aPtr, index_type atPosition, size_type aLength ) { do_InsertFromElementPtrLength(aPtr, atPosition, aLength); }
|
||||
void Insert( char_type aChar, index_type atPosition ) { do_InsertFromElement(aChar, atPosition); }
|
||||
|
||||
|
||||
|
||||
virtual void Cut( index_type cutStart, size_type cutLength );
|
||||
|
||||
|
||||
|
||||
void Replace( index_type cutStart, size_type cutLength, const self_type& aReadable ) { ReplaceFromReadable(cutStart, cutLength, aReadable); }
|
||||
// void Replace( index_type cutStart, size_type cutLength, const promise_type& aReadable ) { ReplaceFromPromise(cutStart, cutLength, aReadable); }
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
index_type CountChar( incompatible_char_type ) const;
|
||||
void operator= ( incompatible_char_type );
|
||||
void Assign ( incompatible_char_type );
|
||||
void operator+= ( incompatible_char_type );
|
||||
void Append ( incompatible_char_type );
|
||||
void Insert ( incompatible_char_type, index_type );
|
||||
|
||||
|
||||
protected:
|
||||
void AssignFromReadable( const self_type& );
|
||||
void AssignFromPromise( const self_type& );
|
||||
virtual void do_AssignFromReadable( const self_type& );
|
||||
virtual void do_AssignFromElementPtr( const char_type* );
|
||||
virtual void do_AssignFromElementPtrLength( const char_type*, size_type );
|
||||
virtual void do_AssignFromElement( char_type );
|
||||
|
||||
void AppendFromReadable( const self_type& );
|
||||
void AppendFromPromise( const self_type& );
|
||||
virtual void do_AppendFromReadable( const self_type& );
|
||||
virtual void do_AppendFromElementPtr( const char_type* );
|
||||
virtual void do_AppendFromElementPtrLength( const char_type*, size_type );
|
||||
virtual void do_AppendFromElement( char_type );
|
||||
|
||||
void InsertFromReadable( const self_type&, index_type );
|
||||
void InsertFromPromise( const self_type&, index_type );
|
||||
virtual void do_InsertFromReadable( const self_type&, index_type );
|
||||
virtual void do_InsertFromElementPtr( const char_type*, index_type );
|
||||
virtual void do_InsertFromElementPtrLength( const char_type*, index_type, size_type );
|
||||
virtual void do_InsertFromElement( char_type, index_type );
|
||||
|
||||
void ReplaceFromReadable( index_type, size_type, const self_type& );
|
||||
void ReplaceFromPromise( index_type, size_type, const self_type& );
|
||||
virtual void do_ReplaceFromReadable( index_type, size_type, const self_type& );
|
||||
|
||||
|
||||
// protected:
|
||||
public:
|
||||
virtual const char_type* GetReadableFragment( nsReadableFragment<char_type>&, nsFragmentRequest, PRUint32 = 0 ) const = 0;
|
||||
virtual char_type* GetWritableFragment( nsWritableFragment<char_type>&, nsFragmentRequest, PRUint32 = 0 ) = 0;
|
||||
virtual PRBool IsDependentOn( const self_type& aString ) const { return &aString == this; }
|
||||
};
|
||||
|
||||
#include "nsAPromiseString.h"
|
||||
|
||||
inline
|
||||
void
|
||||
nsAString::Assign( const nsAPromiseString& aReadable )
|
||||
{
|
||||
AssignFromPromise(aReadable);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsAString::Append( const nsAPromiseString& aReadable )
|
||||
{
|
||||
AppendFromPromise(aReadable);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsAString::Insert( const nsAPromiseString& aReadable, index_type atPosition )
|
||||
{
|
||||
InsertFromPromise(aReadable, atPosition);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsACString::Assign( const nsAPromiseCString& aReadable )
|
||||
{
|
||||
AssignFromPromise(aReadable);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsACString::Append( const nsAPromiseCString& aReadable )
|
||||
{
|
||||
AppendFromPromise(aReadable);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
nsACString::Insert( const nsAPromiseCString& aReadable, index_type atPosition )
|
||||
{
|
||||
InsertFromPromise(aReadable, atPosition);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Note: measure -- should the |Begin...| and |End...| be |inline|?
|
||||
*/
|
||||
inline
|
||||
nsAString::const_iterator&
|
||||
nsAString::BeginReading( const_iterator& aResult ) const
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetReadableFragment(aResult.mFragment, kFirstFragment);
|
||||
aResult.mPosition = aResult.mFragment.mStart;
|
||||
aResult.normalize_forward();
|
||||
return aResult;
|
||||
}
|
||||
|
||||
inline
|
||||
nsAString::const_iterator&
|
||||
nsAString::EndReading( const_iterator& aResult ) const
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetReadableFragment(aResult.mFragment, kLastFragment);
|
||||
aResult.mPosition = aResult.mFragment.mEnd;
|
||||
// must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )|
|
||||
return aResult;
|
||||
}
|
||||
|
||||
inline
|
||||
nsAString::iterator&
|
||||
nsAString::BeginWriting( iterator& aResult )
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetWritableFragment(aResult.mFragment, kFirstFragment);
|
||||
aResult.mPosition = aResult.mFragment.mStart;
|
||||
aResult.normalize_forward();
|
||||
return aResult;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
nsAString::iterator&
|
||||
nsAString::EndWriting( iterator& aResult )
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetWritableFragment(aResult.mFragment, kLastFragment);
|
||||
aResult.mPosition = aResult.mFragment.mEnd;
|
||||
// must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )|
|
||||
return aResult;
|
||||
}
|
||||
|
||||
class NS_COM nsStringComparator
|
||||
{
|
||||
public:
|
||||
virtual int operator()( const PRUnichar*, const PRUnichar*, PRUint32 aLength ) const = 0;
|
||||
};
|
||||
|
||||
class NS_COM nsDefaultStringComparator
|
||||
: public nsStringComparator
|
||||
{
|
||||
public:
|
||||
virtual int operator()( const PRUnichar*, const PRUnichar*, PRUint32 aLength ) const;
|
||||
};
|
||||
|
||||
class NS_COM nsCaseInsensitiveStringComparator
|
||||
: public nsStringComparator
|
||||
{
|
||||
public:
|
||||
virtual int operator()( const PRUnichar*, const PRUnichar*, PRUint32 aLength ) const;
|
||||
};
|
||||
|
||||
NS_COM int Compare( const nsAString& lhs, const nsAString& rhs, const nsStringComparator& = nsDefaultStringComparator() );
|
||||
|
||||
inline
|
||||
PRBool
|
||||
nsAString::Equals( const self_type& rhs ) const
|
||||
{
|
||||
return Length()==rhs.Length() && Compare(*this, rhs)==0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator!=( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return !lhs.Equals(rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator< ( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)< 0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator<=( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)<=0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return lhs.Equals(rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator>=( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)>=0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator> ( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)> 0;
|
||||
}
|
||||
|
||||
inline
|
||||
nsAString::size_type
|
||||
nsAString::Left( nsAString& aResult, size_type aLengthToCopy ) const
|
||||
{
|
||||
return Mid(aResult, 0, aLengthToCopy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
inline
|
||||
nsACString::const_iterator&
|
||||
nsACString::BeginReading( const_iterator& aResult ) const
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetReadableFragment(aResult.mFragment, kFirstFragment);
|
||||
aResult.mPosition = aResult.mFragment.mStart;
|
||||
aResult.normalize_forward();
|
||||
return aResult;
|
||||
}
|
||||
|
||||
inline
|
||||
nsACString::const_iterator&
|
||||
nsACString::EndReading( const_iterator& aResult ) const
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetReadableFragment(aResult.mFragment, kLastFragment);
|
||||
aResult.mPosition = aResult.mFragment.mEnd;
|
||||
// must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )|
|
||||
return aResult;
|
||||
}
|
||||
|
||||
inline
|
||||
nsACString::iterator&
|
||||
nsACString::BeginWriting( iterator& aResult )
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetWritableFragment(aResult.mFragment, kFirstFragment);
|
||||
aResult.mPosition = aResult.mFragment.mStart;
|
||||
aResult.normalize_forward();
|
||||
return aResult;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
nsACString::iterator&
|
||||
nsACString::EndWriting( iterator& aResult )
|
||||
{
|
||||
aResult.mOwningString = this;
|
||||
GetWritableFragment(aResult.mFragment, kLastFragment);
|
||||
aResult.mPosition = aResult.mFragment.mEnd;
|
||||
// must not |normalize_backward| as that would likely invalidate tests like |while ( first != last )|
|
||||
return aResult;
|
||||
}
|
||||
|
||||
|
||||
class NS_COM nsCStringComparator
|
||||
{
|
||||
public:
|
||||
virtual int operator()( const char*, const char*, PRUint32 aLength ) const = 0;
|
||||
};
|
||||
|
||||
class NS_COM nsDefaultCStringComparator
|
||||
: public nsCStringComparator
|
||||
{
|
||||
public:
|
||||
virtual int operator()( const char*, const char*, PRUint32 aLength ) const;
|
||||
};
|
||||
|
||||
class NS_COM nsCaseInsensitiveCStringComparator
|
||||
: public nsCStringComparator
|
||||
{
|
||||
public:
|
||||
virtual int operator()( const char*, const char*, PRUint32 aLength ) const;
|
||||
};
|
||||
|
||||
NS_COM int Compare( const nsACString& lhs, const nsACString& rhs, const nsCStringComparator& = nsDefaultCStringComparator() );
|
||||
|
||||
inline
|
||||
PRBool
|
||||
nsACString::Equals( const self_type& rhs ) const
|
||||
{
|
||||
return Length()==rhs.Length() && Compare(*this, rhs)==0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator!=( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return !lhs.Equals(rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator< ( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)< 0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator<=( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)<=0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator==( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return lhs.Equals(rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator>=( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)>=0;
|
||||
}
|
||||
|
||||
inline
|
||||
PRBool
|
||||
operator> ( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return Compare(lhs, rhs)> 0;
|
||||
}
|
||||
|
||||
inline
|
||||
nsACString::size_type
|
||||
nsACString::Left( nsACString& aResult, size_type aLengthToCopy ) const
|
||||
{
|
||||
return Mid(aResult, 0, aLengthToCopy);
|
||||
}
|
||||
|
||||
// Once you've got strings, you shouldn't need to do anything else to have concatenation
|
||||
#ifndef nsDependentConcatenation_h___
|
||||
#include "nsDependentConcatenation.h"
|
||||
#endif
|
||||
|
||||
#endif // !defined(nsAString_h___)
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsAStringGenerator.h --- generators produce strings into a callers buffer, avoiding temporaries */
|
||||
|
||||
#ifndef nsAStringGenerator_h___
|
||||
#define nsAStringGenerator_h___
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
#include "nscore.h"
|
||||
// for |PRUnichar|
|
||||
|
||||
#include "prtypes.h"
|
||||
// for |PRBool|, |PRUint32|
|
||||
|
||||
|
||||
class nsAString;
|
||||
class nsACString;
|
||||
|
||||
class nsAStringGenerator
|
||||
{
|
||||
public:
|
||||
virtual ~nsAStringGenerator() { }
|
||||
|
||||
virtual PRUnichar* operator()( PRUnichar* aDestBuffer ) const = 0;
|
||||
virtual PRUint32 Length() const = 0;
|
||||
virtual PRUint32 MaxLength() const = 0;
|
||||
virtual PRBool IsDependentOn( const nsAString& ) const = 0;
|
||||
};
|
||||
|
||||
class nsACStringGenerator
|
||||
{
|
||||
public:
|
||||
virtual ~nsACStringGenerator() { }
|
||||
|
||||
virtual char* operator()( char* aDestBuffer ) const = 0;
|
||||
virtual PRUint32 Length() const = 0;
|
||||
virtual PRUint32 MaxLength() const = 0;
|
||||
virtual PRBool IsDependentOn( const nsACString& ) const = 0;
|
||||
};
|
||||
|
||||
#endif // !defined(nsAStringGenerator_h___)
|
||||
@@ -1,36 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsAWritableString.h --- a compatibility header for clients still using the names |nsAWritable[C]String| */
|
||||
|
||||
#ifndef nsAWritableString_h___
|
||||
#define nsAWritableString_h___
|
||||
|
||||
#ifndef nsAReadableString_h___
|
||||
#include "nsAReadableString.h"
|
||||
#endif
|
||||
|
||||
typedef nsAString nsAWritableString;
|
||||
typedef nsACString nsAWritableCString;
|
||||
|
||||
#endif // !defined(nsAWritableString_h___)
|
||||
@@ -1,112 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsAlgorithm_h___
|
||||
#define nsAlgorithm_h___
|
||||
|
||||
#ifndef nsCharTraits_h___
|
||||
#include "nsCharTraits.h"
|
||||
// for |nsCharSourceTraits|, |nsCharSinkTraits|
|
||||
#endif
|
||||
|
||||
#ifndef prtypes_h___
|
||||
#include "prtypes.h"
|
||||
// for |PRUint32|...
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
const T&
|
||||
NS_MIN( const T& a, const T& b )
|
||||
{
|
||||
return b < a ? b : a;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
const T&
|
||||
NS_MAX( const T& a, const T& b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <class InputIterator, class T>
|
||||
inline
|
||||
PRUint32
|
||||
NS_COUNT( InputIterator& first, const InputIterator& last, const T& value )
|
||||
{
|
||||
PRUint32 result = 0;
|
||||
for ( ; first != last; ++first )
|
||||
if ( *first == value )
|
||||
++result;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class InputIterator, class OutputIterator>
|
||||
inline
|
||||
OutputIterator&
|
||||
copy_string( InputIterator& first, const InputIterator& last, OutputIterator& result )
|
||||
{
|
||||
typedef nsCharSourceTraits<InputIterator> source_traits;
|
||||
typedef nsCharSinkTraits<OutputIterator> sink_traits;
|
||||
|
||||
while ( first != last )
|
||||
{
|
||||
PRInt32 count_copied = PRInt32(sink_traits::write(result, source_traits::read(first), source_traits::readable_distance(first, last)));
|
||||
NS_ASSERTION(count_copied > 0, "|copy_string| will never terminate");
|
||||
source_traits::advance(first, count_copied);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class InputIterator, class OutputIterator>
|
||||
OutputIterator&
|
||||
copy_string_backward( const InputIterator& first, InputIterator& last, OutputIterator& result )
|
||||
{
|
||||
while ( first != last )
|
||||
{
|
||||
last.normalize_backward();
|
||||
result.normalize_backward();
|
||||
PRUint32 lengthToCopy = PRUint32( NS_MIN(last.size_backward(), result.size_backward()) );
|
||||
if ( first.fragment().mStart == last.fragment().mStart )
|
||||
lengthToCopy = NS_MIN(lengthToCopy, PRUint32(last.get() - first.get()));
|
||||
|
||||
NS_ASSERTION(lengthToCopy, "|copy_string_backward| will never terminate");
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// XXX Visual C++ can't stomach 'typename' where it rightfully should
|
||||
nsCharTraits<OutputIterator::value_type>::move(result.get()-lengthToCopy, last.get()-lengthToCopy, lengthToCopy);
|
||||
#else
|
||||
nsCharTraits<typename OutputIterator::value_type>::move(result.get()-lengthToCopy, last.get()-lengthToCopy, lengthToCopy);
|
||||
#endif
|
||||
|
||||
last.advance( -PRInt32(lengthToCopy) );
|
||||
result.advance( -PRInt32(lengthToCopy) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // !defined(nsAlgorithm_h___)
|
||||
@@ -1,368 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 strings.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
/* nsBufferHandle.h --- the collection of classes that describe the atomic hunks of strings */
|
||||
|
||||
#ifndef nsBufferHandle_h___
|
||||
#define nsBufferHandle_h___
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
// for |ptrdiff_t|
|
||||
|
||||
#include "prtypes.h"
|
||||
// for |PRBool|
|
||||
|
||||
#include "nsDebug.h"
|
||||
// for |NS_ASSERTION|
|
||||
|
||||
#include "nscore.h"
|
||||
// for |PRUnichar|, |NS_REINTERPRET_CAST|
|
||||
|
||||
#ifdef XP_WIN
|
||||
// VC++ erroneously warns about incompatible linkage in these templates
|
||||
// It's a lie, and it's bothersome. This |#pragma| quiets the warning.
|
||||
#pragma warning( disable: 4251 )
|
||||
#endif
|
||||
|
||||
/**
|
||||
The classes in this file are collectively called `buffer handles'.
|
||||
All buffer handles begin with a pointer-tuple that delimits the useful content of a
|
||||
hunk of string. A buffer handle that points to a sharable hunk of string data
|
||||
additionally has a field which multiplexes some flags and a reference count.
|
||||
|
||||
|
||||
ns[Const]BufferHandle nsSharedBufferHandle mFlexBufferHandle
|
||||
+-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
| mDataStart | | mDataStart | | mDataStart |
|
||||
+-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
| mDataEnd | | mDataEnd | | mDataEnd |
|
||||
+-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
| mFlags | | mFlags |
|
||||
+-----+-----+-----+-----+ +-----+-----+-----+-----+
|
||||
. mAllocator . | mStorageStart |
|
||||
......................... +-----+-----+-----+-----+
|
||||
| mStorageEnd |
|
||||
+-----+-----+-----+-----+
|
||||
. mAllocator .
|
||||
.........................
|
||||
|
||||
Given only a |ns[Const]BufferHandle|, there is no legal way to tell if it is sharable.
|
||||
In all cases, the data might immediately follow the handle in the same allocated block.
|
||||
From the |mFlags| field, you can tell exactly what configuration of a handle you
|
||||
actually have.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <class CharT>
|
||||
class nsBufferHandle
|
||||
{
|
||||
public:
|
||||
nsBufferHandle() { }
|
||||
nsBufferHandle( CharT* aDataStart, CharT* aDataEnd ) : mDataStart(aDataStart), mDataEnd(aDataEnd) { }
|
||||
|
||||
void DataStart( CharT* aNewDataStart ) { mDataStart = aNewDataStart; }
|
||||
CharT* DataStart() { return mDataStart; }
|
||||
const CharT* DataStart() const { return mDataStart; }
|
||||
|
||||
void DataEnd( CharT* aNewDataEnd ) { mDataEnd = aNewDataEnd; }
|
||||
CharT* DataEnd() { return mDataEnd; }
|
||||
const CharT* DataEnd() const { return mDataEnd; }
|
||||
|
||||
ptrdiff_t DataLength() const { return mDataEnd - mDataStart; }
|
||||
|
||||
protected:
|
||||
CharT* mDataStart;
|
||||
CharT* mDataEnd;
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
class nsConstBufferHandle
|
||||
{
|
||||
public:
|
||||
nsConstBufferHandle() { }
|
||||
nsConstBufferHandle( const CharT* aDataStart, const CharT* aDataEnd ) : mDataStart(aDataStart), mDataEnd(aDataEnd) { }
|
||||
|
||||
void DataStart( const CharT* aNewDataStart ) { mDataStart = aNewDataStart; }
|
||||
const CharT* DataStart() const { return mDataStart; }
|
||||
|
||||
void DataEnd( const CharT* aNewDataEnd ) { mDataEnd = aNewDataEnd; }
|
||||
const CharT* DataEnd() const { return mDataEnd; }
|
||||
|
||||
ptrdiff_t DataLength() const { return mDataEnd - mDataStart; }
|
||||
|
||||
protected:
|
||||
const CharT* mDataStart;
|
||||
const CharT* mDataEnd;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* string allocator stuff needs to move to its own file
|
||||
* also see http://bugzilla.mozilla.org/show_bug.cgi?id=70087
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
class nsStringAllocator
|
||||
{
|
||||
public:
|
||||
// more later
|
||||
virtual void Deallocate( CharT* ) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* the following two routines must be provided by the client embedding strings
|
||||
*/
|
||||
NS_COM nsStringAllocator<char>& StringAllocator_char();
|
||||
NS_COM nsStringAllocator<PRUnichar>& StringAllocator_wchar_t();
|
||||
|
||||
|
||||
/**
|
||||
* this traits class lets templated clients pick the appropriate non-template global allocator
|
||||
*/
|
||||
template <class T>
|
||||
struct nsStringAllocatorTraits
|
||||
{
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsStringAllocatorTraits<char>
|
||||
{
|
||||
static nsStringAllocator<char>& global_string_allocator() { return StringAllocator_char(); }
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsStringAllocatorTraits<PRUnichar>
|
||||
{
|
||||
static nsStringAllocator<PRUnichar>& global_string_allocator() { return StringAllocator_wchar_t(); }
|
||||
};
|
||||
|
||||
// end of string allocator stuff that needs to move
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <class CharT>
|
||||
class nsSharedBufferHandle
|
||||
: public nsBufferHandle<CharT>
|
||||
{
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
kIsShared = 0x08000000, // one reason _not_ to set this is for a stack based handle that wants to express `NULL'-ness et al
|
||||
kIsSingleAllocationWithBuffer = 0x04000000, // handle and buffer are one piece, no separate deallocation is possible for the buffer
|
||||
kIsStorageDefinedSeparately = 0x02000000, // i.e., we're using the ``flex'' structure defined below
|
||||
kIsUserAllocator = 0x01000000, // can't |delete|, call a hook instead
|
||||
|
||||
// the following flags are opaque to the string library itself
|
||||
kIsNULL = 0x80000000, // the most common request of external clients is a scheme by which they can express `NULL'-ness
|
||||
kImplementationFlagsMask = 0xF0000000, // 4 bits for use by site-implementations, e.g., for `NULL'-ness
|
||||
|
||||
kFlagsMask = 0xFF000000,
|
||||
kRefCountMask = 0x00FFFFFF
|
||||
};
|
||||
|
||||
public:
|
||||
nsSharedBufferHandle( CharT* aDataStart, CharT* aDataEnd )
|
||||
: nsBufferHandle<CharT>(aDataStart, aDataEnd)
|
||||
{
|
||||
mFlags = kIsShared;
|
||||
}
|
||||
|
||||
nsSharedBufferHandle( CharT* aDataStart, CharT* aDataEnd, CharT*, CharT*, PRBool isSingleAllocation )
|
||||
: nsBufferHandle<CharT>(aDataStart, aDataEnd)
|
||||
{
|
||||
mFlags = kIsShared;
|
||||
if ( isSingleAllocation )
|
||||
mFlags |= kIsSingleAllocationWithBuffer;
|
||||
}
|
||||
|
||||
~nsSharedBufferHandle();
|
||||
|
||||
void
|
||||
AcquireReference() const
|
||||
{
|
||||
nsSharedBufferHandle<CharT>* mutable_this = NS_CONST_CAST(nsSharedBufferHandle<CharT>*, this);
|
||||
mutable_this->set_refcount( get_refcount()+1 );
|
||||
}
|
||||
|
||||
void
|
||||
ReleaseReference() const
|
||||
{
|
||||
nsSharedBufferHandle<CharT>* mutable_this = NS_CONST_CAST(nsSharedBufferHandle<CharT>*, this);
|
||||
if ( !mutable_this->set_refcount( get_refcount()-1 ) )
|
||||
delete mutable_this;
|
||||
// hmm, what if |kIsUserAllocator| and |kIsSingleAllocationWithBuffer|?
|
||||
}
|
||||
|
||||
PRBool
|
||||
IsReferenced() const
|
||||
{
|
||||
return get_refcount() != 0;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
GetImplementationFlags() const
|
||||
{
|
||||
return mFlags & kImplementationFlagsMask;
|
||||
}
|
||||
|
||||
void
|
||||
SetImplementationFlags( PRUint32 aNewFlags )
|
||||
{
|
||||
mFlags = (mFlags & ~kImplementationFlagsMask) | (aNewFlags & kImplementationFlagsMask);
|
||||
}
|
||||
|
||||
protected:
|
||||
PRUint32 mFlags;
|
||||
|
||||
PRUint32
|
||||
get_refcount() const
|
||||
{
|
||||
return mFlags & kRefCountMask;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
set_refcount( PRUint32 aNewRefCount )
|
||||
{
|
||||
NS_ASSERTION(aNewRefCount <= kRefCountMask, "aNewRefCount <= kRefCountMask");
|
||||
|
||||
mFlags = (mFlags & kFlagsMask) | aNewRefCount;
|
||||
return aNewRefCount;
|
||||
}
|
||||
|
||||
nsStringAllocator<CharT>& get_allocator() const;
|
||||
};
|
||||
|
||||
|
||||
template <class CharT>
|
||||
class nsFlexBufferHandle
|
||||
: public nsSharedBufferHandle<CharT>
|
||||
{
|
||||
public:
|
||||
nsFlexBufferHandle( CharT* aDataStart, CharT* aDataEnd, CharT* aStorageStart, CharT* aStorageEnd )
|
||||
: nsSharedBufferHandle<CharT>(aDataStart, aDataEnd),
|
||||
mStorageStart(aStorageStart),
|
||||
mStorageEnd(aStorageEnd)
|
||||
{
|
||||
this->mFlags |= this->kIsStorageDefinedSeparately;
|
||||
}
|
||||
|
||||
void StorageStart( CharT* aNewStorageStart ) { mStorageStart = aNewStorageStart; }
|
||||
CharT* StorageStart() { return mStorageStart; }
|
||||
const CharT* StorageStart() const { return mStorageStart; }
|
||||
|
||||
void StorageEnd( CharT* aNewStorageEnd ) { mStorageEnd = aNewStorageEnd; }
|
||||
CharT* StorageEnd() { return mStorageEnd; }
|
||||
const CharT* StorageEnd() const { return mStorageEnd; }
|
||||
|
||||
ptrdiff_t StorageLength() const { return mStorageEnd - mStorageStart; }
|
||||
|
||||
protected:
|
||||
CharT* mStorageStart;
|
||||
CharT* mStorageEnd;
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
class nsSharedBufferHandleWithAllocator
|
||||
: public nsSharedBufferHandle<CharT>
|
||||
{
|
||||
public:
|
||||
nsSharedBufferHandleWithAllocator( CharT* aDataStart, CharT* aDataEnd, nsStringAllocator<CharT>& aAllocator )
|
||||
: nsSharedBufferHandle<CharT>(aDataStart, aDataEnd),
|
||||
mAllocator(aAllocator)
|
||||
{
|
||||
this->mFlags |= this->kIsUserAllocator;
|
||||
}
|
||||
|
||||
nsStringAllocator<CharT>& get_allocator() const { return mAllocator; }
|
||||
|
||||
protected:
|
||||
nsStringAllocator<CharT>& mAllocator;
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
class nsFlexBufferHandleWithAllocator
|
||||
: public nsFlexBufferHandle<CharT>
|
||||
{
|
||||
public:
|
||||
nsFlexBufferHandleWithAllocator( CharT* aDataStart, CharT* aDataEnd,
|
||||
CharT* aStorageStart, CharT* aStorageEnd,
|
||||
nsStringAllocator<CharT>& aAllocator )
|
||||
: nsFlexBufferHandle<CharT>(aDataStart, aDataEnd, aStorageStart, aStorageEnd),
|
||||
mAllocator(aAllocator)
|
||||
{
|
||||
this->mFlags |= this->kIsUserAllocator;
|
||||
}
|
||||
|
||||
nsStringAllocator<CharT>& get_allocator() const { return mAllocator; }
|
||||
|
||||
protected:
|
||||
nsStringAllocator<CharT>& mAllocator;
|
||||
};
|
||||
|
||||
|
||||
template <class CharT>
|
||||
nsStringAllocator<CharT>&
|
||||
nsSharedBufferHandle<CharT>::get_allocator() const
|
||||
// really don't want this to be |inline|
|
||||
{
|
||||
if ( mFlags & kIsUserAllocator )
|
||||
{
|
||||
if ( mFlags & kIsStorageDefinedSeparately )
|
||||
return NS_REINTERPRET_CAST(const nsFlexBufferHandleWithAllocator<CharT>*, this)->get_allocator();
|
||||
else
|
||||
return NS_REINTERPRET_CAST(const nsSharedBufferHandleWithAllocator<CharT>*, this)->get_allocator();
|
||||
}
|
||||
|
||||
return nsStringAllocatorTraits<CharT>::global_string_allocator();
|
||||
}
|
||||
|
||||
|
||||
template <class CharT>
|
||||
nsSharedBufferHandle<CharT>::~nsSharedBufferHandle()
|
||||
// really don't want this to be |inline|
|
||||
{
|
||||
NS_ASSERTION(!IsReferenced(), "!IsReferenced()");
|
||||
|
||||
if ( !(mFlags & kIsSingleAllocationWithBuffer) )
|
||||
{
|
||||
CharT* string_storage = this->mDataStart;
|
||||
if ( mFlags & kIsStorageDefinedSeparately )
|
||||
string_storage = NS_REINTERPRET_CAST(nsFlexBufferHandle<CharT>*, this)->StorageStart();
|
||||
|
||||
get_allocator().Deallocate(string_storage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // !defined(nsBufferHandle_h___)
|
||||
@@ -1,186 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 strings.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsBufferHandleUtils_h___
|
||||
#define nsBufferHandleUtils_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsStringTraits_h___
|
||||
#include "nsStringTraits.h"
|
||||
#endif
|
||||
|
||||
#include <new.h>
|
||||
// for placement |new|
|
||||
|
||||
|
||||
template <class CharT>
|
||||
class nsAutoBufferHandle
|
||||
{
|
||||
public:
|
||||
nsAutoBufferHandle() : mHandle(0) { }
|
||||
|
||||
nsAutoBufferHandle( const nsAutoBufferHandle<CharT>& aOther )
|
||||
: mHandle(aOther.get())
|
||||
{
|
||||
if ( mHandle )
|
||||
mHandle->AcquireReference();
|
||||
}
|
||||
|
||||
explicit
|
||||
nsAutoBufferHandle( const nsSharedBufferHandle<CharT>* aHandle )
|
||||
: mHandle( NS_CONST_CAST(nsSharedBufferHandle<CharT>*, aHandle) )
|
||||
{
|
||||
if ( mHandle )
|
||||
mHandle->AcquireReference();
|
||||
}
|
||||
|
||||
~nsAutoBufferHandle()
|
||||
{
|
||||
if ( mHandle )
|
||||
mHandle->ReleaseReference();
|
||||
}
|
||||
|
||||
nsAutoBufferHandle<CharT>&
|
||||
operator=( const nsSharedBufferHandle<CharT>* rhs )
|
||||
{
|
||||
nsSharedBufferHandle<CharT>* old_handle = mHandle;
|
||||
if ( (mHandle = NS_CONST_CAST(nsSharedBufferHandle<CharT>*, rhs)) )
|
||||
mHandle->AcquireReference();
|
||||
if ( old_handle )
|
||||
old_handle->ReleaseReference();
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsAutoBufferHandle<CharT>&
|
||||
operator=( const nsAutoBufferHandle<CharT>& rhs )
|
||||
{
|
||||
return operator=(rhs.get());
|
||||
}
|
||||
|
||||
nsSharedBufferHandle<CharT>*
|
||||
get() const
|
||||
{
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
operator nsSharedBufferHandle<CharT>*() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
nsSharedBufferHandle<CharT>*
|
||||
operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
private:
|
||||
nsSharedBufferHandle<CharT>* mHandle;
|
||||
};
|
||||
|
||||
|
||||
template <class HandleT, class CharT>
|
||||
inline
|
||||
size_t
|
||||
NS_AlignedHandleSize( const HandleT*, const CharT* )
|
||||
{
|
||||
// figure out the number of bytes needed the |HandleT| part, including padding to correctly align the data part
|
||||
return ((sizeof(HandleT) + sizeof(CharT) - 1) / sizeof(CharT)) * sizeof(CharT);
|
||||
}
|
||||
|
||||
template <class HandleT, class CharT>
|
||||
inline
|
||||
const CharT*
|
||||
NS_DataAfterHandle( const HandleT* aHandlePtr, const CharT* aDummyCharTPtr )
|
||||
{
|
||||
typedef const CharT* CharT_ptr;
|
||||
return CharT_ptr(NS_STATIC_CAST(const unsigned char*, aHandlePtr) + NS_AlignedHandleSize(aHandlePtr, aDummyCharTPtr));
|
||||
}
|
||||
|
||||
template <class HandleT, class CharT>
|
||||
inline
|
||||
CharT*
|
||||
NS_DataAfterHandle( HandleT* aHandlePtr, const CharT* aDummyCharTPtr )
|
||||
{
|
||||
typedef CharT* CharT_ptr;
|
||||
return CharT_ptr(NS_STATIC_CAST(unsigned char*, aHandlePtr) + NS_AlignedHandleSize(aHandlePtr, aDummyCharTPtr));
|
||||
}
|
||||
|
||||
template <class HandleT, class StringT>
|
||||
HandleT*
|
||||
NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, PRUint32 aAdditionalCapacity, const StringT* aDataSource )
|
||||
{
|
||||
typedef typename StringT::char_type char_type;
|
||||
typedef char_type* char_ptr;
|
||||
|
||||
// figure out the number of bytes needed the |HandleT| part, including padding to correctly align the data part
|
||||
size_t handle_size = NS_AlignedHandleSize(aDummyHandlePtr, char_ptr(0));
|
||||
|
||||
// figure out how many |char_type|s wee need to fit in the data part
|
||||
size_t data_length = aDataSource? aDataSource->Length() : 0;
|
||||
size_t buffer_length = data_length + aAdditionalCapacity;
|
||||
|
||||
// how many bytes is that (including a zero-terminator so we can claim to be flat)?
|
||||
size_t buffer_size = buffer_length * sizeof(char_type);
|
||||
|
||||
|
||||
HandleT* result = 0;
|
||||
void* handle_ptr = ::operator new(handle_size + buffer_size);
|
||||
|
||||
if ( handle_ptr )
|
||||
{
|
||||
char_ptr data_start_ptr = char_ptr(NS_STATIC_CAST(unsigned char*, handle_ptr) + handle_size);
|
||||
char_ptr data_end_ptr = data_start_ptr + data_length;
|
||||
char_ptr buffer_end_ptr = data_start_ptr + buffer_length;
|
||||
|
||||
char_ptr toBegin = data_start_ptr;
|
||||
|
||||
if ( data_length )
|
||||
{
|
||||
typename StringT::const_iterator fromBegin, fromEnd;
|
||||
copy_string(aDataSource->BeginReading(fromBegin), aDataSource->EndReading(fromEnd), toBegin);
|
||||
}
|
||||
|
||||
// and if the caller bothered asking for a buffer bigger than their string, we'll zero-terminate
|
||||
if ( aAdditionalCapacity > 0 )
|
||||
*toBegin = char_type(0);
|
||||
|
||||
result = new (handle_ptr) HandleT(data_start_ptr, data_end_ptr, data_start_ptr, buffer_end_ptr, PR_TRUE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class HandleT, class StringT>
|
||||
inline
|
||||
HandleT*
|
||||
NS_AllocateContiguousHandleWithData( const HandleT* aDummyHandlePtr, const StringT& aDataSource, PRUint32 aAdditionalCapacity )
|
||||
{
|
||||
return NS_AllocateContiguousHandleWithData(aDummyHandlePtr, aAdditionalCapacity, &aDataSource);
|
||||
}
|
||||
|
||||
#endif // !defined(nsBufferHandleUtils_h___)
|
||||
@@ -1,709 +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.1 (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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsCharTraits_h___
|
||||
#define nsCharTraits_h___
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
// for |EOF|, |WEOF|
|
||||
|
||||
#include <string.h>
|
||||
// for |memcpy|, et al
|
||||
|
||||
#ifndef nscore_h___
|
||||
#include "nscore.h"
|
||||
// for |PRUnichar|
|
||||
#endif
|
||||
|
||||
#ifndef nsStringIteratorUtils_h___
|
||||
#include "nsStringIteratorUtils.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CPP_BOOL
|
||||
typedef bool nsCharTraits_bool;
|
||||
#else
|
||||
typedef PRBool nsCharTraits_bool;
|
||||
#endif
|
||||
|
||||
template <class CharT>
|
||||
struct nsCharTraits
|
||||
{
|
||||
typedef CharT char_type;
|
||||
typedef char incompatible_char_type;
|
||||
|
||||
static
|
||||
void
|
||||
assign( char_type& lhs, const char_type& rhs )
|
||||
{
|
||||
lhs = rhs;
|
||||
}
|
||||
|
||||
|
||||
// integer representation of characters:
|
||||
|
||||
typedef int int_type;
|
||||
|
||||
static
|
||||
char_type
|
||||
to_char_type( const int_type& c )
|
||||
{
|
||||
return char_type(c);
|
||||
}
|
||||
|
||||
static
|
||||
int_type
|
||||
to_int_type( const char_type& c )
|
||||
{
|
||||
return int_type(c);
|
||||
}
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
eq_int_type( const int_type& lhs, const int_type& rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
|
||||
// |char_type| comparisons:
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
eq( const char_type& lhs, const char_type& rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
lt( const char_type& lhs, const char_type& rhs )
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
|
||||
// operations on s[n] arrays:
|
||||
|
||||
static
|
||||
char_type*
|
||||
copy( char_type* s1, const char_type* s2, size_t n )
|
||||
{
|
||||
char_type* result = s1;
|
||||
while ( n-- )
|
||||
assign(*s1++, *s2++);
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
char_type*
|
||||
move( char_type* s1, const char_type* s2, size_t n )
|
||||
{
|
||||
char_type* result = s1;
|
||||
|
||||
if ( n )
|
||||
{
|
||||
if ( s2 > s1 )
|
||||
copy(s1, s2, n);
|
||||
else
|
||||
{
|
||||
s1 += n;
|
||||
s2 += n;
|
||||
while ( n-- )
|
||||
assign(*--s1, *--s2);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
char_type*
|
||||
assign( char_type* s, size_t n, const char_type& c )
|
||||
{
|
||||
char_type* result = s;
|
||||
while ( n-- )
|
||||
assign(*s++, c);
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
compare( const char_type* s1, const char_type* s2, size_t n )
|
||||
{
|
||||
for ( ; n--; ++s1, ++s2 )
|
||||
{
|
||||
if ( lt(*s1, *s2) )
|
||||
return -1;
|
||||
if ( lt(*s2, *s1) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
size_t
|
||||
length( const char_type* s )
|
||||
{
|
||||
size_t result = 0;
|
||||
while ( !eq(*s++, CharT(0)) )
|
||||
++result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
const char_type*
|
||||
find( const char_type* s, size_t n, const char_type& c )
|
||||
{
|
||||
while ( n-- )
|
||||
{
|
||||
if ( eq(*s, c) )
|
||||
return s;
|
||||
++s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// I/O related:
|
||||
|
||||
typedef streamoff off_type;
|
||||
typedef streampos pos_type;
|
||||
typedef mbstate_t state_type;
|
||||
|
||||
static
|
||||
int_type
|
||||
eof()
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
|
||||
static
|
||||
int_type
|
||||
not_eof( const int_type& c )
|
||||
{
|
||||
return eq_int_type(c, eof()) ? ~eof() : c;
|
||||
}
|
||||
|
||||
// static state_type get_state( pos_type );
|
||||
#endif
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsCharTraits<char>
|
||||
{
|
||||
typedef char char_type;
|
||||
typedef PRUnichar incompatible_char_type;
|
||||
|
||||
static
|
||||
void
|
||||
assign( char& lhs, char rhs )
|
||||
{
|
||||
lhs = rhs;
|
||||
}
|
||||
|
||||
|
||||
// integer representation of characters:
|
||||
|
||||
typedef int int_type;
|
||||
|
||||
static
|
||||
char
|
||||
to_char_type( int c )
|
||||
{
|
||||
return char(c);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
to_int_type( char c )
|
||||
{
|
||||
return int( NS_STATIC_CAST(unsigned char, c) );
|
||||
}
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
eq_int_type( int lhs, int rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
|
||||
// |char_type| comparisons:
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
eq( char lhs, char rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
lt( char lhs, char rhs )
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
|
||||
// operations on s[n] arrays:
|
||||
|
||||
static
|
||||
char*
|
||||
move( char* s1, const char* s2, size_t n )
|
||||
{
|
||||
return NS_STATIC_CAST(char*, memmove(s1, s2, n));
|
||||
}
|
||||
|
||||
static
|
||||
char*
|
||||
copy( char* s1, const char* s2, size_t n )
|
||||
{
|
||||
return NS_STATIC_CAST(char*, memcpy(s1, s2, n));
|
||||
}
|
||||
|
||||
static
|
||||
char*
|
||||
assign( char* s, size_t n, char c )
|
||||
{
|
||||
return NS_STATIC_CAST(char*, memset(s, to_int_type(c), n));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
compare( const char* s1, const char* s2, size_t n )
|
||||
{
|
||||
return memcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
static
|
||||
size_t
|
||||
length( const char* s )
|
||||
{
|
||||
return strlen(s);
|
||||
}
|
||||
|
||||
static
|
||||
const char*
|
||||
find( const char* s, size_t n, char c )
|
||||
{
|
||||
return NS_REINTERPRET_CAST(const char*, memchr(s, to_int_type(c), n));
|
||||
}
|
||||
|
||||
#if 0
|
||||
// I/O related:
|
||||
|
||||
typedef streamoff off_type;
|
||||
typedef streampos pos_type;
|
||||
typedef mbstate_t state_type;
|
||||
|
||||
static
|
||||
int_type
|
||||
eof()
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
not_eof( int c )
|
||||
{
|
||||
return c==eof() ? ~eof() : c;
|
||||
}
|
||||
|
||||
// static state_type get_state( pos_type );
|
||||
#endif
|
||||
};
|
||||
|
||||
#if 0
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsCharTraits<wchar_t>
|
||||
{
|
||||
typedef wchar_t char_type;
|
||||
|
||||
static
|
||||
void
|
||||
assign( wchar_t& lhs, wchar_t rhs )
|
||||
{
|
||||
lhs = rhs;
|
||||
}
|
||||
|
||||
|
||||
// integer representation of characters:
|
||||
|
||||
typedef wint_t int_type;
|
||||
|
||||
static
|
||||
wchar_t
|
||||
to_char_type( int_type c )
|
||||
{
|
||||
return wchar_t(c);
|
||||
}
|
||||
|
||||
static
|
||||
int_type
|
||||
to_int_type( wchar_t c )
|
||||
{
|
||||
return int_type(c);
|
||||
}
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
eq_int_type( int_type lhs, int_type rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
|
||||
// |char_type| comparisons:
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
eq( wchar_t lhs, wchar_t rhs )
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static
|
||||
nsCharTraits_bool
|
||||
lt( wchar_t lhs, wchar_t rhs )
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
|
||||
// operations on s[n] arrays:
|
||||
|
||||
static
|
||||
wchar_t*
|
||||
move( wchar_t* s1, const wchar_t* s2, size_t n )
|
||||
{
|
||||
return NS_STATIC_CAST(wchar_t*, wmemmove(s1, s2, n));
|
||||
}
|
||||
|
||||
static
|
||||
wchar_t*
|
||||
copy( wchar_t* s1, const wchar_t* s2, size_t n )
|
||||
{
|
||||
return NS_STATIC_CAST(wchar_t*, wmemcpy(s1, s2, n));
|
||||
}
|
||||
|
||||
static
|
||||
wchar_t*
|
||||
assign( wchar_t* s, size_t n, wchar_t c )
|
||||
{
|
||||
return NS_STATIC_CAST(wchar_t*, wmemset(s, to_int_type(c), n));
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
compare( const wchar_t* s1, const wchar_t* s2, size_t n )
|
||||
{
|
||||
return wmemcmp(s1, s2, n);
|
||||
}
|
||||
|
||||
static
|
||||
size_t
|
||||
length( const wchar_t* s )
|
||||
{
|
||||
return wcslen(s);
|
||||
}
|
||||
|
||||
static
|
||||
const wchar_t*
|
||||
find( const wchar_t* s, size_t n, wchar_t c )
|
||||
{
|
||||
return NS_REINTERPRET_CAST(const wchar_t*, wmemchr(s, to_int_type(c), n));
|
||||
}
|
||||
|
||||
#if 0
|
||||
// I/O related:
|
||||
|
||||
typedef streamoff off_type;
|
||||
typedef streampos pos_type;
|
||||
typedef mbstate_t state_type;
|
||||
|
||||
static
|
||||
int_type
|
||||
eof()
|
||||
{
|
||||
return WEOF;
|
||||
}
|
||||
|
||||
static
|
||||
int_type
|
||||
not_eof( int_type c )
|
||||
{
|
||||
return c==eof() ? ~eof() : c;
|
||||
}
|
||||
|
||||
// static state_type get_state( pos_type );
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class InputIterator>
|
||||
struct nsCharSourceTraits
|
||||
{
|
||||
typedef typename InputIterator::difference_type difference_type;
|
||||
|
||||
#if 0
|
||||
static
|
||||
PRUint32
|
||||
distance( const InputIterator& first, const InputIterator& last )
|
||||
{
|
||||
// ...
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( const InputIterator& iter )
|
||||
{
|
||||
return iter.size_forward();
|
||||
}
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( const InputIterator& first, const InputIterator& last )
|
||||
{
|
||||
return PRUint32(SameFragment(first, last) ? last.get()-first.get() : first.size_forward());
|
||||
}
|
||||
|
||||
static
|
||||
const typename InputIterator::value_type*
|
||||
read( const InputIterator& iter )
|
||||
{
|
||||
return iter.get();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
advance( InputIterator& s, difference_type n )
|
||||
{
|
||||
s.advance(n);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
|
||||
|
||||
template <class CharT>
|
||||
struct nsCharSourceTraits<CharT*>
|
||||
{
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
#if 0
|
||||
static
|
||||
PRUint32
|
||||
distance( CharT* first, CharT* last )
|
||||
{
|
||||
return PRUint32(last-first);
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( CharT* s )
|
||||
{
|
||||
return PRUint32(nsCharTraits<CharT>::length(s));
|
||||
// return numeric_limits<PRUint32>::max();
|
||||
}
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( CharT* first, CharT* last )
|
||||
{
|
||||
return PRUint32(last-first);
|
||||
}
|
||||
|
||||
static
|
||||
const CharT*
|
||||
read( CharT* s )
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
advance( CharT*& s, difference_type n )
|
||||
{
|
||||
s += n;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsCharSourceTraits<const char*>
|
||||
{
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
#if 0
|
||||
static
|
||||
PRUint32
|
||||
distance( const char* first, const char* last )
|
||||
{
|
||||
return PRUint32(last-first);
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( const char* s )
|
||||
{
|
||||
return PRUint32(nsCharTraits<char>::length(s));
|
||||
// return numeric_limits<PRUint32>::max();
|
||||
}
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( const char* first, const char* last )
|
||||
{
|
||||
return PRUint32(last-first);
|
||||
}
|
||||
|
||||
static
|
||||
const char*
|
||||
read( const char* s )
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
advance( const char*& s, difference_type n )
|
||||
{
|
||||
s += n;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsCharSourceTraits<const PRUnichar*>
|
||||
{
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
#if 0
|
||||
static
|
||||
PRUint32
|
||||
distance( const PRUnichar* first, const PRUnichar* last )
|
||||
{
|
||||
return PRUint32(last-first);
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( const PRUnichar* s )
|
||||
{
|
||||
return PRUint32(nsCharTraits<PRUnichar>::length(s));
|
||||
// return numeric_limits<PRUint32>::max();
|
||||
}
|
||||
|
||||
static
|
||||
PRUint32
|
||||
readable_distance( const PRUnichar* first, const PRUnichar* last )
|
||||
{
|
||||
return PRUint32(last-first);
|
||||
}
|
||||
|
||||
static
|
||||
const PRUnichar*
|
||||
read( const PRUnichar* s )
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
advance( const PRUnichar*& s, difference_type n )
|
||||
{
|
||||
s += n;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
template <class OutputIterator>
|
||||
struct nsCharSinkTraits
|
||||
{
|
||||
static
|
||||
PRUint32
|
||||
write( OutputIterator& iter, const typename OutputIterator::value_type* s, PRUint32 n )
|
||||
{
|
||||
return iter.write(s, n);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
|
||||
|
||||
template <class CharT>
|
||||
struct nsCharSinkTraits<CharT*>
|
||||
{
|
||||
static
|
||||
PRUint32
|
||||
write( CharT*& iter, const CharT* s, PRUint32 n )
|
||||
{
|
||||
nsCharTraits<CharT>::move(iter, s, n);
|
||||
iter += n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsCharSinkTraits<char*>
|
||||
{
|
||||
static
|
||||
PRUint32
|
||||
write( char*& iter, const char* s, PRUint32 n )
|
||||
{
|
||||
nsCharTraits<char>::move(iter, s, n);
|
||||
iter += n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsCharSinkTraits<PRUnichar*>
|
||||
{
|
||||
static
|
||||
PRUint32
|
||||
write( PRUnichar*& iter, const PRUnichar* s, PRUint32 n )
|
||||
{
|
||||
nsCharTraits<PRUnichar>::move(iter, s, n);
|
||||
iter += n;
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // !defined(nsCharTraits_h___)
|
||||
@@ -1,269 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsDependentConcatenation.h --- string concatenation machinery lives here, but don't include this file
|
||||
directly, always get it by including either "nsAString.h" or one of the compatibility headers */
|
||||
|
||||
#ifndef nsDependentConcatenation_h___
|
||||
#define nsDependentConcatenation_h___
|
||||
|
||||
/**
|
||||
NOT FOR USE BY HUMANS
|
||||
|
||||
Instances of this class only exist as anonymous temporary results from |operator+()|.
|
||||
This is the machinery that makes string concatenation efficient. No allocations or
|
||||
character copies are required unless and until a final assignment is made. It works
|
||||
its magic by overriding and forwarding calls to |GetReadableFragment()|.
|
||||
|
||||
Note: |nsDependentConcatenation| imposes some limits on string concatenation with |operator+()|.
|
||||
- no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33|
|
||||
- left to right evaluation is required ... do not use parentheses to override this
|
||||
|
||||
In practice, neither of these is onerous. Parentheses do not change the semantics of the
|
||||
concatenation, only the order in which the result is assembled ... so there's no reason
|
||||
for a user to need to control it. Too many strings summed together can easily be worked
|
||||
around with an intermediate assignment. I wouldn't have the parentheses limitation if I
|
||||
assigned the identifier mask starting at the top, the first time anybody called
|
||||
|GetReadableFragment()|.
|
||||
*/
|
||||
|
||||
class NS_COM nsDependentConcatenation
|
||||
: public nsAPromiseString
|
||||
{
|
||||
public:
|
||||
typedef nsDependentConcatenation self_type;
|
||||
typedef PRUnichar char_type;
|
||||
typedef nsAString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const char_type* GetReadableFragment( nsReadableFragment<char_type>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char_type* GetWritableFragment( nsWritableFragment<char_type>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
enum { kLeftString, kRightString };
|
||||
|
||||
int
|
||||
GetCurrentStringFromFragment( const nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
return (aFragment.GetIDAsInt() & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetLeftStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.SetID(aFragment.GetIDAsInt() & ~mFragmentIdentifierMask);
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetRightStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.SetID(aFragment.GetIDAsInt() | mFragmentIdentifierMask);
|
||||
return kRightString;
|
||||
}
|
||||
|
||||
public:
|
||||
nsDependentConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 )
|
||||
: mFragmentIdentifierMask(aMask)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
nsDependentConcatenation( const self_type& aLeftString, const string_type& aRightString )
|
||||
: mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
// nsDependentConcatenation( const self_type& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsDependentConcatenation(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation
|
||||
|
||||
public:
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool IsDependentOn( const string_type& ) const;
|
||||
// virtual PRBool PromisesExactly( const string_type& ) const;
|
||||
|
||||
// const self_type operator+( const string_type& rhs ) const;
|
||||
|
||||
PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; }
|
||||
|
||||
private:
|
||||
void operator+( const self_type& ); // NOT TO BE IMPLEMENTED
|
||||
// making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)|
|
||||
// which would break the algorithm for distributing bits in the fragment identifier
|
||||
|
||||
private:
|
||||
const string_type* mStrings[2];
|
||||
PRUint32 mFragmentIdentifierMask;
|
||||
};
|
||||
|
||||
class NS_COM nsDependentCConcatenation
|
||||
: public nsAPromiseCString
|
||||
{
|
||||
public:
|
||||
typedef nsDependentCConcatenation self_type;
|
||||
typedef char char_type;
|
||||
typedef nsACString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const char_type* GetReadableFragment( nsReadableFragment<char_type>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char_type* GetWritableFragment( nsWritableFragment<char_type>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
enum { kLeftString, kRightString };
|
||||
|
||||
int
|
||||
GetCurrentStringFromFragment( const nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
return (aFragment.GetIDAsInt() & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetLeftStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.SetID(aFragment.GetIDAsInt() & ~mFragmentIdentifierMask);
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetRightStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.SetID(aFragment.GetIDAsInt() | mFragmentIdentifierMask);
|
||||
return kRightString;
|
||||
}
|
||||
|
||||
public:
|
||||
nsDependentCConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 )
|
||||
: mFragmentIdentifierMask(aMask)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
nsDependentCConcatenation( const self_type& aLeftString, const string_type& aRightString )
|
||||
: mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
// nsDependentCConcatenation( const self_type& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsDependentCConcatenation(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation
|
||||
|
||||
public:
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool IsDependentOn( const string_type& ) const;
|
||||
// virtual PRBool PromisesExactly( const string_type& ) const;
|
||||
|
||||
// const self_type operator+( const string_type& rhs ) const;
|
||||
|
||||
PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; }
|
||||
|
||||
private:
|
||||
void operator+( const self_type& ); // NOT TO BE IMPLEMENTED
|
||||
// making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)|
|
||||
// which would break the algorithm for distributing bits in the fragment identifier
|
||||
|
||||
private:
|
||||
const string_type* mStrings[2];
|
||||
PRUint32 mFragmentIdentifierMask;
|
||||
};
|
||||
|
||||
/*
|
||||
How shall we provide |operator+()|?
|
||||
|
||||
What would it return? It has to return a stack based object, because the client will
|
||||
not be given an opportunity to handle memory management in an expression like
|
||||
|
||||
myWritableString = stringA + stringB + stringC;
|
||||
|
||||
...so the `obvious' answer of returning a new |nsSharedString| is no good. We could
|
||||
return an |nsString|, if that name were in scope here, though there's no telling what the client
|
||||
will really want to do with the result. What might be better, though,
|
||||
is to return a `promise' to concatenate some strings...
|
||||
|
||||
By making |nsDependentConcatenation| inherit from readable strings, we automatically handle
|
||||
assignment and other interesting uses within writable strings, plus we drastically reduce
|
||||
the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings
|
||||
in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work
|
||||
to implement the virtual functions of readables.
|
||||
*/
|
||||
|
||||
inline
|
||||
const nsDependentConcatenation
|
||||
operator+( const nsDependentConcatenation& lhs, const nsAString& rhs )
|
||||
{
|
||||
return nsDependentConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentCConcatenation
|
||||
operator+( const nsDependentCConcatenation& lhs, const nsACString& rhs )
|
||||
{
|
||||
return nsDependentCConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentConcatenation
|
||||
operator+( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return nsDependentConcatenation(lhs, rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentCConcatenation
|
||||
operator+( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return nsDependentCConcatenation(lhs, rhs);
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline
|
||||
const nsDependentConcatenation
|
||||
nsDependentConcatenation::operator+( const string_type& rhs ) const
|
||||
{
|
||||
return nsDependentConcatenation(*this, rhs, mFragmentIdentifierMask<<1);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentCConcatenation
|
||||
nsDependentCConcatenation::operator+( const string_type& rhs ) const
|
||||
{
|
||||
return nsDependentCConcatenation(*this, rhs, mFragmentIdentifierMask<<1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* !defined(nsDependentConcatenation_h___) */
|
||||
@@ -1,145 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsDependentString_h___
|
||||
#define nsDependentString_h___
|
||||
|
||||
#ifndef nsAFlatString_h___
|
||||
#include "nsAFlatString.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
...this class wraps a constant literal string and lets it act like an |const nsAString|.
|
||||
|
||||
Use it like this:
|
||||
|
||||
SomeFunctionTakingACString( nsDependentCString(myCharPtr) );
|
||||
|
||||
This class just holds a pointer. If you don't supply the length, it must calculate it.
|
||||
No copying or allocations are performed.
|
||||
|
||||
See also |NS_LITERAL_STRING| and |NS_LITERAL_CSTRING| when you have a quoted string you want to
|
||||
use as a |const nsAString|.
|
||||
*/
|
||||
|
||||
class NS_COM nsDependentString
|
||||
: public nsAFlatString
|
||||
{
|
||||
public:
|
||||
void
|
||||
Rebind( const PRUnichar* aPtr )
|
||||
{
|
||||
mHandle.DataStart(aPtr);
|
||||
mHandle.DataEnd(aPtr ? (aPtr+nsCharTraits<PRUnichar>::length(aPtr)) : 0);
|
||||
}
|
||||
|
||||
void
|
||||
Rebind( const PRUnichar* aStartPtr, const PRUnichar* aEndPtr )
|
||||
{
|
||||
mHandle.DataStart(aStartPtr);
|
||||
mHandle.DataEnd(aEndPtr);
|
||||
}
|
||||
|
||||
void
|
||||
Rebind( const PRUnichar* aPtr, PRUint32 aLength )
|
||||
{
|
||||
if ( aLength == PRUint32(-1) )
|
||||
{
|
||||
// NS_WARNING("Tell scc: Caller binding a dependent string doesn't know the real length. Please pick the appropriate call.");
|
||||
Rebind(aPtr);
|
||||
}
|
||||
else
|
||||
Rebind(aPtr, aPtr+aLength);
|
||||
}
|
||||
|
||||
nsDependentString( const PRUnichar* aStartPtr, const PRUnichar* aEndPtr ) { Rebind(aStartPtr, aEndPtr); }
|
||||
nsDependentString( const PRUnichar* aPtr, PRUint32 aLength ) { Rebind(aPtr, aLength); }
|
||||
explicit nsDependentString( const PRUnichar* aPtr ) { Rebind(aPtr); }
|
||||
|
||||
// nsDependentString( const nsDependentString& ); // auto-generated copy-constructor OK
|
||||
// ~nsDependentString(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsDependentString& ); // we're immutable, so no copy-assignment operator
|
||||
|
||||
public:
|
||||
virtual const nsBufferHandle<PRUnichar>* GetFlatBufferHandle() const { return NS_REINTERPRET_CAST(const nsBufferHandle<PRUnichar>*, &mHandle); }
|
||||
virtual const nsBufferHandle<PRUnichar>* GetBufferHandle() const { return NS_REINTERPRET_CAST(const nsBufferHandle<PRUnichar>*, &mHandle); }
|
||||
|
||||
private:
|
||||
nsConstBufferHandle<PRUnichar> mHandle;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class NS_COM nsDependentCString
|
||||
: public nsAFlatCString
|
||||
{
|
||||
public:
|
||||
void
|
||||
Rebind( const char* aPtr )
|
||||
{
|
||||
mHandle.DataStart(aPtr);
|
||||
mHandle.DataEnd(aPtr ? (aPtr+nsCharTraits<char>::length(aPtr)) : 0);
|
||||
}
|
||||
|
||||
void
|
||||
Rebind( const char* aStartPtr, const char* aEndPtr )
|
||||
{
|
||||
mHandle.DataStart(aStartPtr);
|
||||
mHandle.DataEnd(aEndPtr);
|
||||
}
|
||||
|
||||
void
|
||||
Rebind( const char* aPtr, PRUint32 aLength )
|
||||
{
|
||||
if ( aLength == PRUint32(-1) )
|
||||
{
|
||||
// NS_WARNING("Tell scc: Caller binding a dependent string doesn't know the real length. Please pick the appropriate call.");
|
||||
Rebind(aPtr);
|
||||
}
|
||||
else
|
||||
Rebind(aPtr, aPtr+aLength);
|
||||
}
|
||||
|
||||
nsDependentCString( const char* aStartPtr, const char* aEndPtr ) { Rebind(aStartPtr, aEndPtr); }
|
||||
nsDependentCString( const char* aPtr, PRUint32 aLength ) { Rebind(aPtr, aLength); }
|
||||
explicit nsDependentCString( const char* aPtr ) { Rebind(aPtr); }
|
||||
|
||||
// nsDependentCString( const nsDependentCString& ); // auto-generated copy-constructor OK
|
||||
// ~nsDependentCString(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsDependentCString& ); // we're immutable, so no copy-assignment operator
|
||||
|
||||
public:
|
||||
virtual const nsBufferHandle<char>* GetFlatBufferHandle() const { return NS_REINTERPRET_CAST(const nsBufferHandle<char>*, &mHandle); }
|
||||
virtual const nsBufferHandle<char>* GetBufferHandle() const { return NS_REINTERPRET_CAST(const nsBufferHandle<char>*, &mHandle); }
|
||||
|
||||
private:
|
||||
nsConstBufferHandle<char> mHandle;
|
||||
};
|
||||
|
||||
#endif /* !defined(nsDependentString_h___) */
|
||||
@@ -1,182 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsDependentSubstring_h___
|
||||
#define nsDependentSubstring_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsStringTraits_h___
|
||||
#include "nsStringTraits.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsDependentSubstring
|
||||
//
|
||||
|
||||
class NS_COM nsDependentSubstring
|
||||
: public nsAPromiseString
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsDependentConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsDependentConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetReadableFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef nsAString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
public:
|
||||
nsDependentSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
: mString(aString),
|
||||
mStartPos( NS_MIN(aStartPos, aString.Length()) ),
|
||||
mLength( NS_MIN(aLength, aString.Length()-mStartPos) )
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsDependentSubstring( const const_iterator& aStart, const const_iterator& aEnd )
|
||||
: mString(aStart.string())
|
||||
{
|
||||
const_iterator zeroPoint;
|
||||
mString.BeginReading(zeroPoint);
|
||||
mStartPos = Distance(zeroPoint, aStart);
|
||||
mLength = Distance(aStart, aEnd);
|
||||
}
|
||||
|
||||
// nsDependentSubstring( const nsDependentSubstring& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsDependentSubstring(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsDependentSubstring& ); // we're immutable, you can't assign into a substring
|
||||
|
||||
public:
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool IsDependentOn( const string_type& aString ) const { return mString.IsDependentOn(aString); }
|
||||
|
||||
private:
|
||||
const string_type& mString;
|
||||
PRUint32 mStartPos;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
class NS_COM nsDependentCSubstring
|
||||
: public nsAPromiseCString
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsDependentConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsDependentConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetReadableFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef nsACString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const char* GetReadableFragment( nsReadableFragment<char>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char* GetWritableFragment( nsWritableFragment<char>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
public:
|
||||
nsDependentCSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
: mString(aString),
|
||||
mStartPos( NS_MIN(aStartPos, aString.Length()) ),
|
||||
mLength( NS_MIN(aLength, aString.Length()-mStartPos) )
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsDependentCSubstring( const const_iterator& aStart, const const_iterator& aEnd )
|
||||
: mString(aStart.string())
|
||||
{
|
||||
const_iterator zeroPoint;
|
||||
mString.BeginReading(zeroPoint);
|
||||
mStartPos = Distance(zeroPoint, aStart);
|
||||
mLength = Distance(aStart, aEnd);
|
||||
}
|
||||
|
||||
// nsDependentCSubstring( const nsDependentCSubstring& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsDependentCSubstring(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsDependentCSubstring& ); // we're immutable, you can't assign into a substring
|
||||
|
||||
public:
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool IsDependentOn( const string_type& aString ) const { return mString.IsDependentOn(aString); }
|
||||
|
||||
private:
|
||||
const string_type& mString;
|
||||
PRUint32 mStartPos;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
const nsDependentCSubstring
|
||||
Substring( const nsACString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
{
|
||||
return nsDependentCSubstring(aString, aStartPos, aSubstringLength);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentSubstring
|
||||
Substring( const nsAString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
{
|
||||
return nsDependentSubstring(aString, aStartPos, aSubstringLength);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentCSubstring
|
||||
Substring( const nsReadingIterator<char>& aStart, const nsReadingIterator<char>& aEnd )
|
||||
{
|
||||
return nsDependentCSubstring(aStart, aEnd);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentSubstring
|
||||
Substring( const nsReadingIterator<PRUnichar>& aStart, const nsReadingIterator<PRUnichar>& aEnd )
|
||||
{
|
||||
return nsDependentSubstring(aStart, aEnd);
|
||||
}
|
||||
|
||||
|
||||
#endif /* !defined(nsDependentSubstring_h___) */
|
||||
@@ -1,69 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 XPCOM.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsFragmentedString_h___
|
||||
#define nsFragmentedString_h___
|
||||
|
||||
// WORK IN PROGRESS
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsSharedBufferList_h___
|
||||
#include "nsSharedBufferList.h"
|
||||
#endif
|
||||
|
||||
|
||||
class nsFragmentedString
|
||||
: public nsAString
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
protected:
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 );
|
||||
|
||||
public:
|
||||
nsFragmentedString() { }
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
|
||||
virtual void SetLength( PRUint32 aNewLength );
|
||||
// virtual void SetCapacity( PRUint32 aNewCapacity );
|
||||
|
||||
// virtual void Cut( PRUint32 cutStart, PRUint32 cutLength );
|
||||
|
||||
protected:
|
||||
// virtual void do_AssignFromReadable( const nsAString& );
|
||||
// virtual void do_AppendFromReadable( const nsAString& );
|
||||
// virtual void do_InsertFromReadable( const nsAString&, PRUint32 );
|
||||
// virtual void do_ReplaceFromReadable( PRUint32, PRUint32, const nsAString& );
|
||||
|
||||
private:
|
||||
nsSharedBufferList mBufferList;
|
||||
};
|
||||
|
||||
#endif // !defined(nsFragmentedString_h___)
|
||||
@@ -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 Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsLiteralString_h___
|
||||
#define nsLiteralString_h___
|
||||
|
||||
#ifndef nscore_h___
|
||||
#include "nscore.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsDependentString_h___
|
||||
#include "nsDependentString.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
inline
|
||||
const nsDependentString
|
||||
literal_string( const PRUnichar* aPtr )
|
||||
{
|
||||
return nsDependentString(aPtr);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentString
|
||||
literal_string( const PRUnichar* aPtr, PRUint32 aLength )
|
||||
{
|
||||
return nsDependentString(aPtr, aLength);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentCString
|
||||
literal_string( const char* aPtr )
|
||||
{
|
||||
return nsDependentCString(aPtr);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsDependentCString
|
||||
literal_string( const char* aPtr, PRUint32 aLength )
|
||||
{
|
||||
return nsDependentCString(aPtr, aLength);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CPP_2BYTE_WCHAR_T
|
||||
#define NS_L(s) L##s
|
||||
#define NS_MULTILINE_LITERAL_STRING(s) nsDependentString(NS_REINTERPRET_CAST(const PRUnichar*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
|
||||
#define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) nsDependentString n(NS_REINTERPRET_CAST(const PRUnichar*, s), PRUint32((sizeof(s)/sizeof(wchar_t))-1))
|
||||
#else
|
||||
#define NS_L(s) s
|
||||
#define NS_MULTILINE_LITERAL_STRING(s) NS_ConvertASCIItoUCS2(s, PRUint32(sizeof(s)-1))
|
||||
#define NS_NAMED_MULTILINE_LITERAL_STRING(n,s) NS_ConvertASCIItoUCS2 n(s, PRUint32(sizeof(s)-1))
|
||||
#endif
|
||||
|
||||
#define NS_LITERAL_STRING(s) NS_STATIC_CAST(const nsAFlatString&, NS_MULTILINE_LITERAL_STRING(NS_L(s)))
|
||||
#define NS_NAMED_LITERAL_STRING(n,s) NS_NAMED_MULTILINE_LITERAL_STRING(n,NS_L(s))
|
||||
|
||||
#define NS_LITERAL_CSTRING(s) nsDependentCString(s, PRUint32(sizeof(s)-1))
|
||||
#define NS_NAMED_LITERAL_CSTRING(n,s) nsDependentCString n(s, PRUint32(sizeof(s)-1))
|
||||
|
||||
#endif /* !defined(nsLiteralString_h___) */
|
||||
@@ -1,127 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsLocalString_h___
|
||||
#define nsLocalString_h___
|
||||
|
||||
#ifndef nsAFlatString_h___
|
||||
#include "nsAFlatString.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
...this class wraps a constant literal string and lets it act like an |nsAReadable...|.
|
||||
|
||||
Use it like this:
|
||||
|
||||
SomeFunctionTakingACString( nsLiteralCString("Hello, World!") );
|
||||
|
||||
With some tweaking, I think I can make this work as well...
|
||||
|
||||
SomeStringFunc( nsLiteralString( L"Hello, World!" ) );
|
||||
|
||||
This class just holds a pointer. If you don't supply the length, it must calculate it.
|
||||
No copying or allocations are performed.
|
||||
|
||||
|const nsLocalString&| appears frequently in interfaces because it
|
||||
allows the automatic conversion of a |PRUnichar*|.
|
||||
*/
|
||||
|
||||
class NS_COM nsLocalString
|
||||
: public nsAFlatString
|
||||
{
|
||||
public:
|
||||
|
||||
explicit
|
||||
nsLocalString( const PRUnichar* aLiteral )
|
||||
: mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits<PRUnichar>::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral))
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsLocalString( const PRUnichar* aLiteral, PRUint32 aLength )
|
||||
: mHandle(NS_CONST_CAST(PRUnichar*, aLiteral), NS_CONST_CAST(PRUnichar*, aLiteral)+aLength)
|
||||
{
|
||||
// This is an annoying hack. Callers should be fixed to use the other
|
||||
// constructor if they don't really know the length.
|
||||
if ( aLength == PRUint32(-1) )
|
||||
{
|
||||
// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor.");
|
||||
mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(PRUnichar*, aLiteral)+nsCharTraits<PRUnichar>::length(aLiteral)) : NS_CONST_CAST(PRUnichar*, aLiteral));
|
||||
}
|
||||
}
|
||||
|
||||
// nsLocalString( const nsLocalString& ); // auto-generated copy-constructor OK
|
||||
// ~nsLocalString(); // auto-generated destructor OK
|
||||
|
||||
virtual const nsBufferHandle<PRUnichar>* GetFlatBufferHandle() const { return &mHandle; }
|
||||
virtual const nsBufferHandle<PRUnichar>* GetBufferHandle() const { return &mHandle; }
|
||||
|
||||
private:
|
||||
nsBufferHandle<PRUnichar> mHandle;
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsLocalString& ); // we're immutable
|
||||
};
|
||||
|
||||
|
||||
|
||||
class NS_COM nsLocalCString
|
||||
: public nsAFlatCString
|
||||
{
|
||||
public:
|
||||
|
||||
explicit
|
||||
nsLocalCString( const char* aLiteral )
|
||||
: mHandle(NS_CONST_CAST(char*, aLiteral), aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits<char>::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral))
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsLocalCString( const char* aLiteral, PRUint32 aLength )
|
||||
: mHandle(NS_CONST_CAST(char*, aLiteral), NS_CONST_CAST(char*, aLiteral)+aLength)
|
||||
{
|
||||
// This is an annoying hack. Callers should be fixed to use the other
|
||||
// constructor if they don't really know the length.
|
||||
if ( aLength == PRUint32(-1) )
|
||||
{
|
||||
// NS_WARNING("Tell scc: Caller constructing a string doesn't know the real length. Please use the other constructor.");
|
||||
mHandle.DataEnd(aLiteral ? (NS_CONST_CAST(char*, aLiteral)+nsCharTraits<char>::length(aLiteral)) : NS_CONST_CAST(char*, aLiteral));
|
||||
}
|
||||
}
|
||||
|
||||
// nsLocalCString( const nsLocalCString& ); // auto-generated copy-constructor OK
|
||||
// ~nsLocalCString(); // auto-generated destructor OK
|
||||
|
||||
virtual const nsBufferHandle<char>* GetFlatBufferHandle() const { return &mHandle; }
|
||||
virtual const nsBufferHandle<char>* GetBufferHandle() const { return &mHandle; }
|
||||
|
||||
private:
|
||||
nsBufferHandle<char> mHandle;
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsLocalCString& ); // we're immutable
|
||||
};
|
||||
|
||||
#endif /* !defined(nsLocalString_h___) */
|
||||
@@ -1,96 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author:
|
||||
* Scott Collins <scc@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
|
||||
#ifndef nsPrintfCString_h___
|
||||
#define nsPrintfCString_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* |nsPrintfCString| lets you use a formated |printf| string as an |nsAReadableCString|.
|
||||
*
|
||||
* myCStr += nsPrintfCString("%f", 13.917);
|
||||
* // ...a general purpose substitute for |AppendFloat|
|
||||
*
|
||||
* For longer patterns, you'll want to use the constructor that takes a length
|
||||
*
|
||||
* nsPrintfCString(128, "%f, %f, %f, %f, %f, %f, %f, %i, %f", x, y, z, 3.2, j, k, l, 3, 3.1);
|
||||
*
|
||||
* Exceding the default size (which you must specify in the constructor, it is not determined)
|
||||
* causes an allocation, so avoid that. If your formatted string exceeds the allocated space, it is
|
||||
* cut off at the size of the buffer, no error is reported (and no out-of-bounds writing occurs).
|
||||
* This class is intended to be useful for numbers and short
|
||||
* strings, not arbitrary formatting of other strings (e.g., with %s). There is currently no
|
||||
* wide version of this class, since wide |printf| is not generally available. That means
|
||||
* to get a wide version of your formatted data, you must, e.g.,
|
||||
*
|
||||
* CopyASCIItoUCS2(nsPrintfCString("%f", 13.917"), myStr);
|
||||
*
|
||||
* That's another good reason to avoid this class for anything but numbers ... as strings can be
|
||||
* much more efficiently handled with |NS_LITERAL_[C]STRING| and |nsLiteral[C]String|.
|
||||
*/
|
||||
|
||||
class nsPrintfCString
|
||||
: public nsACString
|
||||
{
|
||||
enum { kLocalBufferSize=15 };
|
||||
// ought to be large enough for most things ... a |long long| needs at most 20 (so you'd better ask)
|
||||
// pinkerton suggests 7. We should measure and decide what's appropriate
|
||||
|
||||
|
||||
public:
|
||||
explicit nsPrintfCString( const char* format, ... );
|
||||
nsPrintfCString( size_t n, const char* format, ...);
|
||||
~nsPrintfCString();
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
|
||||
protected:
|
||||
virtual const char* GetReadableFragment( nsReadableFragment<char>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char* GetWritableFragment( nsWritableFragment<char>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
// virtual PRBool GetReadableFragment( nsReadableFragment<char>& aFragment, nsFragmentRequest aRequest ) const;
|
||||
|
||||
private:
|
||||
char* mStart;
|
||||
PRUint32 mLength;
|
||||
char mLocalBuffer[ kLocalBufferSize + 1 ];
|
||||
};
|
||||
|
||||
#endif // !defined(nsPrintfCString_h___)
|
||||
@@ -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 Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 strings.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsPrivateSharableString_h___
|
||||
#define nsPrivateSharableString_h___
|
||||
|
||||
#ifndef nsBufferHandle_h___
|
||||
#include "nsBufferHandle.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This class is part of the machinery that makes
|
||||
* most string implementations in this family share their underlying buffers
|
||||
* when convenient. It is _not_ part of the abstract string interface,
|
||||
* though other machinery interested in sharing buffers will know about it.
|
||||
*
|
||||
* Normal string clients must _never_ call routines from this interface.
|
||||
*/
|
||||
class NS_COM nsPrivateSharableString
|
||||
{
|
||||
public:
|
||||
typedef PRUnichar char_type;
|
||||
|
||||
public:
|
||||
virtual ~nsPrivateSharableString() {}
|
||||
|
||||
virtual PRUint32 GetImplementationFlags() const;
|
||||
virtual const nsBufferHandle<char_type>* GetFlatBufferHandle() const;
|
||||
virtual const nsBufferHandle<char_type>* GetBufferHandle() const;
|
||||
virtual const nsSharedBufferHandle<char_type>* GetSharedBufferHandle() const;
|
||||
|
||||
/**
|
||||
* |GetBufferHandle()| will return either |0|, or a reasonable pointer.
|
||||
* The meaning of |0| is that the string points to a non-contiguous or else empty representation.
|
||||
* Otherwise |GetBufferHandle()| returns a handle that points to the single contiguous hunk of characters
|
||||
* that make up this string.
|
||||
*/
|
||||
};
|
||||
|
||||
class NS_COM nsPrivateSharableCString
|
||||
{
|
||||
public:
|
||||
typedef char char_type;
|
||||
|
||||
public:
|
||||
virtual ~nsPrivateSharableCString() {}
|
||||
|
||||
virtual PRUint32 GetImplementationFlags() const;
|
||||
virtual const nsBufferHandle<char_type>* GetFlatBufferHandle() const;
|
||||
virtual const nsBufferHandle<char_type>* GetBufferHandle() const;
|
||||
virtual const nsSharedBufferHandle<char_type>* GetSharedBufferHandle() const;
|
||||
|
||||
/**
|
||||
* |GetBufferHandle()| will return either |0|, or a reasonable pointer.
|
||||
* The meaning of |0| is that the string points to a non-contiguous or else empty representation.
|
||||
* Otherwise |GetBufferHandle()| returns a handle that points to the single contiguous hunk of characters
|
||||
* that make up this string.
|
||||
*/
|
||||
};
|
||||
|
||||
#endif // !defined(nsPrivateSharableString_h___)
|
||||
@@ -1,269 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsPromiseConcatenation.h --- string concatenation machinery lives here, but don't include this file
|
||||
directly, always get it by including either "nsAString.h" or one of the compatibility headers */
|
||||
|
||||
#ifndef nsPromiseConcatenation_h___
|
||||
#define nsPromiseConcatenation_h___
|
||||
|
||||
/**
|
||||
NOT FOR USE BY HUMANS
|
||||
|
||||
Instances of this class only exist as anonymous temporary results from |operator+()|.
|
||||
This is the machinery that makes string concatenation efficient. No allocations or
|
||||
character copies are required unless and until a final assignment is made. It works
|
||||
its magic by overriding and forwarding calls to |GetReadableFragment()|.
|
||||
|
||||
Note: |nsPromiseConcatenation| imposes some limits on string concatenation with |operator+()|.
|
||||
- no more than 33 strings, e.g., |s1 + s2 + s3 + ... s32 + s33|
|
||||
- left to right evaluation is required ... do not use parentheses to override this
|
||||
|
||||
In practice, neither of these is onerous. Parentheses do not change the semantics of the
|
||||
concatenation, only the order in which the result is assembled ... so there's no reason
|
||||
for a user to need to control it. Too many strings summed together can easily be worked
|
||||
around with an intermediate assignment. I wouldn't have the parentheses limitation if I
|
||||
assigned the identifier mask starting at the top, the first time anybody called
|
||||
|GetReadableFragment()|.
|
||||
*/
|
||||
|
||||
class NS_COM nsPromiseConcatenation
|
||||
: public nsAPromiseString
|
||||
{
|
||||
public:
|
||||
typedef nsPromiseConcatenation self_type;
|
||||
typedef PRUnichar char_type;
|
||||
typedef nsAString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const char_type* GetReadableFragment( nsReadableFragment<char_type>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char_type* GetWritableFragment( nsWritableFragment<char_type>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
enum { kLeftString, kRightString };
|
||||
|
||||
int
|
||||
GetCurrentStringFromFragment( const nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetLeftStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask);
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetRightStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask);
|
||||
return kRightString;
|
||||
}
|
||||
|
||||
public:
|
||||
nsPromiseConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 )
|
||||
: mFragmentIdentifierMask(aMask)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
nsPromiseConcatenation( const self_type& aLeftString, const string_type& aRightString )
|
||||
: mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
// nsPromiseConcatenation( const self_type& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsPromiseConcatenation(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation
|
||||
|
||||
public:
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool Promises( const string_type& ) const;
|
||||
// virtual PRBool PromisesExactly( const string_type& ) const;
|
||||
|
||||
// const self_type operator+( const string_type& rhs ) const;
|
||||
|
||||
PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; }
|
||||
|
||||
private:
|
||||
void operator+( const self_type& ); // NOT TO BE IMPLEMENTED
|
||||
// making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)|
|
||||
// which would break the algorithm for distributing bits in the fragment identifier
|
||||
|
||||
private:
|
||||
const string_type* mStrings[2];
|
||||
PRUint32 mFragmentIdentifierMask;
|
||||
};
|
||||
|
||||
class NS_COM nsPromiseCConcatenation
|
||||
: public nsAPromiseCString
|
||||
{
|
||||
public:
|
||||
typedef nsPromiseCConcatenation self_type;
|
||||
typedef char char_type;
|
||||
typedef nsACString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const char_type* GetReadableFragment( nsReadableFragment<char_type>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char_type* GetWritableFragment( nsWritableFragment<char_type>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
enum { kLeftString, kRightString };
|
||||
|
||||
int
|
||||
GetCurrentStringFromFragment( const nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
return (NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & mFragmentIdentifierMask) ? kRightString : kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetLeftStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) & ~mFragmentIdentifierMask);
|
||||
return kLeftString;
|
||||
}
|
||||
|
||||
int
|
||||
SetRightStringInFragment( nsReadableFragment<char_type>& aFragment ) const
|
||||
{
|
||||
aFragment.mFragmentIdentifier = NS_REINTERPRET_CAST(void*, NS_REINTERPRET_CAST(PRUint32, aFragment.mFragmentIdentifier) | mFragmentIdentifierMask);
|
||||
return kRightString;
|
||||
}
|
||||
|
||||
public:
|
||||
nsPromiseCConcatenation( const string_type& aLeftString, const string_type& aRightString, PRUint32 aMask = 1 )
|
||||
: mFragmentIdentifierMask(aMask)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
nsPromiseCConcatenation( const self_type& aLeftString, const string_type& aRightString )
|
||||
: mFragmentIdentifierMask(aLeftString.mFragmentIdentifierMask<<1)
|
||||
{
|
||||
mStrings[kLeftString] = &aLeftString;
|
||||
mStrings[kRightString] = &aRightString;
|
||||
}
|
||||
|
||||
// nsPromiseCConcatenation( const self_type& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsPromiseCConcatenation(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const self_type& ); // we're immutable, you can't assign into a concatenation
|
||||
|
||||
public:
|
||||
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool Promises( const string_type& ) const;
|
||||
// virtual PRBool PromisesExactly( const string_type& ) const;
|
||||
|
||||
// const self_type operator+( const string_type& rhs ) const;
|
||||
|
||||
PRUint32 GetFragmentIdentifierMask() const { return mFragmentIdentifierMask; }
|
||||
|
||||
private:
|
||||
void operator+( const self_type& ); // NOT TO BE IMPLEMENTED
|
||||
// making this |private| stops you from over parenthesizing concatenation expressions, e.g., |(A+B) + (C+D)|
|
||||
// which would break the algorithm for distributing bits in the fragment identifier
|
||||
|
||||
private:
|
||||
const string_type* mStrings[2];
|
||||
PRUint32 mFragmentIdentifierMask;
|
||||
};
|
||||
|
||||
/*
|
||||
How shall we provide |operator+()|?
|
||||
|
||||
What would it return? It has to return a stack based object, because the client will
|
||||
not be given an opportunity to handle memory management in an expression like
|
||||
|
||||
myWritableString = stringA + stringB + stringC;
|
||||
|
||||
...so the `obvious' answer of returning a new |nsSharedString| is no good. We could
|
||||
return an |nsString|, if that name were in scope here, though there's no telling what the client
|
||||
will really want to do with the result. What might be better, though,
|
||||
is to return a `promise' to concatenate some strings...
|
||||
|
||||
By making |nsPromiseConcatenation| inherit from readable strings, we automatically handle
|
||||
assignment and other interesting uses within writable strings, plus we drastically reduce
|
||||
the number of cases we have to write |operator+()| for. The cost is extra temporary concat strings
|
||||
in the evaluation of strings of '+'s, e.g., |A + B + C + D|, and that we have to do some work
|
||||
to implement the virtual functions of readables.
|
||||
*/
|
||||
|
||||
inline
|
||||
const nsPromiseConcatenation
|
||||
operator+( const nsPromiseConcatenation& lhs, const nsAString& rhs )
|
||||
{
|
||||
return nsPromiseConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseCConcatenation
|
||||
operator+( const nsPromiseCConcatenation& lhs, const nsACString& rhs )
|
||||
{
|
||||
return nsPromiseCConcatenation(lhs, rhs, lhs.GetFragmentIdentifierMask()<<1);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseConcatenation
|
||||
operator+( const nsAString& lhs, const nsAString& rhs )
|
||||
{
|
||||
return nsPromiseConcatenation(lhs, rhs);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseCConcatenation
|
||||
operator+( const nsACString& lhs, const nsACString& rhs )
|
||||
{
|
||||
return nsPromiseCConcatenation(lhs, rhs);
|
||||
}
|
||||
|
||||
#if 0
|
||||
inline
|
||||
const nsPromiseConcatenation
|
||||
nsPromiseConcatenation::operator+( const string_type& rhs ) const
|
||||
{
|
||||
return nsPromiseConcatenation(*this, rhs, mFragmentIdentifierMask<<1);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseCConcatenation
|
||||
nsPromiseCConcatenation::operator+( const string_type& rhs ) const
|
||||
{
|
||||
return nsPromiseCConcatenation(*this, rhs, mFragmentIdentifierMask<<1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* !defined(nsPromiseConcatenation_h___) */
|
||||
@@ -1,170 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsPromiseFlatString_h___
|
||||
#define nsPromiseFlatString_h___
|
||||
|
||||
#ifndef nsSharableString_h___
|
||||
#include "nsSharableString.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* WARNING:
|
||||
*
|
||||
* Try to avoid flat strings. |PromiseFlat[C]String| will help you as a last resort,
|
||||
* and this may be necessary when dealing with legacy or OS calls, but in general,
|
||||
* requiring a zero-terminated contiguous hunk of characters kills many of the performance
|
||||
* wins the string classes offer. Write your own code to use |nsA[C]String&|s for parameters.
|
||||
* Write your string proccessing algorithms to exploit iterators. If you do this, you
|
||||
* will benefit from being able to chain operations without copying or allocating and your
|
||||
* code will be significantly more efficient. Remember, a function that takes an
|
||||
* |const nsA[C]String&| can always be passed a raw character pointer by wrapping it (for free)
|
||||
* in a |nsLocal[C]String|. But a function that takes a character pointer always has the
|
||||
* potential to force allocation and copying.
|
||||
*
|
||||
*
|
||||
* How to use it:
|
||||
*
|
||||
* Like all `promises', a |nsPromiseFlat[C]String| doesn't own the characters it promises.
|
||||
* You must never use it to promise characters out of a string with a shorter lifespan.
|
||||
* The typical use will be something like this
|
||||
*
|
||||
* SomeOSFunction( PromiseFlatCString(aCString).get() ); // GOOD
|
||||
*
|
||||
* Here's a BAD use:
|
||||
*
|
||||
* const char* buffer = PromiseFlatCString(aCString).get();
|
||||
* SomeOSFunction(buffer); // BAD!! |buffer| is a dangling pointer
|
||||
*
|
||||
* A |nsPromiseFlat[C]String| doesn't support non-|const| access (you can't use it to make
|
||||
* changes back into the original string). To help you avoid that, the only way to make
|
||||
* one is with the function |PromiseFlat[C]String|, which produce a |const| instance.
|
||||
* ``What if I need to keep a promise around for a little while?'' you might ask.
|
||||
* In that case, you can keep a reference, like so
|
||||
*
|
||||
* const nsPromiseFlatString& flat = PromiseFlatString(aString);
|
||||
* // this reference holds the anonymous temporary alive, but remember, it must _still_
|
||||
* // have a lifetime shorter than that of |aString|
|
||||
*
|
||||
* SomeOSFunction(flat.get());
|
||||
* SomeOtherOSFunction(flat.get());
|
||||
*
|
||||
*
|
||||
* How does it work?
|
||||
*
|
||||
* A |nsPromiseFlat[C]String| is just a wrapper for another string. If you apply it to
|
||||
* a string that happens to be flat, your promise is just a reference to that other string
|
||||
* and all calls are forwarded through to it. If you apply it to a non-flat string,
|
||||
* then a temporary flat string is created for you, by allocating and copying. In the unlikely
|
||||
* event that you end up assigning the result into a sharing string (e.g., |nsSharable[C]String|),
|
||||
* the right thing happens.
|
||||
*/
|
||||
|
||||
class NS_COM nsPromiseFlatString
|
||||
: public nsAFlatString /* , public nsAPromiseString */
|
||||
{
|
||||
friend const nsPromiseFlatString PromiseFlatString( const nsAString& );
|
||||
|
||||
public:
|
||||
nsPromiseFlatString( const nsPromiseFlatString& );
|
||||
|
||||
protected:
|
||||
nsPromiseFlatString() : mPromisedString(&mFlattenedString) { }
|
||||
explicit nsPromiseFlatString( const nsAString& aString );
|
||||
|
||||
// things we want to forward to the string we are promising
|
||||
virtual const nsBufferHandle<PRUnichar>* GetFlatBufferHandle() const;
|
||||
virtual const nsBufferHandle<PRUnichar>* GetBufferHandle() const;
|
||||
virtual const nsSharedBufferHandle<PRUnichar>* GetSharedBufferHandle() const;
|
||||
virtual PRBool IsDependentOn( const nsAString& ) const;
|
||||
|
||||
|
||||
// things we are forwarding now, but won't when we finally fix obsolete/nsString et al
|
||||
public:
|
||||
virtual const PRUnichar* get() const;
|
||||
virtual PRUint32 Length() const;
|
||||
protected:
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsPromiseFlatString& );
|
||||
|
||||
private:
|
||||
nsSharableString mFlattenedString;
|
||||
const nsAFlatString* mPromisedString;
|
||||
};
|
||||
|
||||
class NS_COM nsPromiseFlatCString
|
||||
: public nsAFlatCString /* , public nsAPromiseCString */
|
||||
{
|
||||
friend const nsPromiseFlatCString PromiseFlatCString( const nsACString& );
|
||||
|
||||
public:
|
||||
nsPromiseFlatCString( const nsPromiseFlatCString& );
|
||||
|
||||
protected:
|
||||
nsPromiseFlatCString() : mPromisedString(&mFlattenedString) { }
|
||||
explicit nsPromiseFlatCString( const nsACString& aString );
|
||||
|
||||
// things we want to forward to the string we are promising
|
||||
virtual const nsBufferHandle<char>* GetFlatBufferHandle() const;
|
||||
virtual const nsBufferHandle<char>* GetBufferHandle() const;
|
||||
virtual const nsSharedBufferHandle<char>* GetSharedBufferHandle() const;
|
||||
virtual PRBool IsDependentOn( const nsACString& ) const;
|
||||
|
||||
|
||||
// things we are forwarding now, but won't when we finally fix obsolete/nsString et al
|
||||
public:
|
||||
virtual const char* get() const;
|
||||
virtual PRUint32 Length() const;
|
||||
protected:
|
||||
virtual const char* GetReadableFragment( nsReadableFragment<char>&, nsFragmentRequest, PRUint32 ) const;
|
||||
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsPromiseFlatCString& );
|
||||
|
||||
private:
|
||||
nsSharableCString mFlattenedString;
|
||||
const nsAFlatCString* mPromisedString;
|
||||
};
|
||||
|
||||
|
||||
inline
|
||||
const nsPromiseFlatString
|
||||
PromiseFlatString( const nsAString& aString )
|
||||
{
|
||||
return nsPromiseFlatString(aString);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseFlatCString
|
||||
PromiseFlatCString( const nsACString& aString )
|
||||
{
|
||||
return nsPromiseFlatCString(aString);
|
||||
}
|
||||
|
||||
#endif /* !defined(nsPromiseFlatString_h___) */
|
||||
@@ -1,182 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsPromiseSubstring_h___
|
||||
#define nsPromiseSubstring_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsStringTraits_h___
|
||||
#include "nsStringTraits.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//
|
||||
// nsPromiseSubstring
|
||||
//
|
||||
|
||||
class NS_COM nsPromiseSubstring
|
||||
: public nsAPromiseString
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetReadableFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef nsAString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
public:
|
||||
nsPromiseSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
: mString(aString),
|
||||
mStartPos( NS_MIN(aStartPos, aString.Length()) ),
|
||||
mLength( NS_MIN(aLength, aString.Length()-mStartPos) )
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsPromiseSubstring( const const_iterator& aStart, const const_iterator& aEnd )
|
||||
: mString(aStart.string())
|
||||
{
|
||||
const_iterator zeroPoint;
|
||||
mString.BeginReading(zeroPoint);
|
||||
mStartPos = Distance(zeroPoint, aStart);
|
||||
mLength = Distance(aStart, aEnd);
|
||||
}
|
||||
|
||||
// nsPromiseSubstring( const nsPromiseSubstring& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsPromiseSubstring(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsPromiseSubstring& ); // we're immutable, you can't assign into a substring
|
||||
|
||||
public:
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); }
|
||||
|
||||
private:
|
||||
const string_type& mString;
|
||||
PRUint32 mStartPos;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
class NS_COM nsPromiseCSubstring
|
||||
: public nsAPromiseCString
|
||||
/*
|
||||
NOT FOR USE BY HUMANS (mostly)
|
||||
|
||||
...not unlike |nsPromiseConcatenation|. Instances of this class exist only as anonymous
|
||||
temporary results from |Substring()|. Like |nsPromiseConcatenation|, this class only
|
||||
holds a pointer, no string data of its own. It does its magic by overriding and forwarding
|
||||
calls to |GetReadableFragment()|.
|
||||
*/
|
||||
{
|
||||
typedef nsACString string_type;
|
||||
typedef string_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
virtual const char* GetReadableFragment( nsReadableFragment<char>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual char* GetWritableFragment( nsWritableFragment<char>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
public:
|
||||
nsPromiseCSubstring( const string_type& aString, PRUint32 aStartPos, PRUint32 aLength )
|
||||
: mString(aString),
|
||||
mStartPos( NS_MIN(aStartPos, aString.Length()) ),
|
||||
mLength( NS_MIN(aLength, aString.Length()-mStartPos) )
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsPromiseCSubstring( const const_iterator& aStart, const const_iterator& aEnd )
|
||||
: mString(aStart.string())
|
||||
{
|
||||
const_iterator zeroPoint;
|
||||
mString.BeginReading(zeroPoint);
|
||||
mStartPos = Distance(zeroPoint, aStart);
|
||||
mLength = Distance(aStart, aEnd);
|
||||
}
|
||||
|
||||
// nsPromiseCSubstring( const nsPromiseCSubstring& ); // auto-generated copy-constructor should be OK
|
||||
// ~nsPromiseCSubstring(); // auto-generated destructor OK
|
||||
|
||||
private:
|
||||
// NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsPromiseCSubstring& ); // we're immutable, you can't assign into a substring
|
||||
|
||||
public:
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRBool Promises( const string_type& aString ) const { return mString.Promises(aString); }
|
||||
|
||||
private:
|
||||
const string_type& mString;
|
||||
PRUint32 mStartPos;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline
|
||||
const nsPromiseCSubstring
|
||||
Substring( const nsACString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
{
|
||||
return nsPromiseCSubstring(aString, aStartPos, aSubstringLength);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseSubstring
|
||||
Substring( const nsAString& aString, PRUint32 aStartPos, PRUint32 aSubstringLength )
|
||||
{
|
||||
return nsPromiseSubstring(aString, aStartPos, aSubstringLength);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseCSubstring
|
||||
Substring( const nsReadingIterator<char>& aStart, const nsReadingIterator<char>& aEnd )
|
||||
{
|
||||
return nsPromiseCSubstring(aStart, aEnd);
|
||||
}
|
||||
|
||||
inline
|
||||
const nsPromiseSubstring
|
||||
Substring( const nsReadingIterator<PRUnichar>& aStart, const nsReadingIterator<PRUnichar>& aEnd )
|
||||
{
|
||||
return nsPromiseSubstring(aStart, aEnd);
|
||||
}
|
||||
|
||||
|
||||
#endif /* !defined(nsPromiseSubstring_h___) */
|
||||
@@ -1,293 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
* Johnny Stenbeck <jst@netscape.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsReadableUtils_h___
|
||||
#define nsReadableUtils_h___
|
||||
|
||||
/**
|
||||
* I guess all the routines in this file are all mis-named.
|
||||
* According to our conventions, they should be |NS_xxx|.
|
||||
*/
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsAStringGenerator_h___
|
||||
#include "nsAStringGenerator.h"
|
||||
#endif
|
||||
|
||||
|
||||
NS_COM size_t Distance( const nsReadingIterator<PRUnichar>&, const nsReadingIterator<PRUnichar>& );
|
||||
NS_COM size_t Distance( const nsReadingIterator<char>&, const nsReadingIterator<char>& );
|
||||
|
||||
|
||||
NS_COM void CopyUCS2toASCII( const nsAString& aSource, nsACString& aDest );
|
||||
NS_COM void CopyASCIItoUCS2( const nsACString& aSource, nsAString& aDest );
|
||||
|
||||
/**
|
||||
* Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
|
||||
*
|
||||
* Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|.
|
||||
* Performs a lossy encoding conversion by chopping 16-bit wide characters down to 8-bits wide while copying |aSource| to your new buffer.
|
||||
* This conversion is not well defined; but it reproduces legacy string behavior.
|
||||
* The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls.
|
||||
*
|
||||
* @param aSource a 16-bit wide string
|
||||
* @return a new |char| buffer you must free with |nsMemory::Free|.
|
||||
*/
|
||||
NS_COM char* ToNewCString( const nsAString& aSource );
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
|
||||
*
|
||||
* Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|.
|
||||
* The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls.
|
||||
*
|
||||
* @param aSource an 8-bit wide string
|
||||
* @return a new |char| buffer you must free with |nsMemory::Free|.
|
||||
*/
|
||||
NS_COM char* ToNewCString( const nsACString& aSource );
|
||||
|
||||
/**
|
||||
* Returns a new |char| buffer containing a zero-terminated copy of |aSource|.
|
||||
*
|
||||
* Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|.
|
||||
* Performs a encoding conversion by converting 16-bit wide characters down to UTF8 encoded 8-bits wide string copying |aSource| to your new buffer.
|
||||
* The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls.
|
||||
*
|
||||
* @param aSource a 16-bit wide string
|
||||
* @return a new |char| buffer you must free with |nsMemory::Free|.
|
||||
*/
|
||||
|
||||
NS_COM char* ToNewUTF8String( const nsAString& aSource );
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new |PRUnichar| buffer containing a zero-terminated copy of |aSource|.
|
||||
*
|
||||
* Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|.
|
||||
* The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls.
|
||||
*
|
||||
* @param aSource a 16-bit wide string
|
||||
* @return a new |PRUnichar| buffer you must free with |nsMemory::Free|.
|
||||
*/
|
||||
NS_COM PRUnichar* ToNewUnicode( const nsAString& aSource );
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new |PRUnichar| buffer containing a zero-terminated copy of |aSource|.
|
||||
*
|
||||
* Allocates and returns a new |char| buffer which you must free with |nsMemory::Free|.
|
||||
* Performs an encoding conversion by 0-padding 8-bit wide characters up to 16-bits wide while copying |aSource| to your new buffer.
|
||||
* This conversion is not well defined; but it reproduces legacy string behavior.
|
||||
* The new buffer is zero-terminated, but that may not help you if |aSource| contains embedded nulls.
|
||||
*
|
||||
* @param aSource an 8-bit wide string
|
||||
* @return a new |PRUnichar| buffer you must free with |nsMemory::Free|.
|
||||
*/
|
||||
NS_COM PRUnichar* ToNewUnicode( const nsACString& aSource );
|
||||
|
||||
/**
|
||||
* Copies |aLength| 16-bit characters from the start of |aSource| to the
|
||||
* |PRUnichar| buffer |aDest|.
|
||||
*
|
||||
* After this operation |aDest| is not null terminated.
|
||||
*
|
||||
* @param aSource a 16-bit wide string
|
||||
* @param aSrcOffset start offset in the source string
|
||||
* @param aDest a |PRUnichar| buffer
|
||||
* @param aLength the number of 16-bit characters to copy
|
||||
* @return pointer to destination buffer - identical to |aDest|
|
||||
*/
|
||||
NS_COM PRUnichar* CopyUnicodeTo( const nsAString& aSource,
|
||||
PRUint32 aSrcOffset,
|
||||
PRUnichar* aDest,
|
||||
PRUint32 aLength );
|
||||
|
||||
|
||||
/**
|
||||
* Copies 16-bit characters between iterators |aSrcStart| and
|
||||
* |aSrcEnd| to the writable string |aDest|. Similar to the
|
||||
* |nsString::Mid| method.
|
||||
*
|
||||
* After this operation |aDest| is not null terminated.
|
||||
*
|
||||
* @param aSrcStart start source iterator
|
||||
* @param aSrcEnd end source iterator
|
||||
* @param aDest destination for the copy
|
||||
*/
|
||||
NS_COM void CopyUnicodeTo( const nsReadingIterator<PRUnichar>& aSrcStart,
|
||||
const nsReadingIterator<PRUnichar>& aSrcEnd,
|
||||
nsAString& aDest );
|
||||
|
||||
/**
|
||||
* Appends 16-bit characters between iterators |aSrcStart| and
|
||||
* |aSrcEnd| to the writable string |aDest|.
|
||||
*
|
||||
* After this operation |aDest| is not null terminated.
|
||||
*
|
||||
* @param aSrcStart start source iterator
|
||||
* @param aSrcEnd end source iterator
|
||||
* @param aDest destination for the copy
|
||||
*/
|
||||
NS_COM void AppendUnicodeTo( const nsReadingIterator<PRUnichar>& aSrcStart,
|
||||
const nsReadingIterator<PRUnichar>& aSrcEnd,
|
||||
nsAString& aDest );
|
||||
|
||||
/**
|
||||
* Returns |PR_TRUE| if |aString| contains only ASCII characters, that is, characters in the range (0x00, 0x7F).
|
||||
*
|
||||
* @param aString a 16-bit wide string to scan
|
||||
*/
|
||||
NS_COM PRBool IsASCII( const nsAString& aString );
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts case in place in the argument string.
|
||||
*/
|
||||
NS_COM void ToUpperCase( nsAString& );
|
||||
NS_COM void ToUpperCase( nsACString& );
|
||||
|
||||
NS_COM void ToLowerCase( nsAString& );
|
||||
NS_COM void ToLowerCase( nsACString& );
|
||||
|
||||
/**
|
||||
* Finds the leftmost occurance of |aPattern|, if any in the range |aSearchStart|..|aSearchEnd|.
|
||||
*
|
||||
* Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| and |aSearchEnd| to
|
||||
* point to the match. If no match was found, returns |PR_FALSE| and makes |aSearchStart == aSearchEnd|.
|
||||
*
|
||||
* Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|.
|
||||
* If we need something faster, then we can implement that later.
|
||||
*/
|
||||
NS_COM PRBool FindInReadable( const nsAString& aPattern, nsReadingIterator<PRUnichar>&, nsReadingIterator<PRUnichar>& );
|
||||
NS_COM PRBool FindInReadable( const nsACString& aPattern, nsReadingIterator<char>&, nsReadingIterator<char>& );
|
||||
|
||||
NS_COM PRBool CaseInsensitiveFindInReadable( const nsAString& aPattern, nsReadingIterator<PRUnichar>&, nsReadingIterator<PRUnichar>& );
|
||||
NS_COM PRBool CaseInsensitiveFindInReadable( const nsACString& aPattern, nsReadingIterator<char>&, nsReadingIterator<char>& );
|
||||
|
||||
|
||||
/**
|
||||
* Finds the rightmost occurance of |aPattern|
|
||||
* Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| and |aSearchEnd| to
|
||||
* point to the match. If no match was found, returns |PR_FALSE| and makes |aSearchStart == aSearchEnd|.
|
||||
*
|
||||
* Currently, this is equivalent to the O(m*n) implementation previously on |ns[C]String|.
|
||||
* If we need something faster, then we can implement that later.
|
||||
*/
|
||||
NS_COM PRBool RFindInReadable( const nsAString& aPattern, nsReadingIterator<PRUnichar>&, nsReadingIterator<PRUnichar>& );
|
||||
NS_COM PRBool RFindInReadable( const nsACString& aPattern, nsReadingIterator<char>&, nsReadingIterator<char>& );
|
||||
|
||||
/**
|
||||
* Finds the leftmost occurance of |aChar|, if any in the range
|
||||
* |aSearchStart|..|aSearchEnd|.
|
||||
*
|
||||
* Returns |PR_TRUE| if a match was found, and adjusts |aSearchStart| to
|
||||
* point to the match. If no match was found, returns |PR_FALSE| and
|
||||
* makes |aSearchStart == aSearchEnd|.
|
||||
*/
|
||||
NS_COM PRBool FindCharInReadable( PRUnichar aChar, nsReadingIterator<PRUnichar>& aSearchStart, const nsReadingIterator<PRUnichar>& aSearchEnd );
|
||||
NS_COM PRBool FindCharInReadable( char aChar, nsReadingIterator<char>& aSearchStart, const nsReadingIterator<char>& aSearchEnd );
|
||||
|
||||
/**
|
||||
* Finds the number of occurences of |aChar| in the string |aStr|
|
||||
*/
|
||||
NS_COM PRUint32 CountCharInReadable( const nsAString& aStr,
|
||||
PRUnichar aChar );
|
||||
NS_COM PRUint32 CountCharInReadable( const nsACString& aStr,
|
||||
char aChar );
|
||||
|
||||
|
||||
/*
|
||||
|nsSubstituteC?String|:
|
||||
this is currently a naive implementation leveraging |FindInReadable|. I have a better
|
||||
algorithm in mind -- Gonnet, Baeza-Yates `Shift-Or' searching which is linear and simple
|
||||
to implement (not quite as simple as re-using |FindInReadable|, though :-).
|
||||
*/
|
||||
|
||||
class NS_COM nsSubstituteString
|
||||
: public nsAStringGenerator
|
||||
{
|
||||
public:
|
||||
nsSubstituteString( const nsAString& aText, const nsAString& aPattern, const nsAString& aReplacement )
|
||||
: mText(aText),
|
||||
mPattern(aPattern),
|
||||
mReplacement(aReplacement),
|
||||
mNumberOfMatches(-1) // |-1| means `don't know'
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
virtual PRUnichar* operator()( PRUnichar* aDestBuffer ) const;
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRUint32 MaxLength() const;
|
||||
virtual PRBool IsDependentOn( const nsAString& ) const;
|
||||
|
||||
private:
|
||||
void CountMatches() const;
|
||||
|
||||
private:
|
||||
const nsAString& mText;
|
||||
const nsAString& mPattern;
|
||||
const nsAString& mReplacement;
|
||||
/* mutable */ PRInt32 mNumberOfMatches;
|
||||
};
|
||||
|
||||
class NS_COM nsSubstituteCString
|
||||
: public nsACStringGenerator
|
||||
{
|
||||
public:
|
||||
nsSubstituteCString( const nsACString& aText, const nsACString& aPattern, const nsACString& aReplacement )
|
||||
: mText(aText),
|
||||
mPattern(aPattern),
|
||||
mReplacement(aReplacement),
|
||||
mNumberOfMatches(-1) // |-1| means `don't know'
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
virtual char* operator()( char* aDestBuffer ) const;
|
||||
virtual PRUint32 Length() const;
|
||||
virtual PRUint32 MaxLength() const;
|
||||
virtual PRBool IsDependentOn( const nsACString& ) const;
|
||||
|
||||
private:
|
||||
void CountMatches() const;
|
||||
|
||||
private:
|
||||
const nsACString& mText;
|
||||
const nsACString& mPattern;
|
||||
const nsACString& mReplacement;
|
||||
/* mutable */ PRInt32 mNumberOfMatches;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !defined(nsReadableUtils_h___)
|
||||
@@ -1,104 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsSharableString.h --- a string implementation that shares its underlying storage */
|
||||
|
||||
|
||||
#ifndef nsSharableString_h___
|
||||
#define nsSharableString_h___
|
||||
|
||||
#ifndef nsAFlatString_h___
|
||||
#include "nsAFlatString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsBufferHandleUtils_h___
|
||||
#include "nsBufferHandleUtils.h"
|
||||
#endif
|
||||
|
||||
//-------1---------2---------3---------4---------5---------6---------7---------8
|
||||
|
||||
/**
|
||||
* Not yet ready for non-|const| access
|
||||
*/
|
||||
|
||||
class NS_COM nsSharableString
|
||||
: public nsAFlatString
|
||||
{
|
||||
public:
|
||||
typedef nsSharableString self_type;
|
||||
typedef PRUnichar char_type;
|
||||
typedef nsAString string_type;
|
||||
|
||||
public:
|
||||
nsSharableString() { }
|
||||
nsSharableString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { }
|
||||
explicit nsSharableString( const string_type& aReadable ) { assign(aReadable); }
|
||||
explicit nsSharableString( const nsSharedBufferHandle<char_type>* aHandle ) : mBuffer(aHandle) { }
|
||||
|
||||
self_type&
|
||||
operator=( const string_type& aReadable )
|
||||
{
|
||||
assign(aReadable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
void assign( const string_type& );
|
||||
virtual const nsSharedBufferHandle<char_type>* GetSharedBufferHandle() const;
|
||||
|
||||
protected:
|
||||
nsAutoBufferHandle<char_type> mBuffer;
|
||||
};
|
||||
|
||||
|
||||
class NS_COM nsSharableCString
|
||||
: public nsAFlatCString
|
||||
{
|
||||
public:
|
||||
typedef nsSharableCString self_type;
|
||||
typedef char char_type;
|
||||
typedef nsACString string_type;
|
||||
|
||||
public:
|
||||
nsSharableCString() { }
|
||||
nsSharableCString( const self_type& aOther ) : mBuffer(aOther.mBuffer) { }
|
||||
explicit nsSharableCString( const string_type& aReadable ) { assign(aReadable); }
|
||||
explicit nsSharableCString( const nsSharedBufferHandle<char_type>* aHandle ) : mBuffer(aHandle) { }
|
||||
|
||||
self_type&
|
||||
operator=( const string_type& aReadable )
|
||||
{
|
||||
assign(aReadable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
void assign( const string_type& );
|
||||
virtual const nsSharedBufferHandle<char_type>* GetSharedBufferHandle() const;
|
||||
|
||||
protected:
|
||||
nsAutoBufferHandle<char_type> mBuffer;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !defined(nsSharableString_h___) */
|
||||
@@ -1,224 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 strings.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsSharedBufferList_h___
|
||||
#define nsSharedBufferList_h___
|
||||
|
||||
#ifndef nsBufferHandle_h___
|
||||
#include "nsBufferHandle.h"
|
||||
// for |nsSharedBufferHandle|
|
||||
#endif
|
||||
|
||||
#ifndef nscore_h___
|
||||
#include "nscore.h"
|
||||
// for |PRUnichar|
|
||||
#endif
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsDependentString_h___
|
||||
#include "nsDependentString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsBufferHandleUtils_h___
|
||||
#include "nsBufferHandleUtils.h"
|
||||
// for |NS_AllocateContiguousHandleWithData|
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* This class forms the basis for several multi-fragment string classes, in
|
||||
* particular: |nsFragmentedString| (though not yet), and |nsSlidingString|/|nsSlidingSubstring|.
|
||||
*
|
||||
* This class is not templated. It is provided only for |PRUnichar|-based strings.
|
||||
* If we turn out to have a need for multi-fragment ASCII strings, then perhaps we'll templatize
|
||||
* or else duplicate this class.
|
||||
*/
|
||||
class NS_COM nsSharedBufferList
|
||||
{
|
||||
public:
|
||||
|
||||
class Buffer
|
||||
: public nsFlexBufferHandle<PRUnichar>
|
||||
{
|
||||
public:
|
||||
Buffer( PRUnichar* aDataStart, PRUnichar* aDataEnd, PRUnichar* aStorageStart, PRUnichar* aStorageEnd, PRBool aIsSingleAllocation=PR_FALSE )
|
||||
: nsFlexBufferHandle<PRUnichar>(aDataStart, aDataEnd, aStorageStart, aStorageEnd)
|
||||
{
|
||||
if ( aIsSingleAllocation )
|
||||
this->mFlags |= this->kIsSingleAllocationWithBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* These buffers will be `owned' by the list, and only the
|
||||
* the list itself will be allowed to delete member |Buffer|s,
|
||||
* therefore, we cannot use the inherited |AcquireReference|
|
||||
* and |ReleaseReference|, as they use the model that the
|
||||
* buffer manages its own lifetime.
|
||||
*/
|
||||
void
|
||||
AcquireNonOwningReference() const
|
||||
{
|
||||
Buffer* mutable_this = NS_CONST_CAST(Buffer*, this);
|
||||
mutable_this->set_refcount( get_refcount()+1 );
|
||||
}
|
||||
|
||||
void
|
||||
ReleaseNonOwningReference() const
|
||||
{
|
||||
Buffer* mutable_this = NS_CONST_CAST(Buffer*, this);
|
||||
mutable_this->set_refcount( get_refcount()-1 );
|
||||
}
|
||||
|
||||
Buffer* mPrev;
|
||||
Buffer* mNext;
|
||||
|
||||
private:
|
||||
// pass-by-value is explicitly denied
|
||||
Buffer( const Buffer& ); // NOT TO BE IMPLEMENTED
|
||||
void operator=( const Buffer& ); // NOT TO BE IMPLEMENTED
|
||||
};
|
||||
|
||||
struct Position
|
||||
{
|
||||
Buffer* mBuffer;
|
||||
PRUnichar* mPosInBuffer;
|
||||
|
||||
Position() { }
|
||||
Position( Buffer* aBuffer, PRUnichar* aPosInBuffer ) : mBuffer(aBuffer), mPosInBuffer(aPosInBuffer) { }
|
||||
|
||||
// Position( const Position& ); -- auto-generated copy-constructor OK
|
||||
// Position& operator=( const Position& ); -- auto-generated copy-assignment OK
|
||||
// ~Position(); -- auto-generated destructor OK
|
||||
|
||||
// iff |aIter| is a valid iterator into a |nsSharedBufferList|
|
||||
explicit
|
||||
Position( const nsReadingIterator<PRUnichar>& aIter )
|
||||
: mBuffer( NS_CONST_CAST(Buffer*, NS_REINTERPRET_CAST(const Buffer*, aIter.fragment().mFragmentIdentifier)) ),
|
||||
mPosInBuffer( NS_CONST_CAST(PRUnichar*, aIter.get()) )
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
// iff |aIter| is a valid iterator into a |nsSharedBufferList|
|
||||
Position&
|
||||
operator=( const nsReadingIterator<PRUnichar>& aIter )
|
||||
{
|
||||
mBuffer = NS_CONST_CAST(Buffer*, NS_REINTERPRET_CAST(const Buffer*, aIter.fragment().mFragmentIdentifier));
|
||||
mPosInBuffer = NS_CONST_CAST(PRUnichar*, aIter.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PointTo( Buffer* aBuffer, PRUnichar* aPosInBuffer ) { mBuffer=aBuffer; mPosInBuffer=aPosInBuffer; }
|
||||
void PointBefore( Buffer* aBuffer ) { PointTo(aBuffer, aBuffer->DataStart()); }
|
||||
void PointAfter( Buffer* aBuffer ) { PointTo(aBuffer, aBuffer->DataEnd()); }
|
||||
|
||||
// Position( const Position& ); -- automatically generated copy-constructor is OK
|
||||
// Position& operator=( const Position& ); -- automatically generated copy-assignment operator is OK
|
||||
|
||||
// don't want to provide this as |operator-|, since that might imply O(1)
|
||||
static ptrdiff_t Distance( const Position&, const Position& );
|
||||
};
|
||||
|
||||
|
||||
|
||||
public:
|
||||
nsSharedBufferList( Buffer* aBuffer = 0 )
|
||||
: mFirstBuffer(aBuffer),
|
||||
mLastBuffer(aBuffer),
|
||||
mTotalDataLength(0)
|
||||
{
|
||||
if ( aBuffer )
|
||||
{
|
||||
aBuffer->mPrev = aBuffer->mNext = 0;
|
||||
mTotalDataLength = aBuffer->DataLength();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~nsSharedBufferList();
|
||||
|
||||
private:
|
||||
// pass-by-value is explicitly denied
|
||||
nsSharedBufferList( const nsSharedBufferList& ); // NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsSharedBufferList& ); // NOT TO BE IMPLEMENTED
|
||||
|
||||
public:
|
||||
void LinkBuffer( Buffer*, Buffer*, Buffer* );
|
||||
Buffer* UnlinkBuffer( Buffer* );
|
||||
|
||||
enum SplitDisposition // when splitting a buffer in two...
|
||||
{
|
||||
kSplitCopyRightData, // copy the data right of the split point to a new buffer
|
||||
kSplitCopyLeastData, // copy the smaller amount of data to the new buffer
|
||||
kSplitCopyLeftData // copy the data left of the split point to a new buffer
|
||||
};
|
||||
|
||||
void SplitBuffer( const Position&, SplitDisposition = kSplitCopyLeastData );
|
||||
|
||||
static
|
||||
Buffer*
|
||||
NewSingleAllocationBuffer( const PRUnichar* aData, PRUint32 aDataLength, PRUint32 aAdditionalCapacity = 1 )
|
||||
{
|
||||
typedef Buffer* Buffer_ptr;
|
||||
return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), nsDependentString(aData, aDataLength), aAdditionalCapacity);
|
||||
}
|
||||
|
||||
static
|
||||
Buffer*
|
||||
NewSingleAllocationBuffer( const nsAString& aReadable, PRUint32 aAdditionalCapacity = 1 )
|
||||
{
|
||||
typedef Buffer* Buffer_ptr;
|
||||
return NS_AllocateContiguousHandleWithData(Buffer_ptr(0), aReadable, aAdditionalCapacity);
|
||||
}
|
||||
|
||||
static
|
||||
Buffer*
|
||||
NewWrappingBuffer( PRUnichar* aDataStart, PRUnichar* aDataEnd, PRUnichar* aStorageEnd )
|
||||
{
|
||||
return new Buffer(aDataStart, aDataEnd, aDataStart, aStorageEnd);
|
||||
}
|
||||
|
||||
void DiscardSuffix( PRUint32 );
|
||||
// need other discards: prefix, and by iterator or pointer or something
|
||||
|
||||
Buffer* GetFirstBuffer() { return mFirstBuffer; }
|
||||
const Buffer* GetFirstBuffer() const { return mFirstBuffer; }
|
||||
|
||||
Buffer* GetLastBuffer() { return mLastBuffer; }
|
||||
const Buffer* GetLastBuffer() const { return mLastBuffer; }
|
||||
|
||||
ptrdiff_t GetDataLength() const { return mTotalDataLength; }
|
||||
|
||||
protected:
|
||||
void DestroyBuffers();
|
||||
|
||||
protected:
|
||||
Buffer* mFirstBuffer;
|
||||
Buffer* mLastBuffer;
|
||||
ptrdiff_t mTotalDataLength;
|
||||
};
|
||||
|
||||
#endif // !defined(nsSharedBufferList_h___)
|
||||
@@ -1,203 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 strings.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef nsSlidingString_h___
|
||||
#define nsSlidingString_h___
|
||||
|
||||
#ifndef nsAString_h___
|
||||
#include "nsAString.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsSharedBufferList_h___
|
||||
#include "nsSharedBufferList.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Maintains the sequence from the prev-most referenced buffer to the last buffer.
|
||||
* As prev-most buffers become un-referenced, they are unlinked from the list
|
||||
* and destroyed.
|
||||
*
|
||||
* One or more |nsSlidingSubstring|s may reference into the list. Each |nsSlidingSubstring|
|
||||
* holds a reference into the prev-most buffer intersecting the
|
||||
* substring it describes. The destructor of a |nsSlidingSubstring| releases this
|
||||
* reference, allowing the buffer list to destroy the contiguous prefix of
|
||||
* unreferenced buffers.
|
||||
*
|
||||
* A single instance of |nsSlidingString| may reference this list.
|
||||
* Through that interface, new data can be appended onto the next-most end
|
||||
* of the list. |nsSlidingString| also the client to advance its starting point.
|
||||
*
|
||||
*/
|
||||
class NS_COM nsSlidingSharedBufferList
|
||||
: public nsSharedBufferList
|
||||
{
|
||||
public:
|
||||
nsSlidingSharedBufferList( Buffer* aBuffer ) : nsSharedBufferList(aBuffer), mRefCount(0) { }
|
||||
|
||||
void AcquireReference() { ++mRefCount; }
|
||||
void ReleaseReference() { if ( !--mRefCount ) delete this; }
|
||||
|
||||
void DiscardUnreferencedPrefix( Buffer* );
|
||||
|
||||
private:
|
||||
PRUint32 mRefCount;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class nsSlidingString;
|
||||
|
||||
/**
|
||||
* a substring over a buffer list, this
|
||||
*/
|
||||
class NS_COM nsSlidingSubstring
|
||||
: virtual public nsAPromiseString
|
||||
{
|
||||
friend class nsSlidingString;
|
||||
|
||||
public:
|
||||
typedef nsSlidingSharedBufferList::Buffer Buffer;
|
||||
typedef nsSlidingSharedBufferList::Position Position;
|
||||
|
||||
nsSlidingSubstring()
|
||||
: mStart(0,0),
|
||||
mEnd(0,0),
|
||||
mBufferList(0),
|
||||
mLength(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsSlidingSubstring( const nsSlidingSubstring& ); // copy-constructor
|
||||
nsSlidingSubstring( const nsSlidingSubstring& aString, const nsReadingIterator<PRUnichar>& aStart, const nsReadingIterator<PRUnichar>& aEnd );
|
||||
nsSlidingSubstring( const nsSlidingString& );
|
||||
nsSlidingSubstring( const nsSlidingString& aString, const nsReadingIterator<PRUnichar>& aStart, const nsReadingIterator<PRUnichar>& aEnd );
|
||||
explicit nsSlidingSubstring( const nsAString& );
|
||||
// copy the supplied string into a new buffer ... there will be no modifying instance over this buffer list
|
||||
|
||||
void Rebind( const nsSlidingSubstring& );
|
||||
void Rebind( const nsSlidingSubstring&, const nsReadingIterator<PRUnichar>&, const nsReadingIterator<PRUnichar>& );
|
||||
void Rebind( const nsSlidingString& );
|
||||
void Rebind( const nsSlidingString&, const nsReadingIterator<PRUnichar>&, const nsReadingIterator<PRUnichar>& );
|
||||
void Rebind( const nsAString& );
|
||||
|
||||
~nsSlidingSubstring();
|
||||
|
||||
virtual PRUint32 Length() const { return mLength; }
|
||||
|
||||
protected:
|
||||
nsSlidingSubstring( nsSlidingSharedBufferList* aBufferList );
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
private:
|
||||
// can't assign into me, I'm a read-only reference
|
||||
void operator=( const nsSlidingSubstring& ); // NOT TO BE IMPLEMENTED
|
||||
|
||||
void
|
||||
init_range_from_buffer_list()
|
||||
// used only from constructors
|
||||
{
|
||||
mStart.PointBefore(mBufferList->GetFirstBuffer());
|
||||
mEnd.PointAfter(mBufferList->GetLastBuffer());
|
||||
mLength = PRUint32(Position::Distance(mStart, mEnd));
|
||||
}
|
||||
|
||||
void
|
||||
acquire_ownership_of_buffer_list() const
|
||||
// used only from constructors and |Rebind|, requires |mStart| already be initialized
|
||||
{
|
||||
mBufferList->AcquireReference();
|
||||
mStart.mBuffer->AcquireNonOwningReference();
|
||||
}
|
||||
|
||||
void
|
||||
release_ownership_of_buffer_list()
|
||||
{
|
||||
if ( mBufferList )
|
||||
{
|
||||
mStart.mBuffer->ReleaseNonOwningReference();
|
||||
mBufferList->DiscardUnreferencedPrefix(mStart.mBuffer);
|
||||
mBufferList->ReleaseReference();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Position mStart;
|
||||
Position mEnd;
|
||||
nsSlidingSharedBufferList* mBufferList;
|
||||
PRUint32 mLength;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An |nsSlidingSharedBufferList| may be modified by zero or one instances of this class.
|
||||
*
|
||||
*/
|
||||
class NS_COM nsSlidingString
|
||||
: virtual public nsAPromiseString,
|
||||
private nsSlidingSubstring
|
||||
{
|
||||
friend class nsSlidingSubstring;
|
||||
|
||||
public:
|
||||
nsSlidingString( PRUnichar* aStorageStart, PRUnichar* aDataEnd, PRUnichar* aStorageEnd );
|
||||
// ...created by consuming ownership of a buffer ... |aStorageStart| must point to something
|
||||
// that it will be OK for the slidking string to call |nsMemory::Free| on
|
||||
|
||||
virtual PRUint32 Length() const { return mLength; }
|
||||
|
||||
// you are giving ownership to the string, it takes and keeps your buffer, deleting it (with |nsMemory::Free|) when done
|
||||
void AppendBuffer( PRUnichar* aStorageStart, PRUnichar* aDataEnd, PRUnichar* aStorageEnd );
|
||||
|
||||
// void Append( ... ); do you want some |Append|s that copy the supplied data?
|
||||
|
||||
void DiscardPrefix( const nsReadingIterator<PRUnichar>& );
|
||||
// any other way you want to do this?
|
||||
|
||||
protected:
|
||||
virtual const PRUnichar* GetReadableFragment( nsReadableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) const;
|
||||
virtual PRUnichar* GetWritableFragment( nsWritableFragment<PRUnichar>&, nsFragmentRequest, PRUint32 ) { return 0; }
|
||||
|
||||
void InsertReadable( const nsAString&, const nsReadingIterator<PRUnichar>& ); // ...to implement |nsScannerString::UngetReadable|
|
||||
|
||||
private:
|
||||
|
||||
void
|
||||
acquire_ownership_of_buffer_list() const
|
||||
// used only from constructors and |Rebind|, requires |mStart| already be initialized
|
||||
{
|
||||
mBufferList->AcquireReference();
|
||||
mStart.mBuffer->AcquireNonOwningReference();
|
||||
}
|
||||
|
||||
nsSlidingString( const nsSlidingString& ); // NOT TO BE IMPLEMENTED
|
||||
void operator=( const nsSlidingString& ); // NOT TO BE IMPLEMENTED
|
||||
};
|
||||
|
||||
#endif // !defined(nsSlidingString_h___)
|
||||
@@ -1,37 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsStringDefines.h --- preprocessor definitions common across all string files */
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#define nsStringDefines_h___
|
||||
|
||||
#if !defined(DEBUG) || !defined(DEBUG_STRING)
|
||||
#define DEBUG_STRING 0
|
||||
#endif
|
||||
|
||||
#if !defined(DEBUG) || !defined(DEBUG_STRING_STATS)
|
||||
#define DEBUG_STRING_STATS 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsStringFragment.h --- machinery that makes string iterators work */
|
||||
|
||||
#ifndef nsStringFragment_h___
|
||||
#define nsStringFragment_h___
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* An |nsFragmentRequest| is used to tell |GetReadableFragment| and
|
||||
* |GetWritableFragment| what to do.
|
||||
*
|
||||
* @see GetReadableFragment
|
||||
*/
|
||||
|
||||
enum nsFragmentRequest { kPrevFragment, kFirstFragment, kLastFragment, kNextFragment, kFragmentAt };
|
||||
|
||||
|
||||
/**
|
||||
* A |nsReadableFragment| provides |const| access to a contiguous hunk of
|
||||
* string of homogenous units, e.g., bytes (|char|). This doesn't mean it
|
||||
* represents a flat hunk. It could be a variable length encoding, for
|
||||
* instance UTF-8. And the fragment itself need not be zero-terminated.
|
||||
*
|
||||
* An |nsReadableFragment| is the underlying machinery that lets
|
||||
* |nsReadingIterator|s work.
|
||||
*
|
||||
* @see nsReadingIterator
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
struct nsReadableFragment
|
||||
{
|
||||
const CharT* mStart;
|
||||
const CharT* mEnd;
|
||||
const void* mFragmentIdentifier;
|
||||
|
||||
nsReadableFragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
const void*
|
||||
GetID() const
|
||||
{
|
||||
return mFragmentIdentifier;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
GetIDAsInt() const
|
||||
{
|
||||
typedef char* char_ptr;
|
||||
typedef unsigned long ulong;
|
||||
return ulong(char_ptr(mFragmentIdentifier)-char_ptr(0));
|
||||
}
|
||||
|
||||
void
|
||||
SetID( const void* id )
|
||||
{
|
||||
mFragmentIdentifier = id;
|
||||
}
|
||||
|
||||
void
|
||||
SetID( unsigned long id )
|
||||
{
|
||||
typedef char* char_ptr;
|
||||
typedef void* void_ptr;
|
||||
mFragmentIdentifier = void_ptr(char_ptr(0)+id);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A |nsWritableFragment| provides non-|const| access to a contiguous hunk of
|
||||
* string of homogenous units, e.g., bytes (|char|). This doesn't mean it
|
||||
* represents a flat hunk. It could be a variable length encoding, for
|
||||
* instance UTF-8. And the fragment itself need not be zero-terminated.
|
||||
*
|
||||
* An |nsWritableFragment| is the underlying machinery that lets
|
||||
* |nsWritingIterator|s work.
|
||||
*
|
||||
* @see nsWritingIterator
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
struct nsWritableFragment
|
||||
{
|
||||
CharT* mStart;
|
||||
CharT* mEnd;
|
||||
void* mFragmentIdentifier;
|
||||
|
||||
nsWritableFragment()
|
||||
: mStart(0), mEnd(0), mFragmentIdentifier(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* !defined(nsStringFragment_h___) */
|
||||
@@ -1,65 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsStringFwd.h --- forward declarations for string classes */
|
||||
|
||||
#ifndef nsStringFwd_h___
|
||||
#define nsStringFwd_h___
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @see nsAString.h
|
||||
*/
|
||||
|
||||
class nsAString;
|
||||
class nsACString;
|
||||
|
||||
|
||||
/**
|
||||
* @see nsAPromiseString.h
|
||||
*/
|
||||
|
||||
class nsAPromiseString;
|
||||
class nsAPromiseCString;
|
||||
|
||||
|
||||
/**
|
||||
* @see nsAFlatString.h
|
||||
*/
|
||||
|
||||
class nsAFlatString;
|
||||
class nsAFlatCString;
|
||||
|
||||
|
||||
/**
|
||||
* @see nsDependentString.h
|
||||
*/
|
||||
|
||||
class nsDependentString;
|
||||
class nsDependentCString;
|
||||
|
||||
#endif /* !defined(nsStringFwd_h___) */
|
||||
@@ -1,436 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsStringIterator_h___
|
||||
#define nsStringIterator_h___
|
||||
|
||||
#ifndef nsStringFragment_h___
|
||||
#include "nsStringFragment.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsCharTraits_h___
|
||||
#include "nsCharTraits.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsStringTraits_h___
|
||||
#include "nsStringTraits.h"
|
||||
#endif
|
||||
|
||||
#ifndef nsAlgorithm_h___
|
||||
#include "nsAlgorithm.h"
|
||||
// for |NS_MIN|, |NS_MAX|, and |NS_COUNT|...
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @see nsReadableFragment
|
||||
* @see nsAString
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
class nsReadingIterator
|
||||
// : public bidirectional_iterator_tag
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef const CharT* pointer;
|
||||
typedef const CharT& reference;
|
||||
// typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class nsAString;
|
||||
friend class nsACString;
|
||||
typedef typename nsStringTraits<CharT>::abstract_string_type string_type;
|
||||
|
||||
nsReadableFragment<CharT> mFragment;
|
||||
const CharT* mPosition;
|
||||
const string_type* mOwningString;
|
||||
|
||||
public:
|
||||
nsReadingIterator() { }
|
||||
// nsReadingIterator( const nsReadingIterator<CharT>& ); // auto-generated copy-constructor OK
|
||||
// nsReadingIterator<CharT>& operator=( const nsReadingIterator<CharT>& ); // auto-generated copy-assignment operator OK
|
||||
|
||||
inline void normalize_forward();
|
||||
inline void normalize_backward();
|
||||
|
||||
pointer
|
||||
get() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
CharT
|
||||
operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2)
|
||||
// don't like this when |CharT| is a type without members.
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsReadingIterator<CharT>&
|
||||
operator++()
|
||||
{
|
||||
++mPosition;
|
||||
normalize_forward();
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsReadingIterator<CharT>
|
||||
operator++( int )
|
||||
{
|
||||
nsReadingIterator<CharT> result(*this);
|
||||
++mPosition;
|
||||
normalize_forward();
|
||||
return result;
|
||||
}
|
||||
|
||||
nsReadingIterator<CharT>&
|
||||
operator--()
|
||||
{
|
||||
normalize_backward();
|
||||
--mPosition;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsReadingIterator<CharT>
|
||||
operator--( int )
|
||||
{
|
||||
nsReadingIterator<CharT> result(*this);
|
||||
normalize_backward();
|
||||
--mPosition;
|
||||
return result;
|
||||
}
|
||||
|
||||
const nsReadableFragment<CharT>&
|
||||
fragment() const
|
||||
{
|
||||
return mFragment;
|
||||
}
|
||||
|
||||
const string_type&
|
||||
string() const
|
||||
{
|
||||
NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)");
|
||||
return *mOwningString;
|
||||
}
|
||||
|
||||
difference_type
|
||||
size_forward() const
|
||||
{
|
||||
return mFragment.mEnd - mPosition;
|
||||
}
|
||||
|
||||
difference_type
|
||||
size_backward() const
|
||||
{
|
||||
return mPosition - mFragment.mStart;
|
||||
}
|
||||
|
||||
nsReadingIterator<CharT>&
|
||||
advance( difference_type n )
|
||||
{
|
||||
while ( n > 0 )
|
||||
{
|
||||
difference_type one_hop = NS_MIN(n, size_forward());
|
||||
|
||||
NS_ASSERTION(one_hop>0, "Infinite loop: can't advance a reading iterator beyond the end of a string");
|
||||
// perhaps I should |break| if |!one_hop|?
|
||||
|
||||
mPosition += one_hop;
|
||||
normalize_forward();
|
||||
n -= one_hop;
|
||||
}
|
||||
|
||||
while ( n < 0 )
|
||||
{
|
||||
normalize_backward();
|
||||
difference_type one_hop = NS_MAX(n, -size_backward());
|
||||
|
||||
NS_ASSERTION(one_hop<0, "Infinite loop: can't advance (backward) a reading iterator beyond the end of a string");
|
||||
// perhaps I should |break| if |!one_hop|?
|
||||
|
||||
mPosition += one_hop;
|
||||
n -= one_hop;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
class nsWritingIterator
|
||||
// : public nsReadingIterator<CharT>
|
||||
{
|
||||
public:
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef CharT value_type;
|
||||
typedef CharT* pointer;
|
||||
typedef CharT& reference;
|
||||
// typedef bidirectional_iterator_tag iterator_category;
|
||||
|
||||
private:
|
||||
friend class nsAString;
|
||||
friend class nsACString;
|
||||
typedef typename nsStringTraits<CharT>::abstract_string_type string_type;
|
||||
|
||||
nsWritableFragment<CharT> mFragment;
|
||||
CharT* mPosition;
|
||||
string_type* mOwningString;
|
||||
|
||||
public:
|
||||
nsWritingIterator() { }
|
||||
// nsWritingIterator( const nsWritingIterator<CharT>& ); // auto-generated copy-constructor OK
|
||||
// nsWritingIterator<CharT>& operator=( const nsWritingIterator<CharT>& ); // auto-generated copy-assignment operator OK
|
||||
|
||||
inline void normalize_forward();
|
||||
inline void normalize_backward();
|
||||
|
||||
pointer
|
||||
get() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// An iterator really deserves this, but some compilers (notably IBM VisualAge for OS/2)
|
||||
// don't like this when |CharT| is a type without members.
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsWritingIterator<CharT>&
|
||||
operator++()
|
||||
{
|
||||
++mPosition;
|
||||
normalize_forward();
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsWritingIterator<CharT>
|
||||
operator++( int )
|
||||
{
|
||||
nsWritingIterator<CharT> result(*this);
|
||||
++mPosition;
|
||||
normalize_forward();
|
||||
return result;
|
||||
}
|
||||
|
||||
nsWritingIterator<CharT>&
|
||||
operator--()
|
||||
{
|
||||
normalize_backward();
|
||||
--mPosition;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsWritingIterator<CharT>
|
||||
operator--( int )
|
||||
{
|
||||
nsWritingIterator<CharT> result(*this);
|
||||
normalize_backward();
|
||||
--mPosition;
|
||||
return result;
|
||||
}
|
||||
|
||||
const nsWritableFragment<CharT>&
|
||||
fragment() const
|
||||
{
|
||||
return mFragment;
|
||||
}
|
||||
|
||||
nsWritableFragment<CharT>&
|
||||
fragment()
|
||||
{
|
||||
return mFragment;
|
||||
}
|
||||
|
||||
const string_type&
|
||||
string() const
|
||||
{
|
||||
NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)");
|
||||
return *mOwningString;
|
||||
}
|
||||
|
||||
string_type&
|
||||
string()
|
||||
{
|
||||
NS_ASSERTION(mOwningString, "iterator not attached to a string (|mOwningString| == 0)");
|
||||
return *mOwningString;
|
||||
}
|
||||
|
||||
difference_type
|
||||
size_forward() const
|
||||
{
|
||||
return mFragment.mEnd - mPosition;
|
||||
}
|
||||
|
||||
difference_type
|
||||
size_backward() const
|
||||
{
|
||||
return mPosition - mFragment.mStart;
|
||||
}
|
||||
|
||||
nsWritingIterator<CharT>&
|
||||
advance( difference_type n )
|
||||
{
|
||||
while ( n > 0 )
|
||||
{
|
||||
difference_type one_hop = NS_MIN(n, size_forward());
|
||||
|
||||
NS_ASSERTION(one_hop>0, "Infinite loop: can't advance a writing iterator beyond the end of a string");
|
||||
// perhaps I should |break| if |!one_hop|?
|
||||
|
||||
mPosition += one_hop;
|
||||
normalize_forward();
|
||||
n -= one_hop;
|
||||
}
|
||||
|
||||
while ( n < 0 )
|
||||
{
|
||||
normalize_backward();
|
||||
difference_type one_hop = NS_MAX(n, -size_backward());
|
||||
|
||||
NS_ASSERTION(one_hop<0, "Infinite loop: can't advance (backward) a writing iterator beyond the end of a string");
|
||||
// perhaps I should |break| if |!one_hop|?
|
||||
|
||||
mPosition += one_hop;
|
||||
n -= one_hop;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
PRUint32
|
||||
write( const value_type* s, PRUint32 n )
|
||||
{
|
||||
NS_ASSERTION(size_forward() > 0, "You can't |write| into an |nsWritingIterator| with no space!");
|
||||
|
||||
n = NS_MIN(n, PRUint32(size_forward()));
|
||||
nsCharTraits<value_type>::move(mPosition, s, n);
|
||||
advance( difference_type(n) );
|
||||
return n;
|
||||
}
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
void
|
||||
nsReadingIterator<CharT>::normalize_forward()
|
||||
{
|
||||
while ( mPosition == mFragment.mEnd
|
||||
&& mOwningString->GetReadableFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
void
|
||||
nsReadingIterator<CharT>::normalize_backward()
|
||||
{
|
||||
while ( mPosition == mFragment.mStart
|
||||
&& mOwningString->GetReadableFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
PRBool
|
||||
operator==( const nsReadingIterator<CharT>& lhs, const nsReadingIterator<CharT>& rhs )
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
PRBool
|
||||
operator!=( const nsReadingIterator<CharT>& lhs, const nsReadingIterator<CharT>& rhs )
|
||||
{
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// |nsWritingIterator|s
|
||||
//
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
void
|
||||
nsWritingIterator<CharT>::normalize_forward()
|
||||
{
|
||||
while ( mPosition == mFragment.mEnd
|
||||
&& mOwningString->GetWritableFragment(mFragment, kNextFragment) )
|
||||
mPosition = mFragment.mStart;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
void
|
||||
nsWritingIterator<CharT>::normalize_backward()
|
||||
{
|
||||
while ( mPosition == mFragment.mStart
|
||||
&& mOwningString->GetWritableFragment(mFragment, kPrevFragment) )
|
||||
mPosition = mFragment.mEnd;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
PRBool
|
||||
operator==( const nsWritingIterator<CharT>& lhs, const nsWritingIterator<CharT>& rhs )
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
inline
|
||||
PRBool
|
||||
operator!=( const nsWritingIterator<CharT>& lhs, const nsWritingIterator<CharT>& rhs )
|
||||
{
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
#endif /* !defined(nsStringIterator_h___) */
|
||||
@@ -1,48 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsStringIteratorUtils_h___
|
||||
#define nsStringIteratorUtils_h___
|
||||
|
||||
#ifndef nsStringDefines_h___
|
||||
#include "nsStringDefines.h"
|
||||
#endif
|
||||
|
||||
template <class Iterator>
|
||||
inline
|
||||
PRBool
|
||||
SameFragment( const Iterator& lhs, const Iterator& rhs )
|
||||
{
|
||||
return lhs.fragment().mStart == rhs.fragment().mStart;
|
||||
}
|
||||
|
||||
template <class CharT> class nsReadingIterator;
|
||||
|
||||
// NOTE: need to break iterators out into their own file (as with many classes here), need
|
||||
// these routines, but can't currently |#include "nsReadableUtils.h"|, this hack is bad
|
||||
// but we need it to get OS2 building again. Fix by splitting things into different files.
|
||||
NS_COM size_t Distance( const nsReadingIterator<PRUnichar>&, const nsReadingIterator<PRUnichar>& );
|
||||
NS_COM size_t Distance( const nsReadingIterator<char>&, const nsReadingIterator<char>& );
|
||||
|
||||
|
||||
#endif /* !defined(nsStringIteratorUtils_h___) */
|
||||
@@ -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 Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
/* nsStringTraits.h --- declares specialized ``traits'' classes which allow templatized functions and classes to select appropriate non-template types */
|
||||
|
||||
#ifndef nsStringTraits_h___
|
||||
#define nsStringTraits_h___
|
||||
|
||||
#ifndef nsStringFwd_h___
|
||||
#include "nsStringFwd.h"
|
||||
#endif
|
||||
|
||||
#ifndef nscore_h___
|
||||
#include "nscore.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
template <class CharT>
|
||||
struct nsStringTraits
|
||||
{
|
||||
typedef nsAString abstract_string_type;
|
||||
typedef nsAPromiseString abstract_promise_type;
|
||||
typedef nsAFlatString abstract_flat_type;
|
||||
typedef const nsDependentString literal_string_type;
|
||||
};
|
||||
|
||||
#if 0
|
||||
// for lame compilers, put these declarations into the general case
|
||||
// so we only need to specialize for |char|
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsStringTraits<PRUnichar>
|
||||
{
|
||||
typedef nsAString abstract_string_type;
|
||||
typedef nsAPromiseString abstract_promise_type;
|
||||
typedef nsAFlatString abstract_flat_type;
|
||||
typedef const nsDependentString literal_string_type;
|
||||
};
|
||||
#endif
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
struct nsStringTraits<char>
|
||||
{
|
||||
typedef nsACString abstract_string_type;
|
||||
typedef nsAPromiseCString abstract_promise_type;
|
||||
typedef nsAFlatCString abstract_flat_type;
|
||||
typedef const nsDependentCString literal_string_type;
|
||||
};
|
||||
|
||||
|
||||
#endif /* !defined(nsStringTraits_h___) */
|
||||
@@ -1,251 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#ifndef nsXPIDLString_h___
|
||||
#define nsXPIDLString_h___
|
||||
|
||||
#ifndef nsSharableString_h___
|
||||
#include "nsSharableString.h"
|
||||
#endif
|
||||
|
||||
#if DEBUG_STRING_STATS
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* |nsXPIDLC?String| extends |nsSharableC?String| with the ability
|
||||
* to defer calculation of its length. This is crucial to allowing
|
||||
* the |getter_Copies| assignment behavior.
|
||||
*
|
||||
* The mechanism relies on the fact that |GetSharedBufferHandle|
|
||||
* must be called before any other object can share the buffer,
|
||||
* and as the default implementation for |GetBufferHandle|, which is
|
||||
* the operation on which all other flat string operations are based.
|
||||
* A valid handle always contains a non-|NULL| data start and end.
|
||||
* After use as an `out' string pointer parameter, an |nsXPIDLC?String|'s
|
||||
* handle will have a non-|NULL| data start, but its data end will be
|
||||
* |NULL|. This is the signal that the length needs to be recalculated.
|
||||
* |GetSharedBufferHandle| detects this situation and repairs it.
|
||||
*
|
||||
* An |nsXPIDLC?String| is now a sharable object, just like |nsSharableC?String|.
|
||||
* This simple implementation always allocates an intermediary handle
|
||||
* object. This cost might turn out to be a burden, it's something we'll
|
||||
* want to measure. A couple of optimizations spring to mind if allocation
|
||||
* of the handle objects shows up on the performance radar:
|
||||
* (1) introduce a custom allocator for the handles, e.g., keep free lists
|
||||
* or arena allocate them, or (2) fatten up the |nsXPIDLC?String| with a
|
||||
* local handle, and only allocate a shared handle in the event that
|
||||
* someone actually wants to share. Both of these alternatives add
|
||||
* complexity or space costs, and so we start with the simplest thing
|
||||
* that could possibly work :-)
|
||||
*/
|
||||
|
||||
class NS_COM nsXPIDLString
|
||||
: public nsSharableString
|
||||
{
|
||||
public:
|
||||
nsXPIDLString()
|
||||
{
|
||||
#if DEBUG_STRING_STATS
|
||||
++sCreatedCount;
|
||||
if ( ++sAliveCount > sHighWaterCount )
|
||||
sHighWaterCount = sAliveCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsXPIDLString( const nsXPIDLString& aString )
|
||||
: nsSharableString(aString.GetSharedBufferHandle())
|
||||
// copy-constructor required (or else C++ generates one for us)
|
||||
{
|
||||
#if DEBUG_STRING_STATS
|
||||
++sCreatedCount;
|
||||
if ( ++sAliveCount > sHighWaterCount )
|
||||
sHighWaterCount = sAliveCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_STRING_STATS
|
||||
~nsXPIDLString()
|
||||
{
|
||||
--sAliveCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsXPIDLString&
|
||||
operator=( const nsXPIDLString& rhs )
|
||||
// copy-assignment operator required (or else C++ generates one for us)
|
||||
{
|
||||
// self-assignment is handled by the underlying |nsAutoBufferHandle|
|
||||
mBuffer = rhs.GetSharedBufferHandle();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Adopt( PRUnichar* aNewValue ) { *PrepareForUseAsOutParam() = aNewValue; }
|
||||
|
||||
// deprecated, to be eliminated
|
||||
operator const PRUnichar*() const { return get(); }
|
||||
PRUnichar operator[]( int i ) const { return get()[ i ]; }
|
||||
|
||||
|
||||
class getter_Copies_t
|
||||
{
|
||||
public:
|
||||
getter_Copies_t( nsXPIDLString& aString ) : mString(&aString) { }
|
||||
// getter_Copies_t( const getter_Copies_t& ); // auto-generated copy-constructor OK
|
||||
// getter_Copies_t& operator=( const getter_Copies_t& ); // auto-generated assignment operator OK
|
||||
|
||||
operator PRUnichar**() const { return mString->PrepareForUseAsOutParam(); }
|
||||
|
||||
private:
|
||||
nsXPIDLString* mString;
|
||||
};
|
||||
|
||||
friend class getter_Copies_t;
|
||||
|
||||
protected:
|
||||
#if DEBUG_STRING_STATS
|
||||
virtual const nsBufferHandle<PRUnichar>* GetFlatBufferHandle() const;
|
||||
virtual const nsBufferHandle<PRUnichar>* GetBufferHandle() const;
|
||||
#endif
|
||||
virtual const nsSharedBufferHandle<PRUnichar>* GetSharedBufferHandle() const;
|
||||
// overridden to fix the length after `out' parameter assignment, if necessary
|
||||
|
||||
PRUnichar** PrepareForUseAsOutParam();
|
||||
|
||||
#if DEBUG_STRING_STATS
|
||||
static size_t sCreatedCount; // total number of |nsXPIDLString|s ever created
|
||||
static size_t sAliveCount; // total number of |nsXPIDLStrings|s alive right now
|
||||
static size_t sHighWaterCount; // greatest number of |nsXPIDLString|s alive at once
|
||||
static size_t sAssignCount; // total number of times |nsXPIDLString|s were
|
||||
// assigned into with |getter_Copies|
|
||||
static size_t sShareCount; // total number times |nsXPIDLString|s were asked to share
|
||||
|
||||
public:
|
||||
static void DebugPrintStats( FILE* );
|
||||
#endif
|
||||
};
|
||||
|
||||
inline
|
||||
nsXPIDLString::getter_Copies_t
|
||||
getter_Copies( nsXPIDLString& aString )
|
||||
{
|
||||
return nsXPIDLString::getter_Copies_t(aString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class NS_COM nsXPIDLCString
|
||||
: public nsSharableCString
|
||||
{
|
||||
public:
|
||||
nsXPIDLCString()
|
||||
{
|
||||
#if DEBUG_STRING_STATS
|
||||
++sCreatedCount;
|
||||
if ( ++sAliveCount > sHighWaterCount )
|
||||
sHighWaterCount = sAliveCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsXPIDLCString( const nsXPIDLCString& aString )
|
||||
: nsSharableCString(aString.GetSharedBufferHandle())
|
||||
// copy-constructor required (or else C++ generates one for us)
|
||||
{
|
||||
#if DEBUG_STRING_STATS
|
||||
++sCreatedCount;
|
||||
if ( ++sAliveCount > sHighWaterCount )
|
||||
sHighWaterCount = sAliveCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_STRING_STATS
|
||||
~nsXPIDLCString()
|
||||
{
|
||||
--sAliveCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsXPIDLCString&
|
||||
operator=( const nsXPIDLCString& rhs )
|
||||
// copy-assignment operator required (or else C++ generates one for us)
|
||||
{
|
||||
// self-assignment is handled by the underlying |nsAutoBufferHandle|
|
||||
mBuffer = rhs.GetSharedBufferHandle();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Adopt( char* aNewValue ) { *PrepareForUseAsOutParam() = aNewValue; }
|
||||
|
||||
// deprecated, to be eliminated
|
||||
operator const char*() const { return get(); }
|
||||
char operator[]( int i ) const { return get()[ i ]; }
|
||||
|
||||
|
||||
class getter_Copies_t
|
||||
{
|
||||
public:
|
||||
getter_Copies_t( nsXPIDLCString& aString ) : mString(&aString) { }
|
||||
// getter_Copies_t( const getter_Copies_t& ); // auto-generated copy-constructor OK
|
||||
// getter_Copies_t& operator=( const getter_Copies_t& ); // auto-generated assignment operator OK
|
||||
|
||||
operator char**() const { return mString->PrepareForUseAsOutParam(); }
|
||||
|
||||
private:
|
||||
nsXPIDLCString* mString;
|
||||
};
|
||||
|
||||
friend class getter_Copies_t;
|
||||
|
||||
protected:
|
||||
#if DEBUG_STRING_STATS
|
||||
virtual const nsBufferHandle<char>* GetFlatBufferHandle() const;
|
||||
virtual const nsBufferHandle<char>* GetBufferHandle() const;
|
||||
#endif
|
||||
virtual const nsSharedBufferHandle<char>* GetSharedBufferHandle() const;
|
||||
// overridden to fix the length after `out' parameter assignment, if necessary
|
||||
|
||||
char** PrepareForUseAsOutParam();
|
||||
|
||||
#if DEBUG_STRING_STATS
|
||||
static size_t sCreatedCount; // total number of |nsXPIDLCString|s ever created
|
||||
static size_t sAliveCount; // total number of |nsXPIDLCStrings|s alive right now
|
||||
static size_t sHighWaterCount; // greatest number of |nsXPIDLCString|s alive at once
|
||||
static size_t sAssignCount; // total number of times |nsXPIDLCString|s were
|
||||
// assigned into with |getter_Copies|
|
||||
static size_t sShareCount; // total number times |nsXPIDLCString|s were asked to share
|
||||
|
||||
public:
|
||||
static void DebugPrintStats( FILE* );
|
||||
#endif
|
||||
};
|
||||
|
||||
inline
|
||||
nsXPIDLCString::getter_Copies_t
|
||||
getter_Copies( nsXPIDLCString& aString )
|
||||
{
|
||||
return nsXPIDLCString::getter_Copies_t(aString);
|
||||
}
|
||||
|
||||
#endif /* !defined(nsXPIDLString_h___) */
|
||||
@@ -1,64 +0,0 @@
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
# Scott Collins <scc@mozilla.org>
|
||||
#
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = string
|
||||
LIBRARY_NAME = string_s
|
||||
|
||||
REQUIRES = xpcom
|
||||
|
||||
CPPSRCS = \
|
||||
nsAFlatString.cpp \
|
||||
nsAString.cpp \
|
||||
nsDependentConcatenation.cpp \
|
||||
nsDependentString.cpp \
|
||||
nsDependentSubstring.cpp \
|
||||
nsFragmentedString.cpp \
|
||||
nsPrintfCString.cpp \
|
||||
nsPrivateSharableString.cpp \
|
||||
nsPromiseFlatString.cpp \
|
||||
nsReadableUtils.cpp \
|
||||
nsSharableString.cpp \
|
||||
nsSharedBufferList.cpp \
|
||||
nsSlidingString.cpp \
|
||||
nsXPIDLString.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
# we don't want the shared lib, but we want to force the creation of a
|
||||
# static lib.
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
# Force use of PIC
|
||||
FORCE_USE_PIC = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_COM -D_IMPL_NS_BASE
|
||||
@@ -1,54 +0,0 @@
|
||||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (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/MPL/
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications. Portions created by Netscape Communications are
|
||||
# Copyright (C) 2001 by Netscape Communications. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Johnny Stenback <jst@netscape.com> (original author)
|
||||
# Scott Collins <scc@mozilla.org>
|
||||
#
|
||||
|
||||
DEPTH=..\..
|
||||
|
||||
LIBRARY_NAME=string_s
|
||||
|
||||
LCFLAGS = -D_IMPL_NS_COM -D_IMPL_NS_BASE -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
CPP_OBJS = \
|
||||
.\$(OBJDIR)\nsAFlatString.obj \
|
||||
.\$(OBJDIR)\nsAString.obj \
|
||||
.\$(OBJDIR)\nsDependentConcatenation.obj \
|
||||
.\$(OBJDIR)\nsDependentString.obj \
|
||||
.\$(OBJDIR)\nsDependentSubstring.obj \
|
||||
.\$(OBJDIR)\nsFragmentedString.obj \
|
||||
.\$(OBJDIR)\nsPrintfCString.obj \
|
||||
.\$(OBJDIR)\nsPrivateSharableString.obj \
|
||||
.\$(OBJDIR)\nsPromiseFlatString.obj \
|
||||
.\$(OBJDIR)\nsReadableUtils.obj \
|
||||
.\$(OBJDIR)\nsSharableString.obj \
|
||||
.\$(OBJDIR)\nsSharedBufferList.obj \
|
||||
.\$(OBJDIR)\nsSlidingString.obj \
|
||||
.\$(OBJDIR)\nsXPIDLString.obj \
|
||||
$(NULL)
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
install:: $(LIBRARY)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
|
||||
clobber::
|
||||
rm -f $(DIST)\lib\$(LIBRARY_NAME).lib
|
||||
@@ -1,146 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#include "nsAFlatString.h"
|
||||
|
||||
const PRUnichar*
|
||||
nsAFlatString::GetReadableFragment( nsReadableFragment<PRUnichar>& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
{
|
||||
const nsBufferHandle<PRUnichar>* buffer = GetBufferHandle();
|
||||
NS_ASSERTION(buffer, "trouble: no buffer!");
|
||||
|
||||
aFragment.mEnd = buffer->DataEnd();
|
||||
return (aFragment.mStart = buffer->DataStart()) + aOffset;
|
||||
}
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PRUnichar*
|
||||
nsAFlatString::GetWritableFragment( nsWritableFragment<PRUnichar>& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset )
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
{
|
||||
nsBufferHandle<PRUnichar>* buffer = NS_CONST_CAST(nsBufferHandle<PRUnichar>*, GetBufferHandle());
|
||||
NS_ASSERTION(buffer, "trouble: no buffer!");
|
||||
|
||||
aFragment.mEnd = buffer->DataEnd();
|
||||
return (aFragment.mStart = buffer->DataStart()) + aOffset;
|
||||
}
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
nsAFlatCString::GetReadableFragment( nsReadableFragment<char>& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
{
|
||||
const nsBufferHandle<char>* buffer = GetBufferHandle();
|
||||
NS_ASSERTION(buffer, "trouble: no buffer!");
|
||||
|
||||
aFragment.mEnd = buffer->DataEnd();
|
||||
return (aFragment.mStart = buffer->DataStart()) + aOffset;
|
||||
}
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char*
|
||||
nsAFlatCString::GetWritableFragment( nsWritableFragment<char>& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset )
|
||||
{
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kFirstFragment:
|
||||
case kLastFragment:
|
||||
case kFragmentAt:
|
||||
{
|
||||
nsBufferHandle<char>* buffer = NS_CONST_CAST(nsBufferHandle<char>*, GetBufferHandle());
|
||||
NS_ASSERTION(buffer, "trouble: no buffer!");
|
||||
|
||||
aFragment.mEnd = buffer->DataEnd();
|
||||
return (aFragment.mStart = buffer->DataStart()) + aOffset;
|
||||
}
|
||||
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsAFlatString::Length() const
|
||||
{
|
||||
const nsBufferHandle<PRUnichar>* handle = GetBufferHandle();
|
||||
return PRUint32(handle ? handle->DataLength() : 0);
|
||||
}
|
||||
|
||||
PRUint32
|
||||
nsAFlatCString::Length() const
|
||||
{
|
||||
const nsBufferHandle<char>* handle = GetBufferHandle();
|
||||
return PRUint32(handle ? handle->DataLength() : 0);
|
||||
}
|
||||
|
||||
const PRUnichar*
|
||||
nsAFlatString::get() const
|
||||
{
|
||||
const nsBufferHandle<PRUnichar>* handle = GetBufferHandle();
|
||||
// NS_ASSERTION(handle, "handle is null!");
|
||||
return handle ? handle->DataStart() : 0;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsAFlatCString::get() const
|
||||
{
|
||||
const nsBufferHandle<char>* handle = GetBufferHandle();
|
||||
// NS_ASSERTION(handle, "handle is null!");
|
||||
return handle ? handle->DataStart() : 0;
|
||||
}
|
||||
@@ -1,948 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#include "nsAString.h"
|
||||
#include "nsDependentSubstring.h"
|
||||
#include "nsDependentString.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
|
||||
int
|
||||
nsDefaultStringComparator::operator()( const PRUnichar* lhs, const PRUnichar* rhs, PRUint32 aLength ) const
|
||||
{
|
||||
return nsCharTraits<PRUnichar>::compare(lhs, rhs, aLength);
|
||||
}
|
||||
|
||||
int
|
||||
nsCaseInsensitiveStringComparator::operator()( const PRUnichar* lhs, const PRUnichar* rhs, PRUint32 aLength ) const
|
||||
{
|
||||
return nsCRT::strncasecmp(lhs, rhs, aLength);
|
||||
}
|
||||
|
||||
NS_COM
|
||||
int
|
||||
Compare( const nsAString& lhs, const nsAString& rhs, const nsStringComparator& aComparator )
|
||||
{
|
||||
typedef nsAString::size_type size_type;
|
||||
|
||||
if ( &lhs == &rhs )
|
||||
return 0;
|
||||
|
||||
size_type lLength = lhs.Length();
|
||||
size_type rLength = rhs.Length();
|
||||
size_type lengthToCompare = NS_MIN(lLength, rLength);
|
||||
|
||||
nsAString::const_iterator leftIter, rightIter;
|
||||
lhs.BeginReading(leftIter);
|
||||
rhs.BeginReading(rightIter);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) );
|
||||
|
||||
if ( lengthAvailable > lengthToCompare )
|
||||
lengthAvailable = lengthToCompare;
|
||||
|
||||
{
|
||||
int result;
|
||||
// Note: |result| should be declared in this |if| expression, but some compilers don't like that
|
||||
if ( (result = aComparator(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 )
|
||||
return result;
|
||||
}
|
||||
|
||||
if ( !(lengthToCompare -= lengthAvailable) )
|
||||
break;
|
||||
|
||||
leftIter.advance( PRInt32(lengthAvailable) );
|
||||
rightIter.advance( PRInt32(lengthAvailable) );
|
||||
}
|
||||
|
||||
if ( lLength < rLength )
|
||||
return -1;
|
||||
else if ( rLength < lLength )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsAString::Equals( const char_type* rhs ) const
|
||||
{
|
||||
return Equals(nsDependentString(rhs));
|
||||
}
|
||||
|
||||
|
||||
|
||||
nsAString::char_type
|
||||
nsAString::First() const
|
||||
{
|
||||
NS_ASSERTION(Length()>0, "|First()| on an empty string");
|
||||
|
||||
const_iterator iter;
|
||||
return *BeginReading(iter);
|
||||
}
|
||||
|
||||
nsAString::char_type
|
||||
nsAString::Last() const
|
||||
{
|
||||
NS_ASSERTION(Length()>0, "|Last()| on an empty string");
|
||||
|
||||
const_iterator iter;
|
||||
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
EndReading(iter);
|
||||
iter.advance(-1);
|
||||
}
|
||||
|
||||
return *iter; // Note: this has undefined results if |IsEmpty()|
|
||||
}
|
||||
|
||||
nsAString::size_type
|
||||
nsAString::CountChar( char_type c ) const
|
||||
{
|
||||
/*
|
||||
re-write this to use a counting sink
|
||||
*/
|
||||
|
||||
size_type result = 0;
|
||||
size_type lengthToExamine = Length();
|
||||
|
||||
const_iterator iter;
|
||||
for ( BeginReading(iter); ; )
|
||||
{
|
||||
PRInt32 lengthToExamineInThisFragment = iter.size_forward();
|
||||
const char_type* fromBegin = iter.get();
|
||||
result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
|
||||
if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
|
||||
return result;
|
||||
iter.advance(lengthToExamineInThisFragment);
|
||||
}
|
||||
// never reached; quiets warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsAString::size_type
|
||||
nsAString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const
|
||||
{
|
||||
// If we're just assigning our entire self, give |aResult| the opportunity to share
|
||||
if ( aStartPos == 0 && aLengthToCopy >= Length() )
|
||||
aResult = *this;
|
||||
else
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
nsAString::size_type
|
||||
nsAString::Right( self_type& aResult, size_type aLengthToCopy ) const
|
||||
{
|
||||
size_type myLength = Length();
|
||||
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
|
||||
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsAString::FindChar( char_type aChar, PRUint32 aOffset ) const
|
||||
{
|
||||
const_iterator iter, done_searching;
|
||||
BeginReading(iter).advance( PRInt32(aOffset) );
|
||||
EndReading(done_searching);
|
||||
|
||||
size_type lengthSearched = 0;
|
||||
while ( iter != done_searching )
|
||||
{
|
||||
PRInt32 fragmentLength = iter.size_forward();
|
||||
const char_type* charFoundAt = nsCharTraits<char_type>::find(iter.get(), fragmentLength, aChar);
|
||||
if ( charFoundAt )
|
||||
return lengthSearched + (charFoundAt-iter.get()) + aOffset;
|
||||
|
||||
lengthSearched += fragmentLength;
|
||||
iter.advance(fragmentLength);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// |Assign()|
|
||||
//
|
||||
|
||||
void
|
||||
nsAString::AssignFromReadable( const self_type& rhs )
|
||||
{
|
||||
if ( this != &rhs )
|
||||
do_AssignFromReadable(rhs);
|
||||
// else, self-assign is a no-op
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::AssignFromPromise( const self_type& aReadable )
|
||||
/*
|
||||
...this function is only called when a promise that somehow references |this| is assigned _into_ |this|.
|
||||
E.g.,
|
||||
|
||||
... writable& w ...
|
||||
... readable& r ...
|
||||
|
||||
w = r + w;
|
||||
|
||||
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
|
||||
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
|
||||
of |r| before being retrieved to be appended.
|
||||
|
||||
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
|
||||
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
|
||||
in the case above, |Insert| could have special behavior with significantly better performance. Since
|
||||
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
|
||||
entire promise. If we measure and this turns out to show up on performance radar, we then have the
|
||||
option to fix either the callers or this mechanism.
|
||||
*/
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_AssignFromReadable(aReadable);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
// Note: not exception safe. We need something to manage temporary buffers like this
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_AssignFromElementPtrLength(buffer, length);
|
||||
delete buffer;
|
||||
}
|
||||
// else assert?
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AssignFromReadable( const self_type& aReadable )
|
||||
{
|
||||
SetLength(0);
|
||||
SetLength(aReadable.Length());
|
||||
// first setting the length to |0| avoids copying characters only to be overwritten later
|
||||
// in the case where the implementation decides to re-allocate
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin));
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AssignFromElementPtr( const char_type* aPtr )
|
||||
{
|
||||
do_AssignFromReadable(nsDependentString(aPtr));
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength )
|
||||
{
|
||||
do_AssignFromReadable(nsDependentString(aPtr, aLength));
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AssignFromElement( char_type aChar )
|
||||
{
|
||||
do_AssignFromReadable(nsDependentString(&aChar, 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Append()|
|
||||
//
|
||||
|
||||
void
|
||||
nsAString::AppendFromReadable( const self_type& aReadable )
|
||||
{
|
||||
if ( this != &aReadable )
|
||||
do_AppendFromReadable(aReadable);
|
||||
else
|
||||
AppendFromPromise(aReadable);
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::AppendFromPromise( const self_type& aReadable )
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_AppendFromReadable(aReadable);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_AppendFromElementPtrLength(buffer, length);
|
||||
delete buffer;
|
||||
}
|
||||
// else assert?
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AppendFromReadable( const self_type& aReadable )
|
||||
{
|
||||
size_type oldLength = this->Length();
|
||||
SetLength(oldLength + aReadable.Length());
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) );
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AppendFromElementPtr( const char_type* aPtr )
|
||||
{
|
||||
do_AppendFromReadable(nsDependentString(aPtr));
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AppendFromElementPtrLength( const char_type* aPtr, size_type aLength )
|
||||
{
|
||||
do_AppendFromReadable(nsDependentString(aPtr, aLength));
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_AppendFromElement( char_type aChar )
|
||||
{
|
||||
do_AppendFromReadable(nsDependentString(&aChar, 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Insert()|
|
||||
//
|
||||
|
||||
void
|
||||
nsAString::InsertFromReadable( const self_type& aReadable, index_type atPosition )
|
||||
{
|
||||
if ( this != &aReadable )
|
||||
do_InsertFromReadable(aReadable, atPosition);
|
||||
else
|
||||
InsertFromPromise(aReadable, atPosition);
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::InsertFromPromise( const self_type& aReadable, index_type atPosition )
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_InsertFromReadable(aReadable, atPosition);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_InsertFromElementPtrLength(buffer, atPosition, length);
|
||||
delete buffer;
|
||||
}
|
||||
// else assert
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition )
|
||||
{
|
||||
size_type oldLength = this->Length();
|
||||
SetLength(oldLength + aReadable.Length());
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
if ( atPosition < oldLength )
|
||||
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
|
||||
else
|
||||
atPosition = oldLength;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition)));
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition )
|
||||
{
|
||||
do_InsertFromReadable(nsDependentString(aPtr), atPosition);
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength )
|
||||
{
|
||||
do_InsertFromReadable(nsDependentString(aPtr, aLength), atPosition);
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_InsertFromElement( char_type aChar, index_type atPosition )
|
||||
{
|
||||
do_InsertFromReadable(nsDependentString(&aChar, 1), atPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Cut()|
|
||||
//
|
||||
|
||||
void
|
||||
nsAString::Cut( index_type cutStart, size_type cutLength )
|
||||
{
|
||||
size_type myLength = this->Length();
|
||||
cutLength = NS_MIN(cutLength, myLength-cutStart);
|
||||
index_type cutEnd = cutStart + cutLength;
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
if ( cutEnd < myLength )
|
||||
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
|
||||
SetLength(myLength-cutLength);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Replace()|
|
||||
//
|
||||
|
||||
void
|
||||
nsAString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
|
||||
{
|
||||
if ( this != &aReplacement )
|
||||
do_ReplaceFromReadable(cutStart, cutLength, aReplacement);
|
||||
else
|
||||
ReplaceFromPromise(cutStart, cutLength, aReplacement);
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable )
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_ReplaceFromReadable(cutStart, cutLength, aReadable);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_ReplaceFromReadable(cutStart, cutLength, nsDependentString(buffer, length));
|
||||
delete buffer;
|
||||
}
|
||||
// else assert?
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
|
||||
{
|
||||
size_type oldLength = this->Length();
|
||||
|
||||
cutStart = NS_MIN(cutStart, oldLength);
|
||||
cutLength = NS_MIN(cutLength, oldLength-cutStart);
|
||||
index_type cutEnd = cutStart + cutLength;
|
||||
|
||||
size_type replacementLength = aReplacement.Length();
|
||||
index_type replacementEnd = cutStart + replacementLength;
|
||||
|
||||
size_type newLength = oldLength - cutLength + replacementLength;
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
if ( cutLength > replacementLength )
|
||||
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
|
||||
SetLength(newLength);
|
||||
if ( cutLength < replacementLength )
|
||||
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
|
||||
|
||||
copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
nsDefaultCStringComparator::operator()( const char* lhs, const char* rhs, PRUint32 aLength ) const
|
||||
{
|
||||
return nsCharTraits<char>::compare(lhs, rhs, aLength);
|
||||
}
|
||||
|
||||
int
|
||||
nsCaseInsensitiveCStringComparator::operator()( const char* lhs, const char* rhs, PRUint32 aLength ) const
|
||||
{
|
||||
return nsCRT::strncasecmp(lhs, rhs, aLength);
|
||||
}
|
||||
|
||||
NS_COM
|
||||
int
|
||||
Compare( const nsACString& lhs, const nsACString& rhs, const nsCStringComparator& aComparator )
|
||||
{
|
||||
typedef nsACString::size_type size_type;
|
||||
|
||||
if ( &lhs == &rhs )
|
||||
return 0;
|
||||
|
||||
size_type lLength = lhs.Length();
|
||||
size_type rLength = rhs.Length();
|
||||
size_type lengthToCompare = NS_MIN(lLength, rLength);
|
||||
|
||||
nsACString::const_iterator leftIter, rightIter;
|
||||
lhs.BeginReading(leftIter);
|
||||
rhs.BeginReading(rightIter);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_type lengthAvailable = size_type( NS_MIN(leftIter.size_forward(), rightIter.size_forward()) );
|
||||
|
||||
if ( lengthAvailable > lengthToCompare )
|
||||
lengthAvailable = lengthToCompare;
|
||||
|
||||
{
|
||||
int result;
|
||||
// Note: |result| should be declared in this |if| expression, but some compilers don't like that
|
||||
if ( (result = aComparator(leftIter.get(), rightIter.get(), lengthAvailable)) != 0 )
|
||||
return result;
|
||||
}
|
||||
|
||||
if ( !(lengthToCompare -= lengthAvailable) )
|
||||
break;
|
||||
|
||||
leftIter.advance( PRInt32(lengthAvailable) );
|
||||
rightIter.advance( PRInt32(lengthAvailable) );
|
||||
}
|
||||
|
||||
if ( lLength < rLength )
|
||||
return -1;
|
||||
else if ( rLength < lLength )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsACString::Equals( const char_type* rhs ) const
|
||||
{
|
||||
return Equals(nsDependentCString(rhs));
|
||||
}
|
||||
|
||||
nsACString::char_type
|
||||
nsACString::First() const
|
||||
{
|
||||
NS_ASSERTION(Length()>0, "|First()| on an empty string");
|
||||
|
||||
const_iterator iter;
|
||||
return *BeginReading(iter);
|
||||
}
|
||||
|
||||
nsACString::char_type
|
||||
nsACString::Last() const
|
||||
{
|
||||
NS_ASSERTION(Length()>0, "|Last()| on an empty string");
|
||||
|
||||
const_iterator iter;
|
||||
|
||||
if ( !IsEmpty() )
|
||||
{
|
||||
EndReading(iter);
|
||||
iter.advance(-1);
|
||||
}
|
||||
|
||||
return *iter; // Note: this has undefined results if |IsEmpty()|
|
||||
}
|
||||
|
||||
nsACString::size_type
|
||||
nsACString::CountChar( char_type c ) const
|
||||
{
|
||||
/*
|
||||
re-write this to use a counting sink
|
||||
*/
|
||||
|
||||
size_type result = 0;
|
||||
size_type lengthToExamine = Length();
|
||||
|
||||
const_iterator iter;
|
||||
for ( BeginReading(iter); ; )
|
||||
{
|
||||
PRInt32 lengthToExamineInThisFragment = iter.size_forward();
|
||||
const char_type* fromBegin = iter.get();
|
||||
result += size_type(NS_COUNT(fromBegin, fromBegin+lengthToExamineInThisFragment, c));
|
||||
if ( !(lengthToExamine -= lengthToExamineInThisFragment) )
|
||||
return result;
|
||||
iter.advance(lengthToExamineInThisFragment);
|
||||
}
|
||||
// never reached; quiets warnings
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsACString::size_type
|
||||
nsACString::Mid( self_type& aResult, index_type aStartPos, size_type aLengthToCopy ) const
|
||||
{
|
||||
// If we're just assigning our entire self, give |aResult| the opportunity to share
|
||||
if ( aStartPos == 0 && aLengthToCopy >= Length() )
|
||||
aResult = *this;
|
||||
else
|
||||
aResult = Substring(*this, aStartPos, aLengthToCopy);
|
||||
|
||||
return aResult.Length();
|
||||
}
|
||||
|
||||
nsACString::size_type
|
||||
nsACString::Right( self_type& aResult, size_type aLengthToCopy ) const
|
||||
{
|
||||
size_type myLength = Length();
|
||||
aLengthToCopy = NS_MIN(myLength, aLengthToCopy);
|
||||
return Mid(aResult, myLength-aLengthToCopy, aLengthToCopy);
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsACString::FindChar( char_type aChar, PRUint32 aOffset ) const
|
||||
{
|
||||
const_iterator iter, done_searching;
|
||||
BeginReading(iter).advance( PRInt32(aOffset) );
|
||||
EndReading(done_searching);
|
||||
|
||||
size_type lengthSearched = 0;
|
||||
while ( iter != done_searching )
|
||||
{
|
||||
PRInt32 fragmentLength = iter.size_forward();
|
||||
const char_type* charFoundAt = nsCharTraits<char_type>::find(iter.get(), fragmentLength, aChar);
|
||||
if ( charFoundAt )
|
||||
return lengthSearched + (charFoundAt-iter.get()) + aOffset;
|
||||
|
||||
lengthSearched += fragmentLength;
|
||||
iter.advance(fragmentLength);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// |Assign()|
|
||||
//
|
||||
|
||||
void
|
||||
nsACString::AssignFromReadable( const self_type& rhs )
|
||||
{
|
||||
if ( this != &rhs )
|
||||
do_AssignFromReadable(rhs);
|
||||
// else, self-assign is a no-op
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::AssignFromPromise( const self_type& aReadable )
|
||||
/*
|
||||
...this function is only called when a promise that somehow references |this| is assigned _into_ |this|.
|
||||
E.g.,
|
||||
|
||||
... writable& w ...
|
||||
... readable& r ...
|
||||
|
||||
w = r + w;
|
||||
|
||||
In this example, you can see that unless the characters promised by |w| in |r+w| are resolved before
|
||||
anything starts getting copied into |w|, there will be trouble. They will be overritten by the contents
|
||||
of |r| before being retrieved to be appended.
|
||||
|
||||
We could have a really tricky solution where we tell the promise to resolve _just_ the data promised
|
||||
by |this|, but this should be a rare case, since clients with more local knowledge will know that, e.g.,
|
||||
in the case above, |Insert| could have special behavior with significantly better performance. Since
|
||||
it's a rare case anyway, we should just do the simplest thing that could possibly work, resolve the
|
||||
entire promise. If we measure and this turns out to show up on performance radar, we then have the
|
||||
option to fix either the callers or this mechanism.
|
||||
*/
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_AssignFromReadable(aReadable);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
// Note: not exception safe. We need something to manage temporary buffers like this
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_AssignFromElementPtrLength(buffer, length);
|
||||
delete buffer;
|
||||
}
|
||||
// else assert?
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AssignFromReadable( const self_type& aReadable )
|
||||
{
|
||||
SetLength(0);
|
||||
SetLength(aReadable.Length());
|
||||
// first setting the length to |0| avoids copying characters only to be overwritten later
|
||||
// in the case where the implementation decides to re-allocate
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin));
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AssignFromElementPtr( const char_type* aPtr )
|
||||
{
|
||||
do_AssignFromReadable(nsDependentCString(aPtr));
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AssignFromElementPtrLength( const char_type* aPtr, size_type aLength )
|
||||
{
|
||||
do_AssignFromReadable(nsDependentCString(aPtr, aLength));
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AssignFromElement( char_type aChar )
|
||||
{
|
||||
do_AssignFromReadable(nsDependentCString(&aChar, 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Append()|
|
||||
//
|
||||
|
||||
void
|
||||
nsACString::AppendFromReadable( const self_type& aReadable )
|
||||
{
|
||||
if ( this != &aReadable )
|
||||
do_AppendFromReadable(aReadable);
|
||||
else
|
||||
AppendFromPromise(aReadable);
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::AppendFromPromise( const self_type& aReadable )
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_AppendFromReadable(aReadable);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_AppendFromElementPtrLength(buffer, length);
|
||||
delete buffer;
|
||||
}
|
||||
// else assert?
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AppendFromReadable( const self_type& aReadable )
|
||||
{
|
||||
size_type oldLength = this->Length();
|
||||
SetLength(oldLength + aReadable.Length());
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance( PRInt32(oldLength) ) );
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AppendFromElementPtr( const char_type* aPtr )
|
||||
{
|
||||
do_AppendFromReadable(nsDependentCString(aPtr));
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AppendFromElementPtrLength( const char_type* aPtr, size_type aLength )
|
||||
{
|
||||
do_AppendFromReadable(nsDependentCString(aPtr, aLength));
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_AppendFromElement( char_type aChar )
|
||||
{
|
||||
do_AppendFromReadable(nsDependentCString(&aChar, 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Insert()|
|
||||
//
|
||||
|
||||
void
|
||||
nsACString::InsertFromReadable( const self_type& aReadable, index_type atPosition )
|
||||
{
|
||||
if ( this != &aReadable )
|
||||
do_InsertFromReadable(aReadable, atPosition);
|
||||
else
|
||||
InsertFromPromise(aReadable, atPosition);
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::InsertFromPromise( const self_type& aReadable, index_type atPosition )
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_InsertFromReadable(aReadable, atPosition);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_InsertFromElementPtrLength(buffer, atPosition, length);
|
||||
delete buffer;
|
||||
}
|
||||
// else assert
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_InsertFromReadable( const self_type& aReadable, index_type atPosition )
|
||||
{
|
||||
size_type oldLength = this->Length();
|
||||
SetLength(oldLength + aReadable.Length());
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
if ( atPosition < oldLength )
|
||||
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(atPosition)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), EndWriting(toBegin));
|
||||
else
|
||||
atPosition = oldLength;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(atPosition)));
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_InsertFromElementPtr( const char_type* aPtr, index_type atPosition )
|
||||
{
|
||||
do_InsertFromReadable(nsDependentCString(aPtr), atPosition);
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_InsertFromElementPtrLength( const char_type* aPtr, index_type atPosition, size_type aLength )
|
||||
{
|
||||
do_InsertFromReadable(nsDependentCString(aPtr, aLength), atPosition);
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_InsertFromElement( char_type aChar, index_type atPosition )
|
||||
{
|
||||
do_InsertFromReadable(nsDependentCString(&aChar, 1), atPosition);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Cut()|
|
||||
//
|
||||
|
||||
void
|
||||
nsACString::Cut( index_type cutStart, size_type cutLength )
|
||||
{
|
||||
size_type myLength = this->Length();
|
||||
cutLength = NS_MIN(cutLength, myLength-cutStart);
|
||||
index_type cutEnd = cutStart + cutLength;
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
if ( cutEnd < myLength )
|
||||
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
|
||||
SetLength(myLength-cutLength);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// |Replace()|
|
||||
//
|
||||
|
||||
void
|
||||
nsACString::ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
|
||||
{
|
||||
if ( this != &aReplacement )
|
||||
do_ReplaceFromReadable(cutStart, cutLength, aReplacement);
|
||||
else
|
||||
ReplaceFromPromise(cutStart, cutLength, aReplacement);
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::ReplaceFromPromise( index_type cutStart, size_type cutLength, const self_type& aReadable )
|
||||
{
|
||||
if ( !aReadable.IsDependentOn(*this) )
|
||||
do_ReplaceFromReadable(cutStart, cutLength, aReadable);
|
||||
else
|
||||
{
|
||||
size_type length = aReadable.Length();
|
||||
char_type* buffer = new char_type[length];
|
||||
if ( buffer )
|
||||
{
|
||||
const_iterator fromBegin, fromEnd;
|
||||
char_type* toBegin = buffer;
|
||||
copy_string(aReadable.BeginReading(fromBegin), aReadable.EndReading(fromEnd), toBegin);
|
||||
do_ReplaceFromReadable(cutStart, cutLength, nsDependentCString(buffer, length));
|
||||
delete buffer;
|
||||
}
|
||||
// else assert?
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsACString::do_ReplaceFromReadable( index_type cutStart, size_type cutLength, const self_type& aReplacement )
|
||||
{
|
||||
size_type oldLength = this->Length();
|
||||
|
||||
cutStart = NS_MIN(cutStart, oldLength);
|
||||
cutLength = NS_MIN(cutLength, oldLength-cutStart);
|
||||
index_type cutEnd = cutStart + cutLength;
|
||||
|
||||
size_type replacementLength = aReplacement.Length();
|
||||
index_type replacementEnd = cutStart + replacementLength;
|
||||
|
||||
size_type newLength = oldLength - cutLength + replacementLength;
|
||||
|
||||
const_iterator fromBegin, fromEnd;
|
||||
iterator toBegin;
|
||||
if ( cutLength > replacementLength )
|
||||
copy_string(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
|
||||
SetLength(newLength);
|
||||
if ( cutLength < replacementLength )
|
||||
copy_string_backward(this->BeginReading(fromBegin).advance(PRInt32(cutEnd)), this->BeginReading(fromEnd).advance(PRInt32(oldLength)), BeginWriting(toBegin).advance(PRInt32(replacementEnd)));
|
||||
|
||||
copy_string(aReplacement.BeginReading(fromBegin), aReplacement.EndReading(fromEnd), BeginWriting(toBegin).advance(PRInt32(cutStart)));
|
||||
}
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
//-------1---------2---------3---------4---------5---------6---------7---------8
|
||||
|
||||
#include "nsAString.h"
|
||||
// remember, no one should include "nsDependentConcatenation.h" themselves
|
||||
// one always gets it through "nsAString.h"
|
||||
|
||||
#ifndef nsDependentConcatenation_h___
|
||||
#include "nsDependentConcatenation.h"
|
||||
#endif
|
||||
|
||||
|
||||
PRUint32
|
||||
nsDependentConcatenation::Length() const
|
||||
{
|
||||
return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length();
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDependentConcatenation::IsDependentOn( const string_type& aString ) const
|
||||
{
|
||||
return mStrings[0]->IsDependentOn(aString) || mStrings[1]->IsDependentOn(aString);
|
||||
}
|
||||
|
||||
#if 0
|
||||
PRBool
|
||||
nsDependentConcatenation::PromisesExactly( const string_type& aString ) const
|
||||
{
|
||||
// Not really like this, test for the empty string, etc
|
||||
return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString;
|
||||
}
|
||||
#endif
|
||||
|
||||
const PRUnichar*
|
||||
nsDependentConcatenation::GetReadableFragment( nsReadableFragment<char_type>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
int whichString;
|
||||
|
||||
// based on the request, pick which string we will forward the |GetReadableFragment()| call into
|
||||
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
whichString = GetCurrentStringFromFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
PRUint32 leftLength = mStrings[kLeftString]->Length();
|
||||
if ( aPosition < leftLength )
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
else
|
||||
{
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
aPosition -= leftLength;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
const char_type* result;
|
||||
PRBool done;
|
||||
do
|
||||
{
|
||||
done = PR_TRUE;
|
||||
result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
done = PR_FALSE;
|
||||
if ( aRequest == kNextFragment && whichString == kLeftString )
|
||||
{
|
||||
aRequest = kFirstFragment;
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
}
|
||||
else if ( aRequest == kPrevFragment && whichString == kRightString )
|
||||
{
|
||||
aRequest = kLastFragment;
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
}
|
||||
else
|
||||
done = PR_TRUE;
|
||||
}
|
||||
}
|
||||
while ( !done );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PRUint32
|
||||
nsDependentCConcatenation::Length() const
|
||||
{
|
||||
return mStrings[kLeftString]->Length() + mStrings[kRightString]->Length();
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDependentCConcatenation::IsDependentOn( const string_type& aString ) const
|
||||
{
|
||||
return mStrings[0]->IsDependentOn(aString) || mStrings[1]->IsDependentOn(aString);
|
||||
}
|
||||
|
||||
#if 0
|
||||
PRBool
|
||||
nsDependentCConcatenation::PromisesExactly( const string_type& aString ) const
|
||||
{
|
||||
// Not really like this, test for the empty string, etc
|
||||
return mStrings[0] == &aString && !mStrings[1] || !mStrings[0] && mStrings[1] == &aString;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char*
|
||||
nsDependentCConcatenation::GetReadableFragment( nsReadableFragment<char_type>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
int whichString;
|
||||
|
||||
// based on the request, pick which string we will forward the |GetReadableFragment()| call into
|
||||
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
case kNextFragment:
|
||||
whichString = GetCurrentStringFromFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
PRUint32 leftLength = mStrings[kLeftString]->Length();
|
||||
if ( aPosition < leftLength )
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
else
|
||||
{
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
aPosition -= leftLength;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
const char_type* result;
|
||||
PRBool done;
|
||||
do
|
||||
{
|
||||
done = PR_TRUE;
|
||||
result = mStrings[whichString]->GetReadableFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
if ( !result )
|
||||
{
|
||||
done = PR_FALSE;
|
||||
if ( aRequest == kNextFragment && whichString == kLeftString )
|
||||
{
|
||||
aRequest = kFirstFragment;
|
||||
whichString = SetRightStringInFragment(aFragment);
|
||||
}
|
||||
else if ( aRequest == kPrevFragment && whichString == kRightString )
|
||||
{
|
||||
aRequest = kLastFragment;
|
||||
whichString = SetLeftStringInFragment(aFragment);
|
||||
}
|
||||
else
|
||||
done = PR_TRUE;
|
||||
}
|
||||
}
|
||||
while ( !done );
|
||||
return result;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#include "nsDependentString.h"
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications. Portions created by Netscape Communications are
|
||||
* Copyright (C) 2001 by Netscape Communications. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Scott Collins <scc@mozilla.org> (original author)
|
||||
*/
|
||||
|
||||
#include "nsDependentSubstring.h"
|
||||
|
||||
PRUint32
|
||||
nsDependentSubstring::Length() const
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
const PRUnichar*
|
||||
nsDependentSubstring::GetReadableFragment( nsReadableFragment<PRUnichar>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
// Offset any request for a specific position (First, Last, At) by our
|
||||
// substrings startpos within the owning string
|
||||
|
||||
if ( aRequest == kFirstFragment )
|
||||
{
|
||||
aPosition = mStartPos;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kLastFragment )
|
||||
{
|
||||
aPosition = mStartPos + mLength;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kFragmentAt )
|
||||
aPosition += mStartPos;
|
||||
|
||||
// requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing
|
||||
|
||||
const PRUnichar* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
// If |GetReadableFragment| returns |0|, then we are off the string, the contents of the
|
||||
// fragment are garbage.
|
||||
|
||||
// Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null
|
||||
if ( position_ptr )
|
||||
{
|
||||
// if there's more physical data in the returned fragment than I logically have left...
|
||||
size_t logical_size_backward = aPosition - mStartPos;
|
||||
if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward )
|
||||
aFragment.mStart = position_ptr - logical_size_backward;
|
||||
|
||||
size_t logical_size_forward = mLength - logical_size_backward;
|
||||
if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward )
|
||||
aFragment.mEnd = position_ptr + logical_size_forward;
|
||||
}
|
||||
|
||||
return position_ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PRUint32
|
||||
nsDependentCSubstring::Length() const
|
||||
{
|
||||
return mLength;
|
||||
}
|
||||
|
||||
const char*
|
||||
nsDependentCSubstring::GetReadableFragment( nsReadableFragment<char>& aFragment, nsFragmentRequest aRequest, PRUint32 aPosition ) const
|
||||
{
|
||||
// Offset any request for a specific position (First, Last, At) by our
|
||||
// substrings startpos within the owning string
|
||||
|
||||
if ( aRequest == kFirstFragment )
|
||||
{
|
||||
aPosition = mStartPos;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kLastFragment )
|
||||
{
|
||||
aPosition = mStartPos + mLength;
|
||||
aRequest = kFragmentAt;
|
||||
}
|
||||
else if ( aRequest == kFragmentAt )
|
||||
aPosition += mStartPos;
|
||||
|
||||
// requests for |kNextFragment| or |kPrevFragment| are just relayed down into the string we're slicing
|
||||
|
||||
const char* position_ptr = mString.GetReadableFragment(aFragment, aRequest, aPosition);
|
||||
|
||||
// If |GetReadableFragment| returns |0|, then we are off the string, the contents of the
|
||||
// fragment are garbage.
|
||||
|
||||
// Therefore, only need to fix up the fragment boundaries when |position_ptr| is not null
|
||||
if ( position_ptr )
|
||||
{
|
||||
// if there's more physical data in the returned fragment than I logically have left...
|
||||
size_t logical_size_backward = aPosition - mStartPos;
|
||||
if ( size_t(position_ptr - aFragment.mStart) > logical_size_backward )
|
||||
aFragment.mStart = position_ptr - logical_size_backward;
|
||||
|
||||
size_t logical_size_forward = mLength - logical_size_backward;
|
||||
if ( size_t(aFragment.mEnd - position_ptr) > logical_size_forward )
|
||||
aFragment.mEnd = position_ptr + logical_size_forward;
|
||||
}
|
||||
|
||||
return position_ptr;
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (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/MPL/
|
||||
*
|
||||
* 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 XPCOM.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Original Author:
|
||||
* Scott Collins <scc@mozilla.org>
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
#include "nsFragmentedString.h"
|
||||
|
||||
|
||||
const PRUnichar*
|
||||
nsFragmentedString::GetReadableFragment( nsReadableFragment<PRUnichar>& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset ) const
|
||||
{
|
||||
const nsSharedBufferList::Buffer* buffer = 0;
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
buffer = NS_STATIC_CAST(const nsSharedBufferList::Buffer*, aFragment.mFragmentIdentifier)->mPrev;
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
buffer = mBufferList.GetFirstBuffer();
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
buffer = mBufferList.GetLastBuffer();
|
||||
break;
|
||||
|
||||
case kNextFragment:
|
||||
buffer = NS_STATIC_CAST(const nsSharedBufferList::Buffer*, aFragment.mFragmentIdentifier)->mNext;
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
// ...work...
|
||||
break;
|
||||
}
|
||||
|
||||
if ( buffer )
|
||||
{
|
||||
aFragment.mStart = buffer->DataStart();
|
||||
aFragment.mEnd = buffer->DataEnd();
|
||||
aFragment.mFragmentIdentifier = buffer;
|
||||
return aFragment.mStart + aOffset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PRUnichar*
|
||||
nsFragmentedString::GetWritableFragment( nsWritableFragment<PRUnichar>& aFragment, nsFragmentRequest aRequest, PRUint32 aOffset )
|
||||
{
|
||||
nsSharedBufferList::Buffer* buffer = 0;
|
||||
switch ( aRequest )
|
||||
{
|
||||
case kPrevFragment:
|
||||
buffer = NS_STATIC_CAST(nsSharedBufferList::Buffer*, aFragment.mFragmentIdentifier)->mPrev;
|
||||
break;
|
||||
|
||||
case kFirstFragment:
|
||||
buffer = mBufferList.GetFirstBuffer();
|
||||
break;
|
||||
|
||||
case kLastFragment:
|
||||
buffer = mBufferList.GetLastBuffer();
|
||||
break;
|
||||
|
||||
case kNextFragment:
|
||||
buffer = NS_STATIC_CAST(nsSharedBufferList::Buffer*, aFragment.mFragmentIdentifier)->mNext;
|
||||
break;
|
||||
|
||||
case kFragmentAt:
|
||||
// ...work...
|
||||
break;
|
||||
}
|
||||
|
||||
if ( buffer )
|
||||
{
|
||||
aFragment.mStart = buffer->DataStart();
|
||||
aFragment.mEnd = buffer->DataEnd();
|
||||
aFragment.mFragmentIdentifier = buffer;
|
||||
return aFragment.mStart + aOffset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
PRUint32
|
||||
nsFragmentedString::Length() const
|
||||
{
|
||||
return PRUint32(mBufferList.GetDataLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* |SetLength|
|
||||
*/
|
||||
void
|
||||
nsFragmentedString::SetLength( PRUint32 aNewLength )
|
||||
{
|
||||
// according to the current interpretation of |SetLength|,
|
||||
// cut off characters from the end, or else add unitialized space to fill
|
||||
|
||||
if ( aNewLength < PRUint32(mBufferList.GetDataLength()) )
|
||||
{
|
||||
// if ( aNewLength )
|
||||
mBufferList.DiscardSuffix(mBufferList.GetDataLength()-aNewLength);
|
||||
// else
|
||||
// mBufferList.DestroyBuffers();
|
||||
}
|
||||
|
||||
// temporarily... eliminate as soon as our munging routines don't need this form of |SetLength|
|
||||
else if ( aNewLength > PRUint32(mBufferList.GetDataLength()) )
|
||||
{
|
||||
size_t empty_space_to_add = aNewLength - mBufferList.GetDataLength();
|
||||
nsSharedBufferList::Buffer* new_buffer = nsSharedBufferList::NewSingleAllocationBuffer(0, 0, empty_space_to_add);
|
||||
new_buffer->DataEnd(new_buffer->DataStart()+empty_space_to_add);
|
||||
mBufferList.LinkBuffer(mBufferList.GetLastBuffer(), new_buffer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* |SetCapacity|.
|
||||
*
|
||||
* If a client tries to increase the capacity of multi-fragment string, perhaps a single
|
||||
* empty fragment of the appropriate size should be appended.
|
||||
*/
|
||||
void
|
||||
nsFragmentedString::SetCapacity( PRUint32 aNewCapacity )
|
||||
{
|
||||
if ( !aNewCapacity )
|
||||
{
|
||||
// |SetCapacity(0)| is special and means ``release all storage''.
|
||||
}
|
||||
else if ( aNewCapacity > ... )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user