1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-24 00:03:11 +01:00

add new C++ memory utility functions

This commit is contained in:
IntelOrca
2015-09-02 22:00:02 +01:00
parent 952a4abdd1
commit 7a0478404e
8 changed files with 233 additions and 130 deletions

View File

@@ -208,6 +208,9 @@
<ClInclude Include="..\src\core\FileStream.hpp" />
<ClInclude Include="..\src\core\IDisposable.hpp" />
<ClInclude Include="..\src\core\IStream.hpp" />
<ClInclude Include="..\src\core\Memory.hpp" />
<ClInclude Include="..\src\core\StringBuilder.hpp" />
<ClInclude Include="..\src\core\StringReader.hpp" />
<ClInclude Include="..\src\cursors.h" />
<ClInclude Include="..\src\diagnostic.h" />
<ClInclude Include="..\src\drawing\drawing.h" />

View File

@@ -794,5 +794,14 @@
<ClInclude Include="..\src\localisation\LanguagePack.h">
<Filter>Source\Localisation</Filter>
</ClInclude>
<ClInclude Include="..\src\core\Memory.hpp">
<Filter>Source\Core</Filter>
</ClInclude>
<ClInclude Include="..\src\core\StringBuilder.hpp">
<Filter>Source\Core</Filter>
</ClInclude>
<ClInclude Include="..\src\core\StringReader.hpp">
<Filter>Source\Core</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -7,4 +7,6 @@ class Exception : public std::exception {
public:
Exception() : std::exception() { }
Exception(const char *message) : std::exception(message) { }
const char *GetMessage() const { return what(); }
};

64
src/core/Memory.hpp Normal file
View File

@@ -0,0 +1,64 @@
#pragma once
/**
* Utility methods for memory management. Typically helpers and wrappers around the C standard library.
*/
namespace Memory {
template<typename T>
T *Allocate() {
return (T*)malloc(sizeof(T));
}
template<typename T>
T *Allocate(size_t size) {
return (T*)malloc(size);
}
template<typename T>
T *AllocateArray(size_t count) {
return (T*)malloc(count * sizeof(T));
}
template<typename T>
T *Reallocate(T *ptr, size_t size) {
if (ptr == NULL)
return (T*)malloc(size);
else
return (T*)realloc((void*)ptr, size);
}
template<typename T>
T *ReallocateArray(T *ptr, size_t count) {
if (ptr == NULL)
return (T*)malloc(count * sizeof(T));
else
return (T*)realloc((void*)ptr, count * sizeof(T));
}
template<typename T>
void Free(T *ptr) {
free((void*)ptr);
}
template<typename T>
T *Copy(T *dst, const T *src, size_t size) {
return (T*)memcpy((void*)dst, (const void*)src, size);
}
template<typename T>
T *CopyArray(T *dst, const T *src, size_t count) {
return (T*)memcpy((void*)dst, (const void*)src, count * sizeof(T));
}
template<typename T>
T *Duplicate(const T *src, size_t size) {
T *result = Allocate<T>(size);
return Copy(result, src, size);
}
template<typename T>
T *DuplicateArray(const T *src, size_t count) {
T *result = AllocateArray<T>(count);
return CopyArray(result, src, count);
}
}

View File

@@ -0,0 +1,82 @@
#pragma once
#include "../common.h"
#include "../localisation/localisation.h"
#include "Memory.hpp"
/**
* Class for constructing strings efficiently. A buffer is automatically allocated and reallocated when characters or strings
* are appended. Use GetString to copy the current state of the string builder to a new fire and forget string.
*/
class StringBuilder final {
public:
StringBuilder() {
_buffer = NULL;
_capacity = 0;
_length = 0;
}
StringBuilder(int capacity) : StringBuilder() {
EnsureCapacity(capacity);
}
~StringBuilder() {
if (_buffer != NULL) Memory::Free(_buffer);
}
utf8 *GetString() const {
utf8 *result = Memory::AllocateArray<utf8>(_length + 1);
Memory::CopyArray(result, _buffer, _length);
result[_length] = 0;
return result;
}
void Append(int codepoint) {
int codepointLength = utf8_get_codepoint_length(codepoint);
EnsureCapacity(_length + codepointLength + 1);
utf8_write_codepoint(_buffer + _length, codepoint);
_length += codepointLength;
_buffer[_length] = 0;
}
void Append(utf8 *text) {
int textLength = strlen(text);
EnsureCapacity(_length + textLength + 1);
Memory::Copy(_buffer + _length, text, textLength);
_length += textLength;
_buffer[_length] = 0;
}
void Clear() {
_length = 0;
if (_capacity >= 1) {
_buffer[_length] = 0;
}
}
/**
* Gets the current state of the StringBuilder. Warning: this represents the StringBuilder's current working buffer and will
* be deallocated when the StringBuilder is destructed.
*/
const utf8 *GetBuffer() {
return _buffer;
}
private:
utf8 *_buffer;
size_t _capacity;
size_t _length;
void EnsureCapacity(size_t capacity)
{
if (_capacity > capacity) return;
_capacity = max(8, _capacity);
while (_capacity < capacity) {
_capacity *= 2;
}
_buffer = Memory::ReallocateArray<utf8>(_buffer, _capacity);
}
};

57
src/core/StringReader.hpp Normal file
View File

@@ -0,0 +1,57 @@
#pragma once
#include "../common.h"
#include "../localisation/localisation.h"
#include "../util/util.h"
interface IStringReader abstract {
virtual bool TryPeek(int *outCodepoint) abstract;
virtual bool TryRead(int *outCodepoint) abstract;
virtual void Skip() abstract;
};
class UTF8StringReader final : public IStringReader {
public:
UTF8StringReader(const utf8 *text)
{
// Skip UTF-8 byte order mark
if (strlen(text) >= 3 && utf8_is_bom(text)) {
text += 3;
}
_text = text;
_current = text;
}
bool TryPeek(int *outCodepoint) override
{
if (_current == NULL) return false;
int codepoint = utf8_get_next(_current, NULL);
*outCodepoint = codepoint;
return true;
}
bool TryRead(int *outCodepoint) override
{
if (_current == NULL) return false;
int codepoint = utf8_get_next(_current, &_current);
*outCodepoint = codepoint;
if (codepoint == 0) {
_current = NULL;
return false;
}
return true;
}
void Skip() override
{
int codepoint;
TryRead(&codepoint);
}
private:
const utf8 *_text;
const utf8 *_current;
};

View File

@@ -4,100 +4,37 @@ extern "C" {
#include "localisation.h"
}
#include "../core/FileStream.hpp"
#include "../core/Memory.hpp"
#include "../core/StringBuilder.hpp"
#include "LanguagePack.h"
#include <SDL.h>
// TODO Move to separate file
class StringBuilder final {
public:
StringBuilder()
{
_buffer = NULL;
_capacity = 0;
_length = 0;
}
StringBuilder(int capacity) : StringBuilder()
{
EnsureCapacity(capacity);
}
~StringBuilder()
{
if (_buffer != NULL) free(_buffer);
}
utf8 *GetString() const
{
utf8 *result = (utf8*)malloc(_length + 1);
memcpy(result, _buffer, _length);
result[_length] = 0;
return result;
}
void Append(int codepoint)
{
int codepointLength = utf8_get_codepoint_length(codepoint);
EnsureCapacity(_length + codepointLength + 1);
utf8_write_codepoint(_buffer + _length, codepoint);
_length += codepointLength;
}
void Append(utf8 *text)
{
int textLength = strlen(text);
EnsureCapacity(_length + textLength + 1);
memcpy(_buffer + _length, text, textLength);
_length += textLength;
}
private:
utf8 *_buffer;
size_t _capacity;
size_t _length;
void EnsureCapacity(size_t capacity)
{
if (_capacity > capacity) return;
_capacity = max(8, _capacity);
while (_capacity < capacity) {
_capacity *= 2;
}
if (_buffer == NULL) {
_buffer = (utf8*)malloc(_capacity);
} else {
_buffer = (utf8*)realloc(_buffer, _capacity);
}
}
};
LanguagePack *LanguagePack::FromFile(int id, const utf8 *path)
{
assert(path != NULL);
int fileLength;
uint32 fileLength;
utf8 *fileData;
// Load file directly into memory
SDL_RWops *file = SDL_RWFromFile(path, "rb");
if (file == NULL) {
log_error("Unable to open %s", path);
try {
FileStream fs = FileStream(path, FILE_MODE_OPEN);
fileLength = (uint32)fs.GetLength();
fileData = Memory::Allocate<utf8>(fileLength);
fs.Read(fileData, fileLength);
fs.Dispose();
} catch (Exception ex) {
log_error("Unable to open %s: %s", path, ex.GetMessage());
return NULL;
}
fileLength = (int)SDL_RWsize(file);
fileData = (utf8*)malloc(fileLength);
SDL_RWread(file, fileData, fileLength, 1);
SDL_RWclose(file);
// Parse the memory as text
LanguagePack *result = FromText(id, fileData);
free(fileData);
Memory::Free(fileData);
return result;
}

View File

@@ -8,58 +8,7 @@ extern "C" {
#include "localisation.h"
}
struct IStringReader abstract {
virtual bool TryPeek(int *outCodepoint) abstract;
virtual bool TryRead(int *outCodepoint) abstract;
virtual void Skip() abstract;
};
// TODO Move to separate file in Core
class UTF8StringReader final : public IStringReader {
public:
UTF8StringReader(const utf8 *text)
{
// Skip UTF-8 byte order mark
if (strlen(text) >= 3 && utf8_is_bom(text)) {
text += 3;
}
_text = text;
_current = text;
}
bool TryPeek(int *outCodepoint) override
{
if (_current == NULL) return false;
int codepoint = utf8_get_next(_current, NULL);
*outCodepoint = codepoint;
return true;
}
bool TryRead(int *outCodepoint) override
{
if (_current == NULL) return false;
int codepoint = utf8_get_next(_current, &_current);
*outCodepoint = codepoint;
if (codepoint == 0) {
_current = NULL;
return false;
}
return true;
}
void Skip() override
{
int codepoint;
TryRead(&codepoint);
}
private:
const utf8 *_text;
const utf8 *_current;
};
#include "../core/StringReader.hpp"
class LanguagePack final {
public: