aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/algorithm.h12
-rw-r--r--common/array.h109
-rw-r--r--common/macresman.cpp4
-rw-r--r--common/memory.h65
-rw-r--r--common/scummsys.h9
-rw-r--r--common/translation.cpp14
-rw-r--r--common/translation.h4
-rw-r--r--common/util.h1
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)