📄 contain.cxx
字号:
/*
* contain.cxx
*
* Container Classes
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/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 Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Revision: 19572 $
* $Author: rjongbloed $
* $Date: 2008-02-21 02:34:24 +0000 (Thu, 21 Feb 2008) $
*/
#include <ptlib.h>
#include <ctype.h>
#ifdef __NUCLEUS_PLUS__
extern "C" int vsprintf(char *, const char *, va_list);
#endif
#if P_REGEX
#include <regex.h>
#else
#include "regex/regex.h"
#endif
#define regexpression ((regex_t *)expression)
#if !P_USE_INLINES
#include "ptlib/contain.inl"
#endif
#define new PNEW
#undef __CLASS__
#define __CLASS__ GetClass()
///////////////////////////////////////////////////////////////////////////////
PContainer::PContainer(PINDEX initialSize)
{
reference = new PContainerReference(initialSize);
PAssert(reference != NULL, POutOfMemory);
}
PContainer::PContainer(int, const PContainer * cont)
{
if (cont == this)
return;
PAssert(cont != NULL, PInvalidParameter);
PAssert2(cont->reference != NULL, cont->GetClass(), "Clone of deleted container");
reference = new PContainerReference(*cont->reference); // create a new reference
PAssert(reference != NULL, POutOfMemory);
}
PContainer::PContainer(const PContainer & cont)
{
if (&cont == this)
return;
PAssert2(cont.reference != NULL, cont.GetClass(), "Copy of deleted container");
++cont.reference->count;
reference = cont.reference; // copy the reference pointer
}
void PContainer::AssignContents(const PContainer & cont)
{
if(cont.reference == NULL){
PAssertAlways("container reference is null");
return;
} else if(cont.GetClass() == NULL){
PAssertAlways("container class is null");
return;
}
if (reference == cont.reference) {
return;
}
if (--reference->count == 0) {
DestroyContents();
delete reference;
reference = NULL;
}
++cont.reference->count;
reference = cont.reference;
}
void PContainer::Destruct()
{
if (reference != NULL) {
if (--reference->count > 0) {
reference = NULL;
}
else {
DestroyContents();
delete reference;
reference = NULL;
}
}
}
PBoolean PContainer::SetMinSize(PINDEX minSize)
{
PASSERTINDEX(minSize);
if (minSize < 0)
minSize = 0;
if (minSize < GetSize())
minSize = GetSize();
return SetSize(minSize);
}
PBoolean PContainer::MakeUnique()
{
if (IsUnique())
return PTrue;
PContainerReference * oldReference = reference;
reference = new PContainerReference(*reference);
--oldReference->count;
return PFalse;
}
///////////////////////////////////////////////////////////////////////////////
PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes, PINDEX initialSize)
: PContainer(initialSize)
{
elementSize = elementSizeInBytes;
PAssert(elementSize != 0, PInvalidParameter);
if (GetSize() == 0)
theArray = NULL;
else {
theArray = (char *)calloc(GetSize(), elementSize);
PAssert(theArray != NULL, POutOfMemory);
}
allocatedDynamically = PTrue;
}
PAbstractArray::PAbstractArray(PINDEX elementSizeInBytes,
const void *buffer,
PINDEX bufferSizeInElements,
PBoolean dynamicAllocation)
: PContainer(bufferSizeInElements)
{
elementSize = elementSizeInBytes;
PAssert(elementSize != 0, PInvalidParameter);
allocatedDynamically = dynamicAllocation;
if (GetSize() == 0)
theArray = NULL;
else if (dynamicAllocation) {
PINDEX sizebytes = elementSize*GetSize();
theArray = (char *)malloc(sizebytes);
PAssert(theArray != NULL, POutOfMemory);
memcpy(theArray, PAssertNULL(buffer), sizebytes);
}
else
theArray = (char *)buffer;
}
void PAbstractArray::DestroyContents()
{
if (theArray != NULL) {
if (allocatedDynamically)
free(theArray);
theArray = NULL;
}
}
void PAbstractArray::CopyContents(const PAbstractArray & array)
{
elementSize = array.elementSize;
theArray = array.theArray;
allocatedDynamically = array.allocatedDynamically;
}
void PAbstractArray::CloneContents(const PAbstractArray * array)
{
elementSize = array->elementSize;
PINDEX sizebytes = elementSize*GetSize();
char * newArray = (char *)malloc(sizebytes);
if (newArray == NULL)
reference->size = 0;
else
memcpy(newArray, array->theArray, sizebytes);
theArray = newArray;
allocatedDynamically = PTrue;
}
void PAbstractArray::PrintOn(ostream & strm) const
{
char separator = strm.fill();
int width = strm.width();
for (PINDEX i = 0; i < GetSize(); i++) {
if (i > 0 && separator != '\0')
strm << separator;
strm.width(width);
PrintElementOn(strm, i);
}
if (separator == '\n')
strm << '\n';
}
void PAbstractArray::ReadFrom(istream & strm)
{
PINDEX i = 0;
while (strm.good()) {
ReadElementFrom(strm, i);
if (!strm.fail())
i++;
}
SetSize(i);
}
PObject::Comparison PAbstractArray::Compare(const PObject & obj) const
{
PAssert(PIsDescendant(&obj, PAbstractArray), PInvalidCast);
const PAbstractArray & other = (const PAbstractArray &)obj;
char * otherArray = other.theArray;
if (theArray == otherArray)
return EqualTo;
if (elementSize < other.elementSize)
return LessThan;
if (elementSize > other.elementSize)
return GreaterThan;
PINDEX thisSize = GetSize();
PINDEX otherSize = other.GetSize();
if (thisSize < otherSize)
return LessThan;
if (thisSize > otherSize)
return GreaterThan;
if (thisSize == 0)
return EqualTo;
int retval = memcmp(theArray, otherArray, elementSize*thisSize);
if (retval < 0)
return LessThan;
if (retval > 0)
return GreaterThan;
return EqualTo;
}
PBoolean PAbstractArray::SetSize(PINDEX newSize)
{
return InternalSetSize(newSize, PFalse);
}
PBoolean PAbstractArray::InternalSetSize(PINDEX newSize, PBoolean force)
{
if (newSize < 0)
newSize = 0;
PINDEX newsizebytes = elementSize*newSize;
PINDEX oldsizebytes = elementSize*GetSize();
if (!force && (newsizebytes == oldsizebytes))
return PTrue;
char * newArray;
if (!IsUnique()) {
if (newsizebytes == 0)
newArray = NULL;
else {
if ((newArray = (char *)malloc(newsizebytes)) == NULL)
return PFalse;
if (theArray != NULL)
memcpy(newArray, theArray, PMIN(oldsizebytes, newsizebytes));
}
--reference->count;
reference = new PContainerReference(newSize);
} else {
if (theArray != NULL) {
if (newsizebytes == 0) {
if (allocatedDynamically)
free(theArray);
newArray = NULL;
}
else if (allocatedDynamically) {
if ((newArray = (char *)realloc(theArray, newsizebytes)) == NULL)
return PFalse;
}
else {
if ((newArray = (char *)malloc(newsizebytes)) == NULL)
return PFalse;
memcpy(newArray, theArray, PMIN(newsizebytes, oldsizebytes));
allocatedDynamically = PTrue;
}
}
else if (newsizebytes != 0) {
if ((newArray = (char *)malloc(newsizebytes)) == NULL)
return PFalse;
}
else
newArray = NULL;
reference->size = newSize;
}
if (newsizebytes > oldsizebytes)
memset(newArray+oldsizebytes, 0, newsizebytes-oldsizebytes);
theArray = newArray;
return PTrue;
}
void PAbstractArray::Attach(const void *buffer, PINDEX bufferSize)
{
if (allocatedDynamically && theArray != NULL)
free(theArray);
theArray = (char *)buffer;
reference->size = bufferSize;
allocatedDynamically = PFalse;
}
void * PAbstractArray::GetPointer(PINDEX minSize)
{
PAssert(SetMinSize(minSize), POutOfMemory);
return theArray;
}
PBoolean PAbstractArray::Concatenate(const PAbstractArray & array)
{
if (!allocatedDynamically || array.elementSize != elementSize)
return PFalse;
PINDEX oldLen = GetSize();
PINDEX addLen = array.GetSize();
if (!SetSize(oldLen + addLen))
return PFalse;
memcpy(theArray+oldLen*elementSize, array.theArray, addLen*elementSize);
return PTrue;
}
void PAbstractArray::PrintElementOn(ostream & /*stream*/, PINDEX /*index*/) const
{
}
void PAbstractArray::ReadElementFrom(istream & /*stream*/, PINDEX /*index*/)
{
}
///////////////////////////////////////////////////////////////////////////////
void PCharArray::PrintOn(ostream & strm) const
{
PINDEX width = strm.width();
if (width > GetSize())
width -= GetSize();
else
width = 0;
PBoolean left = (strm.flags()&ios::adjustfield) == ios::left;
if (left)
strm.write(theArray, GetSize());
while (width-- > 0)
strm << (char)strm.fill();
if (!left)
strm.write(theArray, GetSize());
}
void PCharArray::ReadFrom(istream &strm)
{
PINDEX size = 0;
SetSize(size+100);
while (strm.good()) {
strm >> theArray[size++];
if (size >= GetSize())
SetSize(size+100);
}
SetSize(size);
}
void PBYTEArray::PrintOn(ostream & strm) const
{
PINDEX line_width = strm.width();
if (line_width == 0)
line_width = 16;
strm.width(0);
PINDEX indent = strm.precision();
PINDEX val_width = ((strm.flags()&ios::basefield) == ios::hex) ? 2 : 3;
PINDEX i = 0;
while (i < GetSize()) {
if (i > 0)
strm << '\n';
PINDEX j;
for (j = 0; j < indent; j++)
strm << ' ';
for (j = 0; j < line_width; j++) {
if (j == line_width/2)
strm << ' ';
if (i+j < GetSize())
strm << setw(val_width) << (theArray[i+j]&0xff);
else {
PINDEX k;
for (k = 0; k < val_width; k++)
strm << ' ';
}
strm << ' ';
}
if ((strm.flags()&ios::floatfield) != ios::fixed) {
strm << " ";
for (j = 0; j < line_width; j++) {
if (i+j < GetSize()) {
unsigned val = theArray[i+j]&0xff;
if (isprint(val))
strm << (char)val;
else
strm << '.';
}
}
}
i += line_width;
}
}
void PBYTEArray::ReadFrom(istream &strm)
{
PINDEX size = 0;
SetSize(size+100);
while (strm.good()) {
unsigned v;
strm >> v;
theArray[size] = (BYTE)v;
if (!strm.fail()) {
size++;
if (size >= GetSize())
SetSize(size+100);
}
}
SetSize(size);
}
///////////////////////////////////////////////////////////////////////////////
PBitArray::PBitArray(PINDEX initialSize)
: PBYTEArray((initialSize+7)>>3)
{
}
PBitArray::PBitArray(const void * buffer,
PINDEX length,
PBoolean dynamic)
: PBYTEArray((const BYTE *)buffer, (length+7)>>3, dynamic)
{
}
PObject * PBitArray::Clone() const
{
return new PBitArray(*this);
}
PINDEX PBitArray::GetSize() const
{
return PBYTEArray::GetSize()<<3;
}
PBoolean PBitArray::SetSize(PINDEX newSize)
{
return PBYTEArray::SetSize((newSize+7)>>3);
}
PBoolean PBitArray::SetAt(PINDEX index, PBoolean val)
{
if (!SetMinSize(index+1))
return PFalse;
if (val)
theArray[index>>3] |= (1 << (index&7));
else
theArray[index>>3] &= ~(1 << (index&7));
return PTrue;
}
PBoolean PBitArray::GetAt(PINDEX index) const
{
PASSERTINDEX(index);
if (index >= GetSize())
return PFalse;
return (theArray[index>>3]&(1 << (index&7))) != 0;
}
void PBitArray::Attach(const void * buffer, PINDEX bufferSize)
{
PBYTEArray::Attach((const BYTE *)buffer, (bufferSize+7)>>3);
}
BYTE * PBitArray::GetPointer(PINDEX minSize)
{
return PBYTEArray::GetPointer((minSize+7)>>3);
}
PBoolean PBitArray::Concatenate(const PBitArray & array)
{
return PAbstractArray::Concatenate(array);
}
///////////////////////////////////////////////////////////////////////////////
PString::PString(const char * cstr)
: PCharArray(cstr != NULL ? strlen(cstr)+1 : 1)
{
if (cstr != NULL)
memcpy(theArray, cstr, GetSize());
}
PString::PString(const wchar_t * ustr)
{
if (ustr == NULL)
SetSize(1);
else {
PINDEX len = 0;
while (ustr[len] != 0)
len++;
InternalFromUCS2(ustr, len);
}
}
PString::PString(const char * cstr, PINDEX len)
: PCharArray(len+1)
{
if (len > 0)
memcpy(theArray, PAssertNULL(cstr), len);
}
PString::PString(const wchar_t * ustr, PINDEX len)
: PCharArray(len+1)
{
InternalFromUCS2(ustr, len);
}
PString::PString(const PWCharArray & ustr)
{
PINDEX size = ustr.GetSize();
if (size > 0 && ustr[size-1] == 0) // Stip off trailing NULL if present
size--;
InternalFromUCS2(ustr, size);
}
static int TranslateHex(char x)
{
if (x >= 'a')
return x - 'a' + 10;
if (x >= 'A')
return x - 'A' + '\x0a';
return x - '0';
}
static const unsigned char PStringEscapeCode[] = { 'a', 'b', 'f', 'n', 'r', 't', 'v' };
static const unsigned char PStringEscapeValue[] = { '\a', '\b', '\f', '\n', '\r', '\t', '\v' };
static void TranslateEscapes(const char * src, char * dst)
{
if (*src == '"')
src++;
while (*src != '\0') {
int c = *src++ & 0xff;
if (c == '"' && *src == '\0')
c = '\0'; // Trailing '"' is ignored
else if (c == '\\') {
c = *src++ & 0xff;
for (PINDEX i = 0; i < PARRAYSIZE(PStringEscapeCode); i++) {
if (c == PStringEscapeCode[i])
c = PStringEscapeValue[i];
}
if (c == 'x' && isxdigit(*src & 0xff)) {
c = TranslateHex(*src++);
if (isxdigit(*src & 0xff))
c = (c << 4) + TranslateHex(*src++);
}
else if (c >= '0' && c <= '7') {
int count = c <= '3' ? 3 : 2;
src--;
c = 0;
do {
c = (c << 3) + *src++ - '0';
} while (--count > 0 && *src >= '0' && *src <= '7');
}
}
*dst++ = (char)c;
}
}
PString::PString(ConversionType type, const char * str, ...)
{
switch (type) {
case Pascal :
if (*str != '\0') {
PINDEX len = *str & 0xff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -