diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/algorithm.h | 12 | ||||
-rw-r--r-- | common/array.h | 109 | ||||
-rw-r--r-- | common/macresman.cpp | 4 | ||||
-rw-r--r-- | common/memory.h | 65 | ||||
-rw-r--r-- | common/scummsys.h | 9 | ||||
-rw-r--r-- | common/translation.cpp | 14 | ||||
-rw-r--r-- | common/translation.h | 4 | ||||
-rw-r--r-- | common/util.h | 1 |
8 files changed, 154 insertions, 64 deletions
diff --git a/common/algorithm.h b/common/algorithm.h index e7ccef4840..7a0eed89ce 100644 --- a/common/algorithm.h +++ b/common/algorithm.h @@ -73,25 +73,25 @@ Out copy_if(In first, In last, Out dst, Op op) { return dst; } -// Our 'specialized' 'set_to' template for char, signed char and unsigned char arrays. +// Our 'specialized' 'fill' template for char, signed char and unsigned char arrays. // Since C++ doesn't support partial specialized template functions (currently) we // are going this way... // With this we assure the usage of memset for those, which should be -// faster than a simple loop like for the generic 'set_to'. +// faster than a simple loop like for the generic 'fill'. template<class Value> -signed char *set_to(signed char *first, signed char *last, Value val) { +signed char *fill(signed char *first, signed char *last, Value val) { memset(first, (val & 0xFF), last - first); return last; } template<class Value> -unsigned char *set_to(unsigned char *first, unsigned char *last, Value val) { +unsigned char *fill(unsigned char *first, unsigned char *last, Value val) { memset(first, (val & 0xFF), last - first); return last; } template<class Value> -char *set_to(char *first, char *last, Value val) { +char *fill(char *first, char *last, Value val) { memset(first, (val & 0xFF), last - first); return last; } @@ -100,7 +100,7 @@ char *set_to(char *first, char *last, Value val) { * Sets all elements in the range [first, last) to val. */ template<class In, class Value> -In set_to(In first, In last, Value val) { +In fill(In first, In last, const Value &val) { while (first != last) *first++ = val; return first; diff --git a/common/array.h b/common/array.h index 18cecfb98f..ef0ee27f24 100644 --- a/common/array.h +++ b/common/array.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/algorithm.h" #include "common/textconsole.h" // For error() +#include "common/memory.h" namespace Common { @@ -37,23 +38,7 @@ namespace Common { * proportional to the number of elements in the array. * * The container class closest to this in the C++ standard library is - * std::vector. However, there are some differences. The most important one is - * that std::vector has a far more sophisticated (and complicated) memory - * management scheme. There, only elements that 'live' are actually constructed - * (i.e., have their constructor called), and objects that are removed are - * immediately destructed (have their destructor called). - * With Array, this is not the case; instead, it simply uses new[] and - * delete[] to allocate whole blocks of objects, possibly more than are - * currently 'alive'. This simplifies memory management, but may have - * undesirable side effects when one wants to use an Array of complex - * data types. - * - * @todo Improve the storage management of this class. - * In particular, don't use new[] and delete[], but rather - * construct/destruct objects manually. This way, we can - * ensure that storage which is not currently used does not - * correspond to a live active object. - * (This is only of interest for array of non-POD objects). + * std::vector. However, there are some differences. */ template<class T> class Array { @@ -74,7 +59,7 @@ public: Array(const Array<T> &array) : _capacity(array._size), _size(array._size), _storage(0) { if (array._storage) { allocCapacity(_size); - copy(array._storage, array._storage + _size, _storage); + uninitialized_copy(array._storage, array._storage + _size, _storage); } } @@ -85,11 +70,11 @@ public: Array(const T2 *data, int n) { _size = n; allocCapacity(n); - copy(data, data + _size, _storage); + uninitialized_copy(data, data + _size, _storage); } ~Array() { - delete[] _storage; + freeStorage(_storage, _size); _storage = 0; _capacity = _size = 0; } @@ -97,14 +82,14 @@ public: /** Appends element to the end of the array. */ void push_back(const T &element) { if (_size + 1 <= _capacity) - _storage[_size++] = element; + new ((void *)&_storage[_size++]) T(element); else insert_aux(end(), &element, &element + 1); } void push_back(const Array<T> &array) { if (_size + array.size() <= _capacity) { - copy(array.begin(), array.end(), end()); + uninitialized_copy(array.begin(), array.end(), end()); _size += array.size(); } else insert_aux(end(), array.begin(), array.end()); @@ -114,6 +99,8 @@ public: void pop_back() { assert(_size > 0); _size--; + // We also need to destroy the last object properly here. + _storage[_size].~T(); } /** Returns a reference to the first element of the array. */ @@ -157,6 +144,8 @@ public: T tmp = _storage[idx]; copy(_storage + idx + 1, _storage + _size, _storage + idx); _size--; + // We also need to destroy the last object properly here. + _storage[_size].~T(); return tmp; } @@ -176,10 +165,10 @@ public: if (this == &array) return *this; - delete[] _storage; + freeStorage(_storage, _size); _size = array._size; allocCapacity(_size); - copy(array._storage, array._storage + _size, _storage); + uninitialized_copy(array._storage, array._storage + _size, _storage); return *this; } @@ -189,7 +178,7 @@ public: } void clear() { - delete[] _storage; + freeStorage(_storage, _size); _storage = 0; _size = 0; _capacity = 0; @@ -240,15 +229,15 @@ public: if (oldStorage) { // Copy old data - copy(oldStorage, oldStorage + _size, _storage); - delete[] oldStorage; + uninitialized_copy(oldStorage, oldStorage + _size, _storage); + freeStorage(oldStorage, _size); } } void resize(uint newSize) { reserve(newSize); for (uint i = _size; i < newSize; ++i) - _storage[i] = T(); + new ((void *)&_storage[i]) T(); _size = newSize; } @@ -272,7 +261,7 @@ protected: void allocCapacity(uint capacity) { _capacity = capacity; if (capacity) { - _storage = new T[capacity]; + _storage = (T *)malloc(sizeof(T) * capacity); if (!_storage) ::error("Common::Array: failure to allocate %u bytes", capacity * (uint)sizeof(T)); } else { @@ -280,6 +269,12 @@ protected: } } + void freeStorage(T *storage, const uint elements) { + for (uint i = 0; i < elements; ++i) + storage[i].~T(); + free(storage); + } + /** * Insert a range of elements coming from this or another array. * Unlike std::vector::insert, this method does not accept @@ -299,29 +294,49 @@ protected: const uint n = last - first; if (n) { const uint idx = pos - _storage; - T *oldStorage = _storage; - if (_size + n > _capacity || (_storage <= first && first <= _storage + _size) ) { - // If there is not enough space, allocate more and - // copy old elements over. + if (_size + n > _capacity || (_storage <= first && first <= _storage + _size)) { + T *const oldStorage = _storage; + + // If there is not enough space, allocate more. // Likewise, if this is a self-insert, we allocate new - // storage to avoid conflicts. This is not the most efficient - // way to ensure that, but probably the simplest on. + // storage to avoid conflicts. allocCapacity(roundUpCapacity(_size + n)); - copy(oldStorage, oldStorage + idx, _storage); - pos = _storage + idx; - } - - // Make room for the new elements by shifting back - // existing ones. - copy_backward(oldStorage + idx, oldStorage + _size, _storage + _size + n); - // Insert the new elements. - copy(first, last, pos); + // Copy the data from the old storage till the position where + // we insert new data + uninitialized_copy(oldStorage, oldStorage + idx, _storage); + // Copy the data we insert + uninitialized_copy(first, last, _storage + idx); + // Afterwards copy the old data from the position where we + // insert. + uninitialized_copy(oldStorage + idx, oldStorage + _size, _storage + idx + n); + + freeStorage(oldStorage, _size); + } else if (idx + n <= _size) { + // Make room for the new elements by shifting back + // existing ones. + // 1. Move a part of the data to the uninitialized area + uninitialized_copy(_storage + _size - n, _storage + _size, _storage + _size); + // 2. Move a part of the data to the initialized area + copy_backward(pos, _storage + _size - n, _storage + _size); + + // Insert the new elements. + copy(first, last, pos); + } else { + // Copy the old data from the position till the end to the new + // place. + uninitialized_copy(pos, _storage + _size, _storage + idx + n); + + // Copy a part of the new data to the position inside the + // initialized space. + copy(first, first + (_size - idx), pos); + + // Copy a part of the new data to the position inside the + // uninitialized space. + uninitialized_copy(first + (_size - idx), last, _storage + _size); + } // Finally, update the internal state - if (_storage != oldStorage) { - delete[] oldStorage; - } _size += n; } return pos; diff --git a/common/macresman.cpp b/common/macresman.cpp index 2b9c68ade9..1317600cb7 100644 --- a/common/macresman.cpp +++ b/common/macresman.cpp @@ -110,7 +110,7 @@ bool MacResManager::open(String filename) { String fullPath = ConfMan.get("path") + "/" + filename + "/..namedfork/rsrc"; FSNode resFsNode = FSNode(fullPath); if (resFsNode.exists()) { - SeekableReadStream *macResForkRawStream = resFsNode.createReadStream();; + SeekableReadStream *macResForkRawStream = resFsNode.createReadStream(); if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) { _baseFileName = filename; @@ -173,7 +173,7 @@ bool MacResManager::open(FSNode path, String filename) { String fullPath = path.getPath() + "/" + filename + "/..namedfork/rsrc"; FSNode resFsNode = FSNode(fullPath); if (resFsNode.exists()) { - SeekableReadStream *macResForkRawStream = resFsNode.createReadStream();; + SeekableReadStream *macResForkRawStream = resFsNode.createReadStream(); if (macResForkRawStream && loadFromRawFork(*macResForkRawStream)) { _baseFileName = filename; diff --git a/common/memory.h b/common/memory.h new file mode 100644 index 0000000000..0e5a97c20b --- /dev/null +++ b/common/memory.h @@ -0,0 +1,65 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef COMMON_MEMORY_H +#define COMMON_MEMORY_H + +#include "common/scummsys.h" + +namespace Common { + +/** + * Copies data from the range [first, last) to [dst, dst + (last - first)). + * It requires the range [dst, dst + (last - first)) to be valid and + * uninitialized. + */ +template<class In, class Type> +Type *uninitialized_copy(In first, In last, Type *dst) { + while (first != last) + new ((void *)dst++) Type(*first++); + return dst; +} + +/** + * Initializes the memory [first, first + (last - first)) with the value x. + * It requires the range [first, first + (last - first)) to be valid and + * uninitialized. + */ +/*template<class Type, class Value> +void uninitialized_fill(Type *first, Type *last, const Value &x) { + while (first != last) + new ((void *)first++) Type(x); +}*/ + +/** + * Initializes the memory [dst, dst + n) with the value x. + * It requires the range [dst, dst + n) to be valid and + * uninitialized. + */ +/*template<class Type, class Value> +void uninitialized_fill_n(Type *dst, size_t n, const Value &x) { + while (n--) + new ((void *)dst++) Type(x); +}*/ + +} // End of namespace Common + +#endif diff --git a/common/scummsys.h b/common/scummsys.h index fbd5bb5273..6baab7c16f 100644 --- a/common/scummsys.h +++ b/common/scummsys.h @@ -130,6 +130,15 @@ #define _USE_MATH_DEFINES #include <math.h> + // FIXME: We sadly can't assume standard C++ headers to be present on every + // system we support, so we should get rid of this. The solution should be to + // write a simple placement new on our own. It might be noteworthy we can't + // easily do that for systems which do have a <new>, since it might clash with + // the default definition otherwise! + // Symbian does not have <new> but the new operator + #if !defined(__SYMBIAN32__) + #include <new> + #endif #endif diff --git a/common/translation.cpp b/common/translation.cpp index 3570e8c5ae..081bde987d 100644 --- a/common/translation.cpp +++ b/common/translation.cpp @@ -130,14 +130,14 @@ const char *TranslationManager::getTranslation(const char *message, const char * // Get the range of messages with the same ID (but different context) leftIndex = rightIndex = midIndex; while ( - leftIndex > 0 && - _currentTranslationMessages[leftIndex - 1].msgid == m->msgid + leftIndex > 0 && + _currentTranslationMessages[leftIndex - 1].msgid == m->msgid ) { --leftIndex; } while ( - rightIndex < (int)_currentTranslationMessages.size() - 1 && - _currentTranslationMessages[rightIndex + 1].msgid == m->msgid + rightIndex < (int)_currentTranslationMessages.size() - 1 && + _currentTranslationMessages[rightIndex + 1].msgid == m->msgid ) { ++rightIndex; } @@ -222,7 +222,7 @@ String TranslationManager::getLangById(int id) const { return ""; } -bool TranslationManager::openTranslationsFile(File& inFile) { +bool TranslationManager::openTranslationsFile(File &inFile) { // First look in the Themepath if we can find the file. if (ConfMan.hasKey("themepath") && openTranslationsFile(FSNode(ConfMan.get("themepath")), inFile)) return true; @@ -242,7 +242,7 @@ bool TranslationManager::openTranslationsFile(File& inFile) { return false; } -bool TranslationManager::openTranslationsFile(const FSNode &node, File& inFile, int depth) { +bool TranslationManager::openTranslationsFile(const FSNode &node, File &inFile, int depth) { if (!node.exists() || !node.isReadable() || !node.isDirectory()) return false; @@ -390,7 +390,7 @@ bool TranslationManager::checkHeader(File &in) { buf[12] = '\0'; // Check header - if (strcmp(buf, "TRANSLATIONS")) { + if (strcmp(buf, "TRANSLATIONS") != 0) { warning("File '%s' is not a valid translations data file. Skipping this file", in.getName()); return false; } diff --git a/common/translation.h b/common/translation.h index 9e5245702e..71cf2b0981 100644 --- a/common/translation.h +++ b/common/translation.h @@ -173,13 +173,13 @@ private: * then if needed using the Themepath. If found it opens the given File * to read the translations.dat file. */ - bool openTranslationsFile(File&); + bool openTranslationsFile(File &); /** * Find the translations.dat file in the given directory node. * If found it opens the given File to read the translations.dat file. */ - bool openTranslationsFile(const FSNode &node, File&, int depth = -1); + bool openTranslationsFile(const FSNode &node, File &, int depth = -1); /** * Load the list of languages from the translations.dat file diff --git a/common/util.h b/common/util.h index f8d4c3b385..c9ff83c1cf 100644 --- a/common/util.h +++ b/common/util.h @@ -101,6 +101,7 @@ template<typename T> inline void SWAP(T &a, T &b) { T tmp = a; a = b; b = tmp; } #define GUIO_NOASPECT "\021" #define GUIO_EGAUNDITHER "\022" +#define GUIO0() (GUIO_NONE) #define GUIO1(a) (a) #define GUIO2(a,b) (a b) #define GUIO3(a,b,c) (a b c) |