From 7a0478404efb34b973e2407c37a9cc298d09a3ee Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Wed, 2 Sep 2015 22:00:02 +0100 Subject: [PATCH] add new C++ memory utility functions --- projects/openrct2.vcxproj | 3 + projects/openrct2.vcxproj.filters | 9 +++ src/core/Exception.hpp | 2 + src/core/Memory.hpp | 64 +++++++++++++++++++++ src/core/StringBuilder.hpp | 82 +++++++++++++++++++++++++++ src/core/StringReader.hpp | 57 +++++++++++++++++++ src/localisation/LanguagePack.cpp | 93 +++++-------------------------- src/localisation/LanguagePack.h | 53 +----------------- 8 files changed, 233 insertions(+), 130 deletions(-) create mode 100644 src/core/Memory.hpp create mode 100644 src/core/StringBuilder.hpp create mode 100644 src/core/StringReader.hpp diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 688622c8a5..bca15bf71e 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -208,6 +208,9 @@ + + + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 9cd193edaf..dad1e96ac8 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -794,5 +794,14 @@ Source\Localisation + + Source\Core + + + Source\Core + + + Source\Core + \ No newline at end of file diff --git a/src/core/Exception.hpp b/src/core/Exception.hpp index f3daf469e6..2940d578b0 100644 --- a/src/core/Exception.hpp +++ b/src/core/Exception.hpp @@ -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(); } }; diff --git a/src/core/Memory.hpp b/src/core/Memory.hpp new file mode 100644 index 0000000000..2e4d77c99a --- /dev/null +++ b/src/core/Memory.hpp @@ -0,0 +1,64 @@ +#pragma once + +/** + * Utility methods for memory management. Typically helpers and wrappers around the C standard library. + */ +namespace Memory { + template + T *Allocate() { + return (T*)malloc(sizeof(T)); + } + + template + T *Allocate(size_t size) { + return (T*)malloc(size); + } + + template + T *AllocateArray(size_t count) { + return (T*)malloc(count * sizeof(T)); + } + + template + T *Reallocate(T *ptr, size_t size) { + if (ptr == NULL) + return (T*)malloc(size); + else + return (T*)realloc((void*)ptr, size); + } + + template + 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 + void Free(T *ptr) { + free((void*)ptr); + } + + template + T *Copy(T *dst, const T *src, size_t size) { + return (T*)memcpy((void*)dst, (const void*)src, size); + } + + template + T *CopyArray(T *dst, const T *src, size_t count) { + return (T*)memcpy((void*)dst, (const void*)src, count * sizeof(T)); + } + + template + T *Duplicate(const T *src, size_t size) { + T *result = Allocate(size); + return Copy(result, src, size); + } + + template + T *DuplicateArray(const T *src, size_t count) { + T *result = AllocateArray(count); + return CopyArray(result, src, count); + } +} diff --git a/src/core/StringBuilder.hpp b/src/core/StringBuilder.hpp new file mode 100644 index 0000000000..251fd5ca5a --- /dev/null +++ b/src/core/StringBuilder.hpp @@ -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(_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(_buffer, _capacity); + } +}; diff --git a/src/core/StringReader.hpp b/src/core/StringReader.hpp new file mode 100644 index 0000000000..095f7bd285 --- /dev/null +++ b/src/core/StringReader.hpp @@ -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; +}; diff --git a/src/localisation/LanguagePack.cpp b/src/localisation/LanguagePack.cpp index a9deaa3781..ecfe0e934e 100644 --- a/src/localisation/LanguagePack.cpp +++ b/src/localisation/LanguagePack.cpp @@ -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 -// 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(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; } diff --git a/src/localisation/LanguagePack.h b/src/localisation/LanguagePack.h index a66bc02093..10b4c29d8b 100644 --- a/src/localisation/LanguagePack.h +++ b/src/localisation/LanguagePack.h @@ -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: