mirror of
https://github.com/stefanocasazza/ULib.git
synced 2025-09-28 19:05:55 +08:00
1150 lines
24 KiB
C++
1150 lines
24 KiB
C++
// ============================================================================
|
|
//
|
|
// = LIBRARY
|
|
// ULib - c++ library
|
|
//
|
|
// = FILENAME
|
|
// vector.cpp
|
|
//
|
|
// = AUTHOR
|
|
// Stefano Casazza
|
|
//
|
|
// ============================================================================
|
|
|
|
#include <ulib/utility/string_ext.h>
|
|
|
|
#if defined(ENABLE_MEMPOOL) && defined(U_LINUX)
|
|
# include <ulib/file.h>
|
|
#endif
|
|
|
|
bool UVector<void*>::istream_loading;
|
|
|
|
void UVector<void*>::push(const void* elem) // add to end
|
|
{
|
|
U_TRACE(0, "UVector<void*>::push(%p)", elem)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u _capacity = %u", _length, _capacity)
|
|
|
|
U_INTERNAL_ASSERT_MAJOR(_capacity, 0)
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
if (_length == _capacity)
|
|
{
|
|
const void** old_vec = vec;
|
|
uint32_t old_capacity = _capacity;
|
|
|
|
_capacity <<= 1; // x 2...
|
|
|
|
vec = (const void**) UMemoryPool::_malloc(&_capacity, sizeof(void*));
|
|
|
|
if (_length) U_MEMCPY(vec, old_vec, _length * sizeof(void*));
|
|
|
|
UMemoryPool::_free(old_vec, old_capacity, sizeof(void*));
|
|
}
|
|
|
|
vec[_length++] = elem;
|
|
}
|
|
|
|
void UVector<void*>::move(UVector<void*>& source) // add to end and reset source
|
|
{
|
|
U_TRACE(0, "UVector<void*>::move(%p)", &source)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_ASSERT_MAJOR(source._length, 0)
|
|
|
|
if ((_length + source._length) >= _capacity)
|
|
{
|
|
const void** old_vec = vec;
|
|
uint32_t old_capacity = _capacity;
|
|
|
|
_capacity <<= 1; // x 2...
|
|
|
|
vec = (const void**) UMemoryPool::_malloc(&_capacity, sizeof(void*));
|
|
|
|
if (_length) U_MEMCPY(vec, old_vec, _length * sizeof(void*));
|
|
|
|
UMemoryPool::_free(old_vec, old_capacity, sizeof(void*));
|
|
}
|
|
|
|
U_MEMCPY(vec+_length, source.vec, source._length * sizeof(void*));
|
|
|
|
_length += source._length;
|
|
source._length = 0;
|
|
}
|
|
|
|
// LIST OPERATIONS
|
|
|
|
void UVector<void*>::insert(uint32_t pos, const void* elem) // add elem before pos
|
|
{
|
|
U_TRACE(0, "UVector<void*>::insert(%u,%p)", pos, elem)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_ASSERT(pos <= _length)
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
if (_length == _capacity)
|
|
{
|
|
const void** old_vec = vec;
|
|
uint32_t old_capacity = _capacity;
|
|
|
|
_capacity <<= 1; // x 2...
|
|
|
|
vec = (const void**) UMemoryPool::_malloc(&_capacity, sizeof(void*));
|
|
|
|
U_MEMCPY(vec, old_vec, pos * sizeof(void*));
|
|
U_MEMCPY(vec + pos + 1, old_vec + pos, (_length - pos) * sizeof(void*));
|
|
|
|
UMemoryPool::_free(old_vec, old_capacity, sizeof(void*));
|
|
}
|
|
else
|
|
{
|
|
# ifdef U_APEX_ENABLE
|
|
(void) U_SYSCALL(apex_memmove, "%p,%p,%u", vec + pos + 1, vec + pos, (_length - pos) * sizeof(void*));
|
|
# else
|
|
(void) U_SYSCALL( memmove, "%p,%p,%u", vec + pos + 1, vec + pos, (_length - pos) * sizeof(void*));
|
|
# endif
|
|
}
|
|
|
|
vec[pos] = elem;
|
|
|
|
++_length;
|
|
}
|
|
|
|
void UVector<void*>::insert(uint32_t pos, uint32_t n, const void* elem) // add n copy of elem before pos
|
|
{
|
|
U_TRACE(0, "UVector<void*>::insert(%u,%u,%p)", pos, n, elem)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_ASSERT_MAJOR(n,0)
|
|
U_INTERNAL_ASSERT(pos <= _length)
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
uint32_t new_length = _length + n;
|
|
|
|
if (new_length > _capacity)
|
|
{
|
|
const void** old_vec = vec;
|
|
uint32_t old_capacity = _capacity;
|
|
|
|
_capacity = new_length << 1; // x 2...
|
|
|
|
vec = (const void**) UMemoryPool::_malloc(&_capacity, sizeof(void*));
|
|
|
|
U_MEMCPY(vec, old_vec, pos * sizeof(void*));
|
|
U_MEMCPY(vec + pos + n, old_vec + pos, (_length - pos) * sizeof(void*));
|
|
|
|
UMemoryPool::_free(old_vec, old_capacity, sizeof(void*));
|
|
}
|
|
else
|
|
{
|
|
# ifdef U_APEX_ENABLE
|
|
(void) U_SYSCALL(apex_memmove, "%p,%p,%u", vec + pos + n, vec + pos, (_length - pos) * sizeof(void*));
|
|
# else
|
|
(void) U_SYSCALL( memmove, "%p,%p,%u", vec + pos + n, vec + pos, (_length - pos) * sizeof(void*));
|
|
# endif
|
|
}
|
|
|
|
for (uint32_t i = 0; i < n; ++i) vec[pos++] = elem;
|
|
|
|
_length = new_length;
|
|
}
|
|
|
|
void UVector<void*>::reserve(uint32_t n)
|
|
{
|
|
U_TRACE(0, "UVector<void*>::reserve(%u)", n)
|
|
|
|
if (n != _capacity)
|
|
{
|
|
if (n == 0) n = 64; // NB: the check n == 0 is specific for class UTree...
|
|
|
|
const void** old_vec = vec;
|
|
uint32_t old_capacity = _capacity;
|
|
|
|
allocate(n);
|
|
|
|
if (_length) U_MEMCPY(vec, old_vec, _length * sizeof(void*));
|
|
|
|
if (old_capacity) UMemoryPool::_free(old_vec, old_capacity, sizeof(void*));
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
bool UVector<void*>::check_memory() // check all element
|
|
{
|
|
U_TRACE_NO_PARAM(0+256, "UVector<void*>::check_memory()")
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
const void* pelem;
|
|
|
|
for (uint32_t i = 0; i < _length; ++i)
|
|
{
|
|
pelem = at(i);
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(((const UMemoryError*)pelem)->_this, (void*)U_CHECK_MEMORY_SENTINEL)
|
|
}
|
|
|
|
U_RETURN(true);
|
|
}
|
|
#endif
|
|
|
|
UVector<UString>::UVector(const UString& str, char delim) : UVector<UStringRep*>(64)
|
|
{
|
|
U_TRACE_REGISTER_OBJECT(0, UVector<UString>, "%V,%C", str.rep, delim)
|
|
|
|
uint32_t n = str.size() / 128;
|
|
|
|
if (n > 64)
|
|
{
|
|
# if defined(ENABLE_MEMPOOL) && defined(U_LINUX)
|
|
UMemoryPool::allocateMemoryBlocks(U_SIZE_TO_STACK_INDEX(sizeof(UStringRep)), UFile::getSizeAligned(n * sizeof(UStringRep)) / sizeof(UStringRep));
|
|
# endif
|
|
|
|
UMemoryPool::_free(vec, _capacity, sizeof(void*));
|
|
|
|
allocate(n);
|
|
}
|
|
|
|
(void) split(str, delim);
|
|
|
|
if (_length) reserve(_length);
|
|
}
|
|
|
|
UVector<UString>::UVector(const UString& x, const char* delim) : UVector<UStringRep*>(64)
|
|
{
|
|
U_TRACE_REGISTER_OBJECT(0, UVector<UString>, "%V,%S", x.rep, delim)
|
|
|
|
const char* s = x.data();
|
|
char c = *s;
|
|
|
|
if (c == '[' ||
|
|
c == '(')
|
|
{
|
|
istream_loading = true; // NB: we need this flag for distinguish this operation in UString::setFromData()...
|
|
|
|
(void) loadFromData(s, x.size());
|
|
|
|
istream_loading = false;
|
|
}
|
|
else
|
|
{
|
|
(void) split(x, delim); // NB: use substr(), so dependency from x...
|
|
}
|
|
|
|
if (_length) reserve(_length);
|
|
}
|
|
|
|
__pure uint32_t UVector<UString>::find(const char* s, uint32_t n)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::find(%.*S,%u)", n, s, n)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
UStringRep* r;
|
|
|
|
for (uint32_t i = 0; i < _length; ++i)
|
|
{
|
|
r = UVector<UStringRep*>::at(i);
|
|
|
|
if (r->equal(s, n)) U_RETURN(i);
|
|
}
|
|
|
|
U_RETURN(U_NOT_FOUND);
|
|
}
|
|
|
|
__pure uint32_t UVector<UString>::findRange(const char* s, uint32_t n, uint32_t start, uint32_t _end)
|
|
{
|
|
U_TRACE(0+256, "UVector<UString>::findRange(%.*S,%u,%u,%u)", n, s, n, start, _end)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_ASSERT(_end <= _length)
|
|
U_INTERNAL_ASSERT_MINOR(start, _end)
|
|
|
|
UStringRep* r;
|
|
|
|
for (uint32_t i = start; i < _end; ++i)
|
|
{
|
|
r = UVector<UStringRep*>::at(i);
|
|
|
|
if (r->equal(s, n)) U_RETURN(i);
|
|
}
|
|
|
|
U_RETURN(U_NOT_FOUND);
|
|
}
|
|
|
|
__pure uint32_t UVector<UString>::find(const UString& str, bool ignore_case)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::find(%V,%b)", str.rep, ignore_case)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
uint32_t i;
|
|
UStringRep* r;
|
|
|
|
if (ignore_case)
|
|
{
|
|
for (i = 0; i < _length; ++i)
|
|
{
|
|
r = UVector<UStringRep*>::at(i);
|
|
|
|
if (str.equalnocase(r)) U_RETURN(i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < _length; ++i)
|
|
{
|
|
r = UVector<UStringRep*>::at(i);
|
|
|
|
if (str.equal(r)) U_RETURN(i);
|
|
}
|
|
}
|
|
|
|
U_RETURN(U_NOT_FOUND);
|
|
}
|
|
|
|
// Check equality with string at pos
|
|
|
|
__pure bool UVector<UString>::isEqual(uint32_t pos, const UString& str, bool ignore_case)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::isEqual(%u,%V,%b)", pos, str.rep, ignore_case)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
if (_length)
|
|
{
|
|
UStringRep* rep = UVector<UStringRep*>::at(pos);
|
|
|
|
if (UStringRep::equal_lookup(rep, U_STRING_TO_PARAM(*rep), str.rep, str.size(), ignore_case)) U_RETURN(true);
|
|
}
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
__pure uint32_t UVector<UString>::findSorted(const UString& str, bool ignore_case, bool bcouple)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::findSorted(%V,%b,%b)", str.rep, ignore_case, bcouple)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT_RANGE(1,_length,_capacity)
|
|
|
|
UStringRep* key;
|
|
UStringRep* target = str.rep;
|
|
int old_probe = -1, low = -1, high = _length;
|
|
uint32_t mask = (bcouple ? 0xFFFFFFFE : 0xFFFFFFFF);
|
|
|
|
while ((high - low) > 1)
|
|
{
|
|
int probe = (((low + high) & 0xFFFFFFFF) >> 1) & mask;
|
|
|
|
U_INTERNAL_DUMP("low = %d high = %d probe = %d old_probe = %d", low, high, probe, old_probe)
|
|
|
|
if (probe == old_probe) U_RETURN(U_NOT_FOUND);
|
|
|
|
key = UVector<UStringRep*>::at(probe);
|
|
int cmp = (ignore_case ? key->comparenocase(target)
|
|
: key->compare( target));
|
|
|
|
U_INTERNAL_DUMP("cmp = %d", cmp)
|
|
|
|
if (cmp > 0) high = probe;
|
|
else if (cmp == 0) U_RETURN(probe);
|
|
else low = probe;
|
|
|
|
old_probe = probe;
|
|
}
|
|
|
|
if (low == -1 || (key = UVector<UStringRep*>::at(low),
|
|
(ignore_case ? key->comparenocase(target)
|
|
: key->compare(target))) != 0)
|
|
{
|
|
U_RETURN(U_NOT_FOUND);
|
|
}
|
|
|
|
U_RETURN(low);
|
|
}
|
|
|
|
uint32_t UVector<UString>::contains(const UString& str, bool ignore_case)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::contains(%V,%b)", str.rep, ignore_case)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
UString elem;
|
|
uint32_t i, n;
|
|
|
|
if (ignore_case)
|
|
{
|
|
for (i = 0; i < _length; ++i)
|
|
{
|
|
elem = at(i);
|
|
n = elem.findnocase(str);
|
|
|
|
if (n != U_NOT_FOUND) U_RETURN(i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < _length; ++i)
|
|
{
|
|
elem = at(i);
|
|
n = elem.find(str);
|
|
|
|
if (n != U_NOT_FOUND) U_RETURN(i);
|
|
}
|
|
}
|
|
|
|
U_RETURN(U_NOT_FOUND);
|
|
}
|
|
|
|
bool UVector<UString>::contains(UVector<UString>& _vec, bool ignore_case)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::contains(%p,%b)", &_vec, ignore_case)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
UString elem;
|
|
|
|
for (uint32_t i = 0, n = _vec.size(); i < n; ++i)
|
|
{
|
|
elem = _vec.at(i);
|
|
|
|
if (contains(elem, ignore_case) != U_NOT_FOUND) U_RETURN(true);
|
|
}
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
// Check equality with an existing vector object
|
|
|
|
bool UVector<UString>::_isEqual(UVector<UString>& _vec, bool ignore_case)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::_isEqual(%p,%b)", &_vec, ignore_case)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
if (_length)
|
|
{
|
|
UString elem;
|
|
|
|
for (uint32_t i = 0; i < _length; ++i)
|
|
{
|
|
elem = at(i);
|
|
|
|
if (_vec.find(elem, ignore_case) == U_NOT_FOUND) U_RETURN(false);
|
|
}
|
|
|
|
U_RETURN(true);
|
|
}
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
void UVector<UString>::sort(bool ignore_case)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::sort(%b)", ignore_case)
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT_RANGE(2,_length,_capacity)
|
|
|
|
if (ignore_case) UVector<void*>::sort(UVector<UString>::qscomp);
|
|
else mksort((UStringRep**)vec, _length, 0);
|
|
}
|
|
|
|
UString UVector<UString>::operator[](uint32_t pos) const
|
|
{
|
|
U_TRACE(0, "UVector<UString>::operator[](%u)", pos)
|
|
|
|
#ifdef DEBUG
|
|
if (pos >= _length)
|
|
{
|
|
U_ERROR("Array access out of bounds - UVector<UString>::at(pos:%u >= _length:%u) _capacity = %u elem(0) = %V elem(%u) = %V",
|
|
pos, _length, _capacity, vec[0], _length-1, (_length ? vec[_length-1] : UStringRep::string_rep_null));
|
|
}
|
|
#endif
|
|
|
|
return at(pos);
|
|
}
|
|
|
|
UString UVector<UString>::join(char c)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::join(%C)", c)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
if (_length == 0) return UString::getStringNull();
|
|
|
|
uint32_t i = 0,
|
|
len = 0;
|
|
|
|
for (; i < _length; ++i) len += ((UStringRep*)vec[i])->size();
|
|
|
|
len += (_length - 1);
|
|
|
|
UString str(len < U_CAPACITY ? U_CAPACITY : len);
|
|
|
|
str.size_adjust(len);
|
|
|
|
i = 0;
|
|
char* ptr = str.data();
|
|
|
|
while (true)
|
|
{
|
|
UStringRep* rep = (UStringRep*)vec[i];
|
|
|
|
uint32_t sz = rep->size();
|
|
|
|
if (sz) U_MEMCPY(ptr, rep->data(), sz);
|
|
|
|
if (++i >= _length) break;
|
|
|
|
ptr += sz;
|
|
|
|
*ptr++ = c;
|
|
}
|
|
|
|
(void) str.shrink();
|
|
|
|
U_RETURN_STRING(str);
|
|
}
|
|
|
|
UString UVector<UString>::join(const char* t, uint32_t tlen)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::join(%.*S,%u)", tlen, t, tlen)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
if (_length == 0) return UString::getStringNull();
|
|
|
|
uint32_t i = 0,
|
|
len = 0;
|
|
|
|
for (; i < _length; ++i) len += ((UStringRep*)vec[i])->size();
|
|
|
|
len += (_length - 1) * tlen;
|
|
|
|
UString str(len < U_CAPACITY ? U_CAPACITY : len);
|
|
|
|
str.size_adjust(len);
|
|
|
|
i = 0;
|
|
char* ptr = str.data();
|
|
|
|
while (true)
|
|
{
|
|
UStringRep* rep = (UStringRep*)vec[i];
|
|
|
|
uint32_t sz = rep->size();
|
|
|
|
if (sz) U_MEMCPY(ptr, rep->data(), sz);
|
|
|
|
if (++i >= _length) break;
|
|
|
|
ptr += sz;
|
|
|
|
if (tlen)
|
|
{
|
|
U_MEMCPY(ptr, t, tlen);
|
|
|
|
ptr += tlen;
|
|
}
|
|
}
|
|
|
|
(void) str.shrink();
|
|
|
|
U_RETURN_STRING(str);
|
|
}
|
|
|
|
uint32_t UVector<UString>::split(const UString& str, const char* delim)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::split(%V,%S)", str.rep, delim)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
const char* p;
|
|
UStringRep* r;
|
|
|
|
uint32_t len, n = _length;
|
|
const char* s = str.data();
|
|
const char* _end = s + str.size();
|
|
|
|
if (str.isQuoted())
|
|
{
|
|
++s;
|
|
--_end;
|
|
}
|
|
|
|
while (s < _end)
|
|
{
|
|
s = u_delimit_token(s, &p, _end, delim, '#');
|
|
|
|
U_INTERNAL_DUMP("s = %p end = %p", s, _end)
|
|
|
|
if (s <= _end)
|
|
{
|
|
len = s++ - p;
|
|
r = str.rep->substr(p, len);
|
|
|
|
U_INTERNAL_DUMP("r = %V", r)
|
|
|
|
UVector<void*>::push(r);
|
|
}
|
|
}
|
|
|
|
U_RETURN(_length - n);
|
|
}
|
|
|
|
uint32_t UVector<UString>::split(const char* s, uint32_t len, const char* delim)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::split(%.*S,%u,%S)", len, s, len, delim)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
const char* p;
|
|
UStringRep* r;
|
|
|
|
uint32_t n = _length;
|
|
const char* _end = s + len;
|
|
|
|
if (*s == '"' &&
|
|
*(_end-1) == '"')
|
|
{
|
|
++s;
|
|
--_end;
|
|
}
|
|
|
|
while (s < _end)
|
|
{
|
|
s = u_delimit_token(s, &p, _end, delim, '#');
|
|
|
|
U_INTERNAL_DUMP("s = %p end = %p", s, _end)
|
|
|
|
if (s <= _end)
|
|
{
|
|
len = s++ - p;
|
|
r = UStringRep::create(len, len, p);
|
|
|
|
U_INTERNAL_DUMP("r = %V", r)
|
|
|
|
UVector<void*>::push(r);
|
|
}
|
|
}
|
|
|
|
U_RETURN(_length - n);
|
|
}
|
|
|
|
uint32_t UVector<UString>::split(const UString& str, char delim)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::split(%V,%C)", str.rep, delim)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
const char* p;
|
|
UStringRep* r;
|
|
|
|
uint32_t n = _length;
|
|
const char* s = str.data();
|
|
const char* _end = s + str.size();
|
|
|
|
if (delim != ';' && // usp translator (printfor)
|
|
str.isQuoted())
|
|
{
|
|
++s;
|
|
--_end;
|
|
}
|
|
|
|
while (s < _end)
|
|
{
|
|
// skip char delimiter
|
|
|
|
if (*s == delim)
|
|
{
|
|
++s;
|
|
|
|
continue;
|
|
}
|
|
|
|
// delimit token with char delimiter
|
|
|
|
p = s;
|
|
s = (const char*) memchr(s, delim, _end - s);
|
|
|
|
if (s == 0) s = _end;
|
|
|
|
r = str.rep->substr(p, s - p);
|
|
|
|
UVector<void*>::push(r);
|
|
|
|
++s;
|
|
}
|
|
|
|
U_RETURN(_length - n);
|
|
}
|
|
|
|
uint32_t UVector<UString>::split(const char* s, uint32_t len, char delim)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::split(%.*S,%u,%C)", len, s, len, delim)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
const char* p;
|
|
UStringRep* r;
|
|
|
|
uint32_t n = _length;
|
|
const char* _end = s + len;
|
|
|
|
if (*s == '"' &&
|
|
*(_end-1) == '"')
|
|
{
|
|
++s;
|
|
--_end;
|
|
}
|
|
|
|
while (s < _end)
|
|
{
|
|
// skip char delimiter
|
|
|
|
if (*s == delim)
|
|
{
|
|
++s;
|
|
|
|
continue;
|
|
}
|
|
|
|
// delimit token with char delimiter
|
|
|
|
p = s;
|
|
s = (const char*) memchr(s, delim, _end - s);
|
|
|
|
if (s == 0) s = _end;
|
|
|
|
len = s++ - p;
|
|
r = UStringRep::create(len, len, p);
|
|
|
|
UVector<void*>::push(r);
|
|
}
|
|
|
|
U_RETURN(_length - n);
|
|
}
|
|
|
|
uint32_t UVector<UString>::intersection(UVector<UString>& set1, UVector<UString>& set2)
|
|
{
|
|
U_TRACE(0, "UVector<UString>::intersection(%p,%p)", &set1, &set2)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
U_INTERNAL_DUMP("_length = %u", _length)
|
|
|
|
U_INTERNAL_ASSERT(_length <= _capacity)
|
|
|
|
if (set1.empty() ||
|
|
set2.empty())
|
|
{
|
|
U_RETURN(0);
|
|
}
|
|
|
|
UString elem;
|
|
uint32_t i, n = _length;
|
|
|
|
for (i = 0; i < set1._length; ++i)
|
|
{
|
|
elem = set1.at(i);
|
|
|
|
if (set2.find(elem) != U_NOT_FOUND) push(elem);
|
|
}
|
|
|
|
U_RETURN(_length - n);
|
|
}
|
|
|
|
__pure bool UVector<UString>::operator==(const UVector<UString>& v) const
|
|
{
|
|
U_TRACE(0, "UVector<UString>::operator==(%p)", &v)
|
|
|
|
U_CHECK_MEMORY
|
|
|
|
if (_length == v._length)
|
|
{
|
|
for (uint32_t i = 0; i < _length; ++i)
|
|
{
|
|
UStringRep* r1 = UVector<UStringRep*>::at(i);
|
|
UStringRep* r2 = v.UVector<UStringRep*>::at(i);
|
|
|
|
if (r1->equal(r2) == false) U_RETURN(false);
|
|
}
|
|
|
|
U_RETURN(true);
|
|
}
|
|
|
|
U_RETURN(false);
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// THREE-WAY RADIX QUICKSORT
|
|
// ------------------------------------------------------
|
|
// Multikey Quicksort - Dr. Dobb's Journal, November 1998
|
|
//
|
|
// by Jon Bentley and Robert Sedgewick
|
|
// ------------------------------------------------------
|
|
|
|
static inline int chfunc(UStringRep* a[], int i, int depth)
|
|
{
|
|
U_TRACE(0, "chfunc(%p,%d,%d)", a, i, depth)
|
|
|
|
UStringRep* t = a[i];
|
|
|
|
U_INTERNAL_DUMP("t = %V", t)
|
|
|
|
int result = (t->data())[depth];
|
|
|
|
U_RETURN(result);
|
|
}
|
|
|
|
static inline void vecswap2(UStringRep** a, UStringRep** b, int n)
|
|
{
|
|
U_TRACE(0, "vecswap2(%p,%p,%d)", a, b, n)
|
|
|
|
UStringRep* t;
|
|
|
|
while (n-- > 0)
|
|
{
|
|
t = *a;
|
|
*a++ = *b;
|
|
*b++ = t;
|
|
}
|
|
}
|
|
|
|
#define ch(a) chfunc(a, 0, depth)
|
|
|
|
#define med3(a, b, c) med3func(a, b, c, depth)
|
|
|
|
#define swap2(a,b) { t = *(a); *(a) = *(b); *(b) = t; }
|
|
|
|
static inline UStringRep** med3func(UStringRep** a, UStringRep** b, UStringRep** c, int depth)
|
|
{
|
|
U_TRACE(0, "med3func(%p,%p,%p,%d)", a, b, c, depth)
|
|
|
|
int va, vb, vc;
|
|
UStringRep** result;
|
|
|
|
if ((va = ch(a)) == (vb = ch(b))) U_RETURN_POINTER(a, UStringRep*);
|
|
if ((vc = ch(c)) == va || vc == vb) U_RETURN_POINTER(c, UStringRep*);
|
|
|
|
result = (va < vb ? (vb < vc ? b : (va < vc ? c : a))
|
|
: (vb > vc ? b : (va < vc ? a : c)));
|
|
|
|
U_RETURN_POINTER(result, UStringRep*);
|
|
}
|
|
|
|
static inline void inssort(UStringRep** a, int n, int depth)
|
|
{
|
|
U_TRACE(0, "inssort(%p,%d,%d)", a, n, depth)
|
|
|
|
UStringRep** pi, **pj, *t;
|
|
|
|
for (pi = a + 1; --n > 0; ++pi)
|
|
{
|
|
for (pj = pi; pj > a; --pj)
|
|
{
|
|
// Inline strcmp: break if *(pj-1) <= *pj
|
|
|
|
if ((*(pj-1))->compare(*pj, depth) <= 0) break;
|
|
|
|
swap2(pj, pj-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UVector<UString>::mksort(UStringRep** a, int n, int depth)
|
|
{
|
|
U_TRACE(0+256, "UVector<UString>::mksort(%p,%d,%d)", a, n, depth)
|
|
|
|
int r, partval;
|
|
UStringRep** pa, **pb, **pc, **pd, **pl, **pm, **pn, *t;
|
|
|
|
if (n <= 10) // insertion sort
|
|
{
|
|
inssort(a, n, depth);
|
|
|
|
return;
|
|
}
|
|
|
|
pl = a;
|
|
pm = a + (n / 2);
|
|
pn = a + (n - 1);
|
|
|
|
if (n > 50)
|
|
{
|
|
// On big arrays, pseudomedian of 9
|
|
|
|
int d = (n / 8);
|
|
|
|
pl = med3(pl, pl + d, pl + 2 * d);
|
|
pm = med3(pm - d, pm, pm + d);
|
|
pn = med3(pn - 2 * d, pn - d, pn);
|
|
}
|
|
|
|
pm = med3(pl, pm, pn);
|
|
|
|
swap2(a, pm);
|
|
|
|
partval = ch(a);
|
|
|
|
pa = pb = a + 1;
|
|
pc = pd = a + n - 1;
|
|
|
|
for (;;)
|
|
{
|
|
while (pb <= pc &&
|
|
(r = ch(pb) - partval) <= 0)
|
|
{
|
|
if (r == 0)
|
|
{
|
|
swap2(pa, pb);
|
|
|
|
++pa;
|
|
}
|
|
|
|
++pb;
|
|
}
|
|
|
|
while (pb <= pc &&
|
|
(r = ch(pc) - partval) >= 0)
|
|
{
|
|
if (r == 0)
|
|
{
|
|
swap2(pc, pd);
|
|
|
|
--pd;
|
|
}
|
|
|
|
--pc;
|
|
}
|
|
|
|
if (pb > pc) break;
|
|
|
|
swap2(pb, pc);
|
|
|
|
++pb;
|
|
--pc;
|
|
}
|
|
|
|
pn = a + n;
|
|
r = U_min(pa - a, pb - pa); vecswap2(a, pb - r, r);
|
|
r = U_min(pd - pc, pn - pd - 1); vecswap2(pb, pn - r, r);
|
|
|
|
if ((r = pb - pa) > 1) mksort( a, r, depth);
|
|
if (ch(a + r) != 0) mksort(a + r, pa - a + pn - pd - 1, depth + 1);
|
|
if ((r = pd - pc) > 1) mksort(a + n - r, r, depth);
|
|
}
|
|
|
|
uint32_t UVector<UString>::loadFromData(const char* ptr, uint32_t sz)
|
|
{
|
|
U_TRACE(0+256, "UVector<UString>::loadFromData(%.*S,%u)", sz, ptr, sz)
|
|
|
|
U_INTERNAL_ASSERT_MAJOR(sz, 0)
|
|
U_INTERNAL_ASSERT_MAJOR(_capacity, 0)
|
|
|
|
const char* _end = ptr + sz;
|
|
const char* _start = ptr;
|
|
|
|
char terminator = 0, c = *ptr;
|
|
|
|
if (c == '(' ||
|
|
c == '[')
|
|
{
|
|
++ptr; // skip '(' or '['
|
|
|
|
terminator = (c == '(' ? ')' : ']');
|
|
}
|
|
|
|
U_INTERNAL_DUMP("terminator = %C", terminator)
|
|
|
|
while (ptr < _end)
|
|
{
|
|
// U_INTERNAL_DUMP("ptr = %.*S", 20, ptr)
|
|
|
|
c = *ptr++;
|
|
|
|
if (u__isspace(c)) continue; // skip white-space
|
|
|
|
// U_INTERNAL_DUMP("c = %C", c)
|
|
|
|
if ( terminator == c ||
|
|
(terminator == 0 &&
|
|
(c == '}' || c == ']')))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (c == '#')
|
|
{
|
|
do { c = *ptr++; } while (c != '\n' && ptr < _end); // skip line comment
|
|
|
|
continue;
|
|
}
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(u__isspace(c), false)
|
|
|
|
UString str(U_CAPACITY);
|
|
|
|
// U_INTERNAL_DUMP("c = %C", c)
|
|
|
|
if (c == '"')
|
|
{
|
|
// NB: check if we have a string null...
|
|
|
|
if (*ptr != '"') str.setFromData(&ptr, _end - ptr, '"');
|
|
else
|
|
{
|
|
++ptr;
|
|
|
|
str.clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
--ptr;
|
|
|
|
str.setFromData(&ptr, _end - ptr, terminator);
|
|
}
|
|
|
|
push(str);
|
|
}
|
|
|
|
U_INTERNAL_DUMP("ptr - _start = %lu", ptr - _start)
|
|
|
|
U_INTERNAL_ASSERT((ptr - _start) <= sz)
|
|
|
|
sz = ptr - _start;
|
|
|
|
U_RETURN(sz);
|
|
}
|
|
|
|
// STREAMS
|
|
|
|
#ifdef U_STDCPP_ENABLE
|
|
U_EXPORT istream& operator>>(istream& is, UVector<UString>& v)
|
|
{
|
|
U_TRACE(0+256, "UVector<UString>::operator>>(%p,%p)", &is, &v)
|
|
|
|
U_INTERNAL_ASSERT_MAJOR(v._capacity,0)
|
|
U_INTERNAL_ASSERT(is.peek() == '[' || is.peek() == '(')
|
|
|
|
if (is.good())
|
|
{
|
|
streambuf* sb = is.rdbuf();
|
|
|
|
int c = sb->sbumpc(); // skip '[' or '('
|
|
|
|
if (c == EOF) is.setstate(ios::eofbit);
|
|
else
|
|
{
|
|
int terminator = (c == '[' ? ']' : ')');
|
|
|
|
while (true)
|
|
{
|
|
do { c = sb->sbumpc(); } while (c != EOF && u__isspace(c)); // skip white-space
|
|
|
|
// U_INTERNAL_DUMP("c = %C", c)
|
|
|
|
if (c == terminator ||
|
|
c == EOF)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (c == '#')
|
|
{
|
|
do { c = sb->sbumpc(); } while (c != '\n' && c != EOF); // skip line comment
|
|
|
|
continue;
|
|
}
|
|
|
|
U_INTERNAL_ASSERT_EQUALS(u__isspace(c), false)
|
|
|
|
sb->sputbackc(c);
|
|
|
|
UString str(U_CAPACITY);
|
|
|
|
str.get(is);
|
|
|
|
v.push(str);
|
|
}
|
|
|
|
if (c == EOF) is.setstate(ios::eofbit);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------
|
|
// NB: we can load an empty vector (ex. mod_http)...
|
|
// -------------------------------------------------
|
|
// if (v._length == 0) is.setstate(ios::failbit);
|
|
// -------------------------------------------------
|
|
|
|
return is;
|
|
}
|
|
|
|
// DEBUG
|
|
|
|
# ifdef DEBUG
|
|
const char* UVector<void*>::dump(bool reset) const
|
|
{
|
|
*UObjectIO::os << "vec " << (void*)vec << '\n'
|
|
<< "_length " << _length << '\n'
|
|
<< "_capacity " << _capacity;
|
|
|
|
/*
|
|
<< "tail " << tail << '\n'
|
|
<< "head " << head << '\n'
|
|
*/
|
|
|
|
if (reset)
|
|
{
|
|
UObjectIO::output();
|
|
|
|
return UObjectIO::buffer_output;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
# endif
|
|
#endif
|