You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/CryCommonTools/SimpleStringPool.h

250 lines
6.7 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYCOMMONTOOLS_SIMPLESTRINGPOOL_H
#define CRYINCLUDE_CRYCOMMONTOOLS_SIMPLESTRINGPOOL_H
#pragma once
#include <algorithm>
/////////////////////////////////////////////////////////////////////
// String pool implementation.
// Inspired by expat implementation.
/////////////////////////////////////////////////////////////////////
class CSimpleStringPool
{
public:
enum
{
STD_BLOCK_SIZE = 4096
};
struct BLOCK
{
BLOCK* next;
int size;
char s[1];
};
unsigned int m_blockSize;
BLOCK* m_blocks;
BLOCK* m_free_blocks;
const char* m_end;
char* m_ptr;
char* m_start;
int nUsedSpace;
int nUsedBlocks;
CSimpleStringPool()
{
m_blockSize = STD_BLOCK_SIZE;
m_blocks = 0;
m_start = 0;
m_ptr = 0;
m_end = 0;
nUsedSpace = 0;
nUsedBlocks = 0;
m_free_blocks = 0;
}
~CSimpleStringPool()
{
BLOCK* pBlock = m_blocks;
while (pBlock)
{
BLOCK* temp = pBlock->next;
//nFree++;
free(pBlock);
pBlock = temp;
}
pBlock = m_free_blocks;
while (pBlock)
{
BLOCK* temp = pBlock->next;
//nFree++;
free(pBlock);
pBlock = temp;
}
m_blocks = 0;
m_ptr = 0;
m_start = 0;
m_end = 0;
}
void SetBlockSize(unsigned int nBlockSize)
{
if (nBlockSize > 1024 * 1024)
{
nBlockSize = 1024 * 1024;
}
unsigned int size = 512;
while (size < nBlockSize)
{
size *= 2;
}
m_blockSize = size - offsetof(BLOCK, s);
}
void Clear()
{
if (m_free_blocks)
{
BLOCK* pLast = m_blocks;
while (pLast)
{
BLOCK* temp = pLast->next;
if (!temp)
{
break;
}
pLast = temp;
}
if (pLast)
{
pLast->next = m_free_blocks;
}
}
m_free_blocks = m_blocks;
m_blocks = 0;
m_start = 0;
m_ptr = 0;
m_end = 0;
nUsedSpace = 0;
}
char* Append(const char* ptr, int nStrLen)
{
char* ret = m_ptr;
if (m_ptr && nStrLen + 1 < (m_end - m_ptr))
{
memcpy(m_ptr, ptr, nStrLen);
m_ptr = m_ptr + nStrLen;
*m_ptr++ = 0; // add null termination.
}
else
{
int nNewBlockSize = (std::max)(nStrLen + 1, (int)m_blockSize);
AllocBlock(nNewBlockSize, nStrLen + 1);
memcpy(m_ptr, ptr, nStrLen);
m_ptr = m_ptr + nStrLen;
*m_ptr++ = 0; // add null termination.
ret = m_start;
}
nUsedSpace += nStrLen;
return ret;
}
char* ReplaceString(const char* str1, const char* str2)
{
int nStrLen1 = check_cast<int>(strlen(str1));
int nStrLen2 = check_cast<int>(strlen(str2));
// undo ptr1 add.
if (m_ptr != m_start)
{
m_ptr = m_ptr - nStrLen1 - 1;
}
assert(m_ptr == str1);
int nStrLen = nStrLen1 + nStrLen2;
char* ret = m_ptr;
if (m_ptr && nStrLen + 1 < (m_end - m_ptr))
{
memcpy(m_ptr, str1, nStrLen1);
memcpy(m_ptr + nStrLen1, str2, nStrLen2);
m_ptr = m_ptr + nStrLen;
*m_ptr++ = 0; // add null termination.
}
else
{
int nNewBlockSize = (std::max)(nStrLen + 1, check_cast<int>(m_blockSize));
if (m_ptr == m_start)
{
ReallocBlock(nNewBlockSize * 2); // Reallocate current block.
memcpy(m_ptr + nStrLen1, str2, nStrLen2);
}
else
{
AllocBlock(nNewBlockSize, nStrLen + 1);
memcpy(m_ptr, str1, nStrLen1);
memcpy(m_ptr + nStrLen1, str2, nStrLen2);
}
m_ptr = m_ptr + nStrLen;
*m_ptr++ = 0; // add null termination.
ret = m_start;
}
nUsedSpace += nStrLen;
return ret;
}
private:
void AllocBlock(int blockSize, int nMinBlockSize)
{
if (m_free_blocks)
{
BLOCK* pBlock = m_free_blocks;
BLOCK* pPrev = 0;
while (pBlock)
{
if (pBlock->size >= nMinBlockSize)
{
// Reuse free block
if (pPrev)
{
pPrev->next = pBlock->next;
}
else
{
m_free_blocks = pBlock->next;
}
pBlock->next = m_blocks;
m_blocks = pBlock;
m_ptr = pBlock->s;
m_start = pBlock->s;
m_end = pBlock->s + pBlock->size;
return;
}
pPrev = pBlock;
pBlock = pBlock->next;
}
}
size_t nMallocSize = offsetof(BLOCK, s) + blockSize * sizeof(char);
//nMallocs++;
BLOCK* pBlock = (BLOCK*)malloc(nMallocSize);
pBlock->size = blockSize;
pBlock->next = m_blocks;
m_blocks = pBlock;
m_ptr = pBlock->s;
m_start = pBlock->s;
m_end = pBlock->s + blockSize;
nUsedBlocks++;
}
void ReallocBlock(int blockSize)
{
BLOCK* pThisBlock = m_blocks;
BLOCK* pPrevBlock = m_blocks->next;
m_blocks = pPrevBlock;
size_t nMallocSize = offsetof(BLOCK, s) + blockSize * sizeof(char);
//nMallocs++;
BLOCK* pBlock = (BLOCK*)realloc(pThisBlock, nMallocSize);
pBlock->size = blockSize;
pBlock->next = m_blocks;
m_blocks = pBlock;
m_ptr = pBlock->s;
m_start = pBlock->s;
m_end = pBlock->s + blockSize;
}
};
#endif // CRYINCLUDE_CRYCOMMONTOOLS_SIMPLESTRINGPOOL_H