[Scummvm-cvs-logs] SF.net SVN: scummvm:[47355] tools/trunk
tdhs at users.sourceforge.net
tdhs at users.sourceforge.net
Mon Jan 18 16:40:49 CET 2010
Revision: 47355
http://scummvm.svn.sourceforge.net/scummvm/?rev=47355&view=rev
Author: tdhs
Date: 2010-01-18 15:40:49 +0000 (Mon, 18 Jan 2010)
Log Message:
-----------
Removed Mohawk tool specific String class and migrated to Common::String.
Modified Paths:
--------------
tools/trunk/Makefile.common
tools/trunk/common/scummsys.h
tools/trunk/engines/mohawk/mohawk_file.cpp
tools/trunk/engines/mohawk/mohawk_file.h
tools/trunk/engines/mohawk/util.h
Added Paths:
-----------
tools/trunk/common/hash-str.h
tools/trunk/common/hashmap.cpp
tools/trunk/common/hashmap.h
tools/trunk/common/memorypool.cpp
tools/trunk/common/memorypool.h
Removed Paths:
-------------
tools/trunk/engines/mohawk/utils/str.cpp
tools/trunk/engines/mohawk/utils/str.h
Modified: tools/trunk/Makefile.common
===================================================================
--- tools/trunk/Makefile.common 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/Makefile.common 2010-01-18 15:40:49 UTC (rev 47355)
@@ -85,7 +85,10 @@
UTILS := \
common/file.o \
+ common/hashmap.o \
common/md5.o \
+ common/memorypool.o \
+ common/str.o \
common/util.o \
sound/adpcm.o \
sound/audiostream.o \
@@ -134,7 +137,9 @@
deriven_OBJS := \
engines/mohawk/deriven.o \
engines/mohawk/mohawk_file.o \
- engines/mohawk/utils/str.o \
+ common/hashmap.o \
+ common/memorypool.o \
+ common/str.o \
engines/mohawk/utils/file.o \
engines/mohawk/utils/adpcm.o \
engines/mohawk/utils/audiostream.o \
@@ -168,7 +173,9 @@
extract_mohawk_OBJS := \
engines/mohawk/extract_mohawk.o \
engines/mohawk/mohawk_file.o \
- engines/mohawk/utils/str.o \
+ common/hashmap.o \
+ common/memorypool.o \
+ common/str.o \
engines/mohawk/utils/file.o \
engines/mohawk/utils/adpcm.o \
engines/mohawk/utils/audiostream.o \
Added: tools/trunk/common/hash-str.h
===================================================================
--- tools/trunk/common/hash-str.h (rev 0)
+++ tools/trunk/common/hash-str.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -0,0 +1,88 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef COMMON_HASH_STR_H
+#define COMMON_HASH_STR_H
+
+#include "common/hashmap.h"
+#include "common/str.h"
+
+namespace Common {
+
+uint hashit(const char *str);
+uint hashit_lower(const char *str); // Generate a hash based on the lowercase version of the string
+inline uint hashit(const String &str) { return hashit(str.c_str()); }
+inline uint hashit_lower(const String &str) { return hashit_lower(str.c_str()); }
+
+
+// FIXME: The following functors obviously are not consistently named
+
+struct CaseSensitiveString_EqualTo {
+ bool operator()(const String& x, const String& y) const { return x.equals(y); }
+};
+
+struct CaseSensitiveString_Hash {
+ uint operator()(const String& x) const { return hashit(x.c_str()); }
+};
+
+
+struct IgnoreCase_EqualTo {
+ bool operator()(const String& x, const String& y) const { return x.equalsIgnoreCase(y); }
+};
+
+struct IgnoreCase_Hash {
+ uint operator()(const String& x) const { return hashit_lower(x.c_str()); }
+};
+
+
+
+// Specalization of the Hash functor for String objects.
+// We do case sensitve hashing here, because that is what
+// the default EqualTo is compatible with. If one wants to use
+// case insensitve hashing, then only because one wants to use
+// IgnoreCase_EqualTo, and then one has to specify a custom
+// hash anyway.
+template <>
+struct Hash<String> {
+ uint operator()(const String& s) const {
+ return hashit(s.c_str());
+ }
+};
+
+template <>
+struct Hash<const char *> {
+ uint operator()(const char *s) const {
+ return hashit(s);
+ }
+};
+
+// String map -- by default case insensitive
+typedef HashMap<String, String, IgnoreCase_Hash, IgnoreCase_EqualTo> StringMap;
+
+
+
+} // End of namespace Common
+
+
+#endif
Property changes on: tools/trunk/common/hash-str.h
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Rev Author URL Id
Added: svn:eol-style
+ native
Added: tools/trunk/common/hashmap.cpp
===================================================================
--- tools/trunk/common/hashmap.cpp (rev 0)
+++ tools/trunk/common/hashmap.cpp 2010-01-18 15:40:49 UTC (rev 47355)
@@ -0,0 +1,112 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// The hash map (associative array) implementation in this file is
+// based on the PyDict implementation of CPython. The erase() method
+// is based on example code in the Wikipedia article on Hash tables.
+
+#include "common/hashmap.h"
+
+namespace Common {
+
+// Hash function for strings, taken from CPython.
+uint hashit(const char *p) {
+ uint hash = *p << 7;
+ byte c;
+ int size = 0;
+ while ((c = *p++)) {
+ hash = (1000003 * hash) ^ c;
+ size++;
+ }
+ return hash ^ size;
+}
+
+// Like hashit, but converts every char to lowercase before hashing.
+uint hashit_lower(const char *p) {
+ uint hash = tolower(*p) << 7;
+ byte c;
+ int size = 0;
+ while ((c = *p++)) {
+ hash = (1000003 * hash) ^ tolower(c);
+ size++;
+ }
+ return hash ^ size;
+}
+
+#ifdef DEBUG_HASH_COLLISIONS
+static double
+ g_collisions = 0,
+ g_dummyHits = 0,
+ g_lookups = 0,
+ g_collPerLook = 0,
+ g_capacity = 0,
+ g_size = 0;
+static int g_max_capacity = 0, g_max_size = 0;
+static int g_totalHashmaps = 0;
+static int g_stats[4] = {0,0,0,0};
+
+void updateHashCollisionStats(int collisions, int dummyHits, int lookups, int arrsize, int nele) {
+ g_collisions += collisions;
+ g_lookups += lookups;
+ g_dummyHits += dummyHits;
+ if (lookups)
+ g_collPerLook += (double)collisions / (double)lookups;
+ g_capacity += arrsize;
+ g_size += nele;
+ g_totalHashmaps++;
+
+ if (3*nele <= 2*8)
+ g_stats[0]++;
+ if (3*nele <= 2*16)
+ g_stats[1]++;
+ if (3*nele <= 2*32)
+ g_stats[2]++;
+ if (3*nele <= 2*64)
+ g_stats[3]++;
+
+ g_max_capacity = MAX(g_max_capacity, arrsize);
+ g_max_size = MAX(g_max_size, nele);
+
+ fprintf(stdout, "%d hashmaps: colls %.1f; dummies hit %.1f, lookups %.1f; ratio %.3f%%; size %f (max: %d); capacity %f (max: %d)\n",
+ g_totalHashmaps,
+ g_collisions / g_totalHashmaps,
+ g_dummyHits / g_totalHashmaps,
+ g_lookups / g_totalHashmaps,
+ 100 * g_collPerLook / g_totalHashmaps,
+ g_size / g_totalHashmaps, g_max_size,
+ g_capacity / g_totalHashmaps, g_max_capacity);
+ fprintf(stdout, " %d less than %d; %d less than %d; %d less than %d; %d less than %d\n",
+ g_stats[0], 2*8/3,
+ g_stats[1],2*16/3,
+ g_stats[2],2*32/3,
+ g_stats[3],2*64/3);
+
+ // TODO:
+ // * Should record the maximal size of the map during its lifetime, not that at its death
+ // * Should do some statistics: how many maps are less than 2/3*8, 2/3*16, 2/3*32, ...
+}
+#endif
+
+} // End of namespace Common
Property changes on: tools/trunk/common/hashmap.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Rev Author URL Id
Added: svn:eol-style
+ native
Added: tools/trunk/common/hashmap.h
===================================================================
--- tools/trunk/common/hashmap.h (rev 0)
+++ tools/trunk/common/hashmap.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -0,0 +1,597 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+// The hash map (associative array) implementation in this file is
+// based on the PyDict implementation of CPython.
+
+#ifndef COMMON_HASHMAP_H
+#define COMMON_HASHMAP_H
+
+#include "common/func.h"
+#include "common/str.h"
+#include "common/util.h"
+
+#define USE_HASHMAP_MEMORY_POOL
+#ifdef USE_HASHMAP_MEMORY_POOL
+#include "common/memorypool.h"
+#endif
+
+namespace Common {
+
+// The sgi IRIX MIPSpro Compiler has difficulties with nested templates.
+// This and the other __sgi conditionals below work around these problems.
+#ifdef __sgi
+template<class T> class IteratorImpl;
+#endif
+
+// Enable the following #define if you want to check how many collisions the
+// code produces (many collisions indicate either a bad hash function, or a
+// hash table that is too small).
+//#define DEBUG_HASH_COLLISIONS
+
+
+/**
+ * HashMap<Key,Val> maps objects of type Key to objects of type Val.
+ * For each used Key type, we need an "uint hashit(Key,uint)" function
+ * that computes a hash for the given Key object and returns it as an
+ * an integer from 0 to hashsize-1, and also an "equality functor".
+ * that returns true if if its two arguments are to be considered
+ * equal. Also, we assume that "=" works on Val objects for assignment.
+ *
+ * If aa is an HashMap<Key,Val>, then space is allocated each time aa[key] is
+ * referenced, for a new key. If the object is const, then an assertion is
+ * triggered instead. Hence if you are not sure whether a key is contained in
+ * the map, use contains() first to check for its presence.
+ */
+template<class Key, class Val, class HashFunc = Hash<Key>, class EqualFunc = EqualTo<Key> >
+class HashMap {
+private:
+#if defined (PALMOS_MODE)
+public:
+#endif
+
+ typedef HashMap<Key, Val, HashFunc, EqualFunc> HM_t;
+
+ struct Node {
+ const Key _key;
+ Val _value;
+ explicit Node(const Key &key) : _key(key), _value() {}
+ Node() : _key(), _value() {}
+ };
+
+ enum {
+ HASHMAP_PERTURB_SHIFT = 5,
+ HASHMAP_MIN_CAPACITY = 16,
+
+ // The quotient of the next two constants controls how much the
+ // internal storage of the hashmap may fill up before being
+ // increased automatically.
+ // Note: the quotient of these two must be between and different
+ // from 0 and 1.
+ HASHMAP_LOADFACTOR_NUMERATOR = 2,
+ HASHMAP_LOADFACTOR_DENOMINATOR = 3,
+
+ HASHMAP_MEMORYPOOL_SIZE = HASHMAP_MIN_CAPACITY * HASHMAP_LOADFACTOR_NUMERATOR / HASHMAP_LOADFACTOR_DENOMINATOR
+ };
+
+
+ ObjectPool<Node, HASHMAP_MEMORYPOOL_SIZE> _nodePool;
+
+ Node **_storage; ///< hashtable of size arrsize.
+ uint _mask; ///< Capacity of the HashMap minus one; must be a power of two of minus one
+ uint _size;
+ uint _deleted; ///< Number of deleted elements (_dummyNodes)
+
+ HashFunc _hash;
+ EqualFunc _equal;
+
+ /** Default value, returned by the const getVal. */
+ const Val _defaultVal;
+
+ /** Dummy node, used as marker for erased objects. */
+ #define HASHMAP_DUMMY_NODE ((Node *)1)
+
+#ifdef DEBUG_HASH_COLLISIONS
+ mutable int _collisions, _lookups, _dummyHits;
+#endif
+
+ Node *allocNode(const Key &key) {
+ return new (_nodePool) Node(key);
+ }
+
+ void freeNode(Node *node) {
+ if (node && node != HASHMAP_DUMMY_NODE)
+ _nodePool.deleteChunk(node);
+ }
+
+ void assign(const HM_t &map);
+ int lookup(const Key &key) const;
+ int lookupAndCreateIfMissing(const Key &key);
+ void expandStorage(uint newCapacity);
+
+#ifndef __sgi
+ template<class T> friend class IteratorImpl;
+#endif
+
+ /**
+ * Simple HashMap iterator implementation.
+ */
+ template<class NodeType>
+ class IteratorImpl {
+ friend class HashMap;
+#ifdef __sgi
+ template<class T> friend class Common::IteratorImpl;
+#else
+ template<class T> friend class IteratorImpl;
+#endif
+ protected:
+ typedef const HashMap hashmap_t;
+
+ uint _idx;
+ hashmap_t *_hashmap;
+
+ protected:
+ IteratorImpl(uint idx, hashmap_t *hashmap) : _idx(idx), _hashmap(hashmap) {}
+
+ NodeType *deref() const {
+ assert(_hashmap != 0);
+ assert(_idx <= _hashmap->_mask);
+ Node *node = _hashmap->_storage[_idx];
+ assert(node != 0);
+ assert(node != HASHMAP_DUMMY_NODE);
+ return node;
+ }
+
+ public:
+ IteratorImpl() : _idx(0), _hashmap(0) {}
+ template<class T>
+ IteratorImpl(const IteratorImpl<T> &c) : _idx(c._idx), _hashmap(c._hashmap) {}
+
+ NodeType &operator*() const { return *deref(); }
+ NodeType *operator->() const { return deref(); }
+
+ bool operator==(const IteratorImpl &iter) const { return _idx == iter._idx && _hashmap == iter._hashmap; }
+ bool operator!=(const IteratorImpl &iter) const { return !(*this == iter); }
+
+ IteratorImpl &operator++() {
+ assert(_hashmap);
+ do {
+ _idx++;
+ } while (_idx <= _hashmap->_mask && (_hashmap->_storage[_idx] == 0 || _hashmap->_storage[_idx] == HASHMAP_DUMMY_NODE));
+ if (_idx > _hashmap->_mask)
+ _idx = (uint)-1;
+
+ return *this;
+ }
+
+ IteratorImpl operator++(int) {
+ IteratorImpl old = *this;
+ operator ++();
+ return old;
+ }
+ };
+
+public:
+ typedef IteratorImpl<Node> iterator;
+ typedef IteratorImpl<const Node> const_iterator;
+
+ HashMap();
+ HashMap(const HM_t &map);
+ ~HashMap();
+
+ HM_t &operator=(const HM_t &map) {
+ if (this == &map)
+ return *this;
+
+ // Remove the previous content and ...
+ clear();
+ delete[] _storage;
+ // ... copy the new stuff.
+ assign(map);
+ return *this;
+ }
+
+ bool contains(const Key &key) const;
+
+ Val &operator[](const Key &key);
+ const Val &operator[](const Key &key) const;
+
+ Val &getVal(const Key &key);
+ const Val &getVal(const Key &key) const;
+ const Val &getVal(const Key &key, const Val &defaultVal) const;
+ void setVal(const Key &key, const Val &val);
+
+ void clear(bool shrinkArray = 0);
+
+ void erase(const Key &key);
+
+ uint size() const { return _size; }
+
+ iterator begin() {
+ // Find and return the first non-empty entry
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
+ return iterator(ctr, this);
+ }
+ return end();
+ }
+ iterator end() {
+ return iterator((uint)-1, this);
+ }
+
+ const_iterator begin() const {
+ // Find and return the first non-empty entry
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (_storage[ctr] && _storage[ctr] != HASHMAP_DUMMY_NODE)
+ return const_iterator(ctr, this);
+ }
+ return end();
+ }
+ const_iterator end() const {
+ return const_iterator((uint)-1, this);
+ }
+
+ iterator find(const Key &key) {
+ uint ctr = lookup(key);
+ if (_storage[ctr])
+ return iterator(ctr, this);
+ return end();
+ }
+
+ const_iterator find(const Key &key) const {
+ uint ctr = lookup(key);
+ if (_storage[ctr])
+ return const_iterator(ctr, this);
+ return end();
+ }
+
+ // TODO: insert() method?
+
+ bool empty() const {
+ return (_size == 0);
+ }
+};
+
+//-------------------------------------------------------
+// HashMap functions
+
+/**
+ * Base constructor, creates an empty hashmap.
+ */
+template<class Key, class Val, class HashFunc, class EqualFunc>
+HashMap<Key, Val, HashFunc, EqualFunc>::HashMap()
+//
+// We have to skip _defaultVal() on PS2 to avoid gcc 3.2.2 ICE
+//
+#ifdef __PLAYSTATION2__
+ {
+#else
+ : _defaultVal() {
+#endif
+ _mask = HASHMAP_MIN_CAPACITY - 1;
+ _storage = new Node *[HASHMAP_MIN_CAPACITY];
+ assert(_storage != NULL);
+ memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *));
+
+ _size = 0;
+ _deleted = 0;
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _collisions = 0;
+ _lookups = 0;
+ _dummyHits = 0;
+#endif
+}
+
+/**
+ * Copy constructor, creates a full copy of the given hashmap.
+ * We must provide a custom copy constructor as we use pointers
+ * to heap buffers for the internal storage.
+ */
+template<class Key, class Val, class HashFunc, class EqualFunc>
+HashMap<Key, Val, HashFunc, EqualFunc>::HashMap(const HM_t &map) :
+ _defaultVal() {
+#ifdef DEBUG_HASH_COLLISIONS
+ _collisions = 0;
+ _lookups = 0;
+ _dummyHits = 0;
+#endif
+ assign(map);
+}
+
+/**
+ * Destructor, frees all used memory.
+ */
+template<class Key, class Val, class HashFunc, class EqualFunc>
+HashMap<Key, Val, HashFunc, EqualFunc>::~HashMap() {
+ for (uint ctr = 0; ctr <= _mask; ++ctr)
+ freeNode(_storage[ctr]);
+
+ delete[] _storage;
+#ifdef DEBUG_HASH_COLLISIONS
+ extern void updateHashCollisionStats(int, int, int, int, int);
+ updateHashCollisionStats(_collisions, _dummyHits, _lookups, _mask+1, _size);
+#endif
+}
+
+/**
+ * Internal method for assigning the content of another HashMap
+ * to this one.
+ *
+ * @note We do *not* deallocate the previous storage here -- the caller is
+ * responsible for doing that!
+ */
+template<class Key, class Val, class HashFunc, class EqualFunc>
+void HashMap<Key, Val, HashFunc, EqualFunc>::assign(const HM_t &map) {
+ _mask = map._mask;
+ _storage = new Node *[_mask+1];
+ assert(_storage != NULL);
+ memset(_storage, 0, (_mask+1) * sizeof(Node *));
+
+ // Simply clone the map given to us, one by one.
+ _size = 0;
+ _deleted = 0;
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ if (map._storage[ctr] == HASHMAP_DUMMY_NODE) {
+ _storage[ctr] = HASHMAP_DUMMY_NODE;
+ _deleted++;
+ } else if (map._storage[ctr] != NULL) {
+ _storage[ctr] = allocNode(map._storage[ctr]->_key);
+ _storage[ctr]->_value = map._storage[ctr]->_value;
+ _size++;
+ }
+ }
+ // Perform a sanity check (to help track down hashmap corruption)
+ assert(_size == map._size);
+ assert(_deleted == map._deleted);
+}
+
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+void HashMap<Key, Val, HashFunc, EqualFunc>::clear(bool shrinkArray) {
+ for (uint ctr = 0; ctr <= _mask; ++ctr) {
+ freeNode(_storage[ctr]);
+ _storage[ctr] = NULL;
+ }
+
+#ifdef USE_HASHMAP_MEMORY_POOL
+ _nodePool.freeUnusedPages();
+#endif
+
+ if (shrinkArray && _mask >= HASHMAP_MIN_CAPACITY) {
+ delete[] _storage;
+
+ _mask = HASHMAP_MIN_CAPACITY;
+ _storage = new Node *[HASHMAP_MIN_CAPACITY];
+ assert(_storage != NULL);
+ memset(_storage, 0, HASHMAP_MIN_CAPACITY * sizeof(Node *));
+ }
+
+ _size = 0;
+ _deleted = 0;
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+void HashMap<Key, Val, HashFunc, EqualFunc>::expandStorage(uint newCapacity) {
+ assert(newCapacity > _mask+1);
+
+#ifndef NDEBUG
+ const uint old_size = _size;
+#endif
+ const uint old_mask = _mask;
+ Node **old_storage = _storage;
+
+ // allocate a new array
+ _size = 0;
+ _deleted = 0;
+ _mask = newCapacity - 1;
+ _storage = new Node *[newCapacity];
+ assert(_storage != NULL);
+ memset(_storage, 0, newCapacity * sizeof(Node *));
+
+ // rehash all the old elements
+ for (uint ctr = 0; ctr <= old_mask; ++ctr) {
+ if (old_storage[ctr] == NULL || old_storage[ctr] == HASHMAP_DUMMY_NODE)
+ continue;
+
+ // Insert the element from the old table into the new table.
+ // Since we know that no key exists twice in the old table, we
+ // can do this slightly better than by calling lookup, since we
+ // don't have to call _equal().
+ const uint hash = _hash(old_storage[ctr]->_key);
+ uint idx = hash & _mask;
+ for (uint perturb = hash; _storage[idx] != NULL && _storage[idx] != HASHMAP_DUMMY_NODE; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ idx = (5 * idx + perturb + 1) & _mask;
+ }
+
+ _storage[idx] = old_storage[ctr];
+ _size++;
+ }
+
+ // Perform a sanity check: Old number of elements should match the new one!
+ // This check will fail if some previous operation corrupted this hashmap.
+ assert(_size == old_size);
+
+ delete[] old_storage;
+
+ return;
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+int HashMap<Key, Val, HashFunc, EqualFunc>::lookup(const Key &key) const {
+ const uint hash = _hash(key);
+ uint ctr = hash & _mask;
+ for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ if (_storage[ctr] == NULL)
+ break;
+ if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
+#ifdef DEBUG_HASH_COLLISIONS
+ _dummyHits++;
+#endif
+ } else if (_equal(_storage[ctr]->_key, key))
+ break;
+
+ ctr = (5 * ctr + perturb + 1) & _mask;
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _collisions++;
+#endif
+ }
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _lookups++;
+ fprintf(stderr, "collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
+ _collisions, _dummyHits, _lookups, ((double) _collisions / (double)_lookups),
+ (const void *)this, _mask+1, _size);
+#endif
+
+ return ctr;
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+int HashMap<Key, Val, HashFunc, EqualFunc>::lookupAndCreateIfMissing(const Key &key) {
+ const uint hash = _hash(key);
+ uint ctr = hash & _mask;
+ const uint NONE_FOUND = _mask + 1;
+ uint first_free = NONE_FOUND;
+ bool found = false;
+ for (uint perturb = hash; ; perturb >>= HASHMAP_PERTURB_SHIFT) {
+ if (_storage[ctr] == NULL)
+ break;
+ if (_storage[ctr] == HASHMAP_DUMMY_NODE) {
+#ifdef DEBUG_HASH_COLLISIONS
+ _dummyHits++;
+#endif
+ if (first_free != _mask + 1)
+ first_free = ctr;
+ } else if (_equal(_storage[ctr]->_key, key)) {
+ found = true;
+ break;
+ }
+
+ ctr = (5 * ctr + perturb + 1) & _mask;
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _collisions++;
+#endif
+ }
+
+#ifdef DEBUG_HASH_COLLISIONS
+ _lookups++;
+ fprintf(stderr, "collisions %d, dummies hit %d, lookups %d, ratio %f in HashMap %p; size %d num elements %d\n",
+ _collisions, _dummyHits, _lookups, ((double) _collisions / (double)_lookups),
+ (const void *)this, _mask+1, _size);
+#endif
+
+ if (!found && first_free != _mask + 1)
+ ctr = first_free;
+
+ if (!found) {
+ if (_storage[ctr])
+ _deleted--;
+ _storage[ctr] = allocNode(key);
+ assert(_storage[ctr] != NULL);
+ _size++;
+
+ // Keep the load factor below a certain threshold.
+ // Deleted nodes are also counted
+ uint capacity = _mask + 1;
+ if ((_size + _deleted) * HASHMAP_LOADFACTOR_DENOMINATOR >
+ capacity * HASHMAP_LOADFACTOR_NUMERATOR) {
+ capacity = capacity < 500 ? (capacity * 4) : (capacity * 2);
+ expandStorage(capacity);
+ ctr = lookup(key);
+ assert(_storage[ctr] != NULL);
+ }
+ }
+
+ return ctr;
+}
+
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+bool HashMap<Key, Val, HashFunc, EqualFunc>::contains(const Key &key) const {
+ uint ctr = lookup(key);
+ return (_storage[ctr] != NULL);
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) {
+ return getVal(key);
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+const Val &HashMap<Key, Val, HashFunc, EqualFunc>::operator[](const Key &key) const {
+ return getVal(key);
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) {
+ uint ctr = lookupAndCreateIfMissing(key);
+ assert(_storage[ctr] != NULL);
+ return _storage[ctr]->_value;
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key) const {
+ return getVal(key, _defaultVal);
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+const Val &HashMap<Key, Val, HashFunc, EqualFunc>::getVal(const Key &key, const Val &defaultVal) const {
+ uint ctr = lookup(key);
+ if (_storage[ctr] != NULL)
+ return _storage[ctr]->_value;
+ else
+ return defaultVal;
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+void HashMap<Key, Val, HashFunc, EqualFunc>::setVal(const Key &key, const Val &val) {
+ uint ctr = lookupAndCreateIfMissing(key);
+ assert(_storage[ctr] != NULL);
+ _storage[ctr]->_value = val;
+}
+
+template<class Key, class Val, class HashFunc, class EqualFunc>
+void HashMap<Key, Val, HashFunc, EqualFunc>::erase(const Key &key) {
+
+ uint ctr = lookup(key);
+ if (_storage[ctr] == NULL)
+ return;
+
+ // If we remove a key, we replace it with a dummy node.
+ freeNode(_storage[ctr]);
+ _storage[ctr] = HASHMAP_DUMMY_NODE;
+ _size--;
+ _deleted++;
+ return;
+}
+
+#undef HASHMAP_DUMMY_NODE
+
+} // End of namespace Common
+
+#endif
Property changes on: tools/trunk/common/hashmap.h
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Rev Author URL Id
Added: svn:eol-style
+ native
Added: tools/trunk/common/memorypool.cpp
===================================================================
--- tools/trunk/common/memorypool.cpp (rev 0)
+++ tools/trunk/common/memorypool.cpp 2010-01-18 15:40:49 UTC (rev 47355)
@@ -0,0 +1,183 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/memorypool.h"
+#include "common/util.h"
+
+namespace Common {
+
+enum {
+ INITIAL_CHUNKS_PER_PAGE = 8
+};
+
+static size_t adjustChunkSize(size_t chunkSize) {
+ // You must at least fit the pointer in the node (technically unneeded considering the next rounding statement)
+ chunkSize = MAX(chunkSize, sizeof(void*));
+ // There might be an alignment problem on some platforms when trying to load a void* on a non natural boundary
+ // so we round to the next sizeof(void*)
+ chunkSize = (chunkSize + sizeof(void*) - 1) & (~(sizeof(void*) - 1));
+
+ return chunkSize;
+}
+
+
+MemoryPool::MemoryPool(size_t chunkSize)
+ : _chunkSize(adjustChunkSize(chunkSize)) {
+
+ _next = NULL;
+
+ _chunksPerPage = INITIAL_CHUNKS_PER_PAGE;
+}
+
+MemoryPool::~MemoryPool() {
+#if 0
+ freeUnusedPages();
+ if (!_pages.empty())
+ warning("Memory leak found in pool");
+#endif
+
+ for (size_t i = 0; i < _pages.size(); ++i)
+ ::free(_pages[i].start);
+}
+
+void MemoryPool::allocPage() {
+ Page page;
+
+ // Allocate a new page
+ page.numChunks = _chunksPerPage;
+ assert(page.numChunks * _chunkSize < 16*1024*1024); // Refuse to allocate pages bigger than 16 MB
+
+ page.start = ::malloc(page.numChunks * _chunkSize);
+ assert(page.start);
+ _pages.push_back(page);
+
+
+ // Next time, we'll allocate a page twice as big as this one.
+ _chunksPerPage *= 2;
+
+ // Add the page to the pool of free chunk
+ addPageToPool(page);
+}
+
+void MemoryPool::addPageToPool(const Page &page) {
+
+ // Add all chunks of the new page to the linked list (pool) of free chunks
+ void *current = page.start;
+ for (size_t i = 1; i < page.numChunks; ++i) {
+ void *next = ((char*)current + _chunkSize);
+ *(void **)current = next;
+
+ current = next;
+ }
+
+ // Last chunk points to the old _next
+ *(void**)current = _next;
+
+ // From now on, the first free chunk is the first chunk of the new page
+ _next = page.start;
+}
+
+void *MemoryPool::allocChunk() {
+ if (!_next) // No free chunks left? Allocate a new page
+ allocPage();
+
+ assert(_next);
+ void *result = _next;
+ _next = *(void**)result;
+ return result;
+}
+
+void MemoryPool::freeChunk(void *ptr) {
+ // Add the chunk back to (the start of) the list of free chunks
+ *(void**)ptr = _next;
+ _next = ptr;
+}
+
+// Technically not compliant C++ to compare unrelated pointers. In practice...
+bool MemoryPool::isPointerInPage(void *ptr, const Page &page) {
+ return (ptr >= page.start) && (ptr < (char*)page.start + page.numChunks * _chunkSize);
+}
+
+void MemoryPool::freeUnusedPages() {
+ //std::sort(_pages.begin(), _pages.end());
+ Array<size_t> numberOfFreeChunksPerPage;
+ numberOfFreeChunksPerPage.resize(_pages.size());
+ for (size_t i = 0; i < numberOfFreeChunksPerPage.size(); ++i) {
+ numberOfFreeChunksPerPage[i] = 0;
+ }
+
+ // Compute for each page how many chunks in it are still in use.
+ void *iterator = _next;
+ while (iterator) {
+ // TODO: This should be a binary search (requiring us to keep _pages sorted)
+ for (size_t i = 0; i < _pages.size(); ++i) {
+ if (isPointerInPage(iterator, _pages[i])) {
+ ++numberOfFreeChunksPerPage[i];
+ break;
+ }
+ }
+ iterator = *(void**)iterator;
+ }
+
+ // Free all pages which are not in use.
+ size_t freedPagesCount = 0;
+ for (size_t i = 0; i < _pages.size(); ++i) {
+ if (numberOfFreeChunksPerPage[i] == _pages[i].numChunks) {
+ // Remove all chunks of this page from the list of free chunks
+ void **iter2 = &_next;
+ while (*iter2) {
+ if (isPointerInPage(*iter2, _pages[i]))
+ *iter2 = **(void***)iter2;
+ else
+ iter2 = *(void***)iter2;
+ }
+ ::free(_pages[i].start);
+ ++freedPagesCount;
+ _pages[i].start = NULL;
+ }
+ }
+
+// printf("freed %d pages out of %d\n", (int)freedPagesCount, (int)_pages.size());
+
+ // Remove all now unused pages
+ size_t newSize = 0;
+ for (size_t i = 0; i < _pages.size(); ++i) {
+ if (_pages[i].start != NULL) {
+ if (newSize != i)
+ _pages[newSize] = _pages[i];
+ ++newSize;
+ }
+ }
+ _pages.resize(newSize);
+
+ // Reset _chunksPerPage
+ _chunksPerPage = INITIAL_CHUNKS_PER_PAGE;
+ for (size_t i = 0; i < _pages.size(); ++i) {
+ if (_chunksPerPage < _pages[i].numChunks)
+ _chunksPerPage = _pages[i].numChunks;
+ }
+}
+
+} // End of namespace Common
Property changes on: tools/trunk/common/memorypool.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Rev Author URL Id
Added: svn:eol-style
+ native
Added: tools/trunk/common/memorypool.h
===================================================================
--- tools/trunk/common/memorypool.h (rev 0)
+++ tools/trunk/common/memorypool.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -0,0 +1,166 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef COMMON_MEMORYPOOL_H
+#define COMMON_MEMORYPOOL_H
+
+#include "common/scummsys.h"
+#include "common/array.h"
+
+
+namespace Common {
+
+/**
+ * This class provides a pool of memory 'chunks' of identical size.
+ * The size of a chunk is determined when creating the memory pool.
+ *
+ * Using a memory pool may yield better performance and memory usage
+ * when allocating and deallocating many memory blocks of equal size.
+ * E.g. the Common::String class uses a memory pool for the refCount
+ * variables (each the size of an int) it allocates for each string
+ * instance.
+ */
+class MemoryPool {
+protected:
+ MemoryPool(const MemoryPool&);
+ MemoryPool& operator=(const MemoryPool&);
+
+ struct Page {
+ void *start;
+ size_t numChunks;
+ };
+
+ const size_t _chunkSize;
+ Array<Page> _pages;
+ void *_next;
+ size_t _chunksPerPage;
+
+ void allocPage();
+ void addPageToPool(const Page &page);
+ bool isPointerInPage(void *ptr, const Page &page);
+
+public:
+ /**
+ * Constructor for a memory pool with the given chunk size.
+ * @param chunkSize the chunk size of this memory pool
+ */
+ MemoryPool(size_t chunkSize);
+ ~MemoryPool();
+
+ /**
+ * Allocate a new chunk from the memory pool.
+ */
+ void *allocChunk();
+ /**
+ * Return a chunk to the memory pool. The given pointer must have
+ * been obtained from calling the allocChunk() method of the very
+ * same MemoryPool instance. Passing any other pointer (e.g. to
+ * a chunk from another MemoryPool, or a malloc'ed memory block)
+ * will lead to undefined behavior and may result in a crash (if
+ * you are lucky) or in silent data corruption.
+ */
+ void freeChunk(void *ptr);
+
+ /**
+ * Perform garbage collection. The memory pool stores all the
+ * chunks it manages in memory 'pages' obtained via the classic
+ * memory allocation APIs (i.e. malloc/free). Ordinarily, once
+ * a page has been allocated, it won't be released again during
+ * the life time of the memory pool. The exception is when this
+ * method is called.
+ */
+ void freeUnusedPages();
+
+ /**
+ * Return the chunk size used by this memory pool.
+ */
+ size_t getChunkSize() const { return _chunkSize; }
+};
+
+/**
+ * This is a memory pool which already contains in itself some storage
+ * space for a fixed number of chunks. Thus if the memory pool is only
+ * lightly used, no malloc() calls have to be made at all.
+ */
+template<size_t CHUNK_SIZE, size_t NUM_INTERNAL_CHUNKS = 32>
+class FixedSizeMemoryPool : public MemoryPool {
+private:
+ enum {
+ REAL_CHUNK_SIZE = (CHUNK_SIZE + sizeof(void*) - 1) & (~(sizeof(void*) - 1))
+ };
+
+ byte _storage[NUM_INTERNAL_CHUNKS * REAL_CHUNK_SIZE];
+public:
+ FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {
+ assert(REAL_CHUNK_SIZE == _chunkSize);
+ // Insert some static storage
+ Page internalPage = { _storage, NUM_INTERNAL_CHUNKS };
+ addPageToPool(internalPage);
+ }
+};
+
+// Ensure NUM_INTERNAL_CHUNKS == 0 results in a compile error
+template<size_t CHUNK_SIZE>
+class FixedSizeMemoryPool<CHUNK_SIZE,0> : public MemoryPool {
+public:
+ FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {}
+};
+
+/**
+ * A memory pool for C++ objects.
+ */
+template<class T, size_t NUM_INTERNAL_CHUNKS = 32>
+class ObjectPool : public FixedSizeMemoryPool<sizeof(T), NUM_INTERNAL_CHUNKS> {
+public:
+ /**
+ * Return the memory chunk used as storage for the given object back
+ * to the pool, after calling its destructor.
+ */
+ void deleteChunk(T *ptr) {
+ ptr->~T();
+ this->freeChunk(ptr);
+ }
+};
+
+} // End of namespace Common
+
+/**
+ * A custom placement new operator, using an arbitrary MemoryPool.
+ *
+ * This *should* work with all C++ implementations, but may not.
+ *
+ * For details on using placement new for custom allocators, see e.g.
+ * <http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14>
+ */
+inline void* operator new(size_t nbytes, Common::MemoryPool& pool) {
+ assert(nbytes <= pool.getChunkSize());
+ return pool.allocChunk();
+}
+
+inline void operator delete(void* p, Common::MemoryPool& pool) {
+ pool.freeChunk(p);
+}
+
+#endif
Property changes on: tools/trunk/common/memorypool.h
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Rev Author URL Id
Added: svn:eol-style
+ native
Modified: tools/trunk/common/scummsys.h
===================================================================
--- tools/trunk/common/scummsys.h 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/common/scummsys.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -97,8 +97,10 @@
*/
#if defined(__GNUC__)
#define GCC_PACK __attribute__((packed))
+ #define GCC_PRINTF(x,y) __attribute__((format(printf, x, y)))
#else
#define GCC_PACK
+ #define GCC_PRINTF(x,y)
#endif
#ifndef ARRAYSIZE
Modified: tools/trunk/engines/mohawk/mohawk_file.cpp
===================================================================
--- tools/trunk/engines/mohawk/mohawk_file.cpp 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/engines/mohawk/mohawk_file.cpp 2010-01-18 15:40:49 UTC (rev 47355)
@@ -28,6 +28,21 @@
| (uint16)((high >> 8) | (high << 8));
}
+Common::String MohawkFile::tag2string(uint32 tag) {
+ char str[5];
+ str[0] = (char)(tag >> 24);
+ str[1] = (char)(tag >> 16);
+ str[2] = (char)(tag >> 8);
+ str[3] = (char)tag;
+ str[4] = '\0';
+ // Replace non-printable chars by dot
+ for (int i = 0; i < 4; ++i) {
+ if (!isprint(str[i]))
+ str[i] = '.';
+ }
+ return Common::String(str);
+}
+
MohawkFile::MohawkFile() {
_mhk = NULL;
_curFile = Common::String::emptyString;
Modified: tools/trunk/engines/mohawk/mohawk_file.h
===================================================================
--- tools/trunk/engines/mohawk/mohawk_file.h 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/engines/mohawk/mohawk_file.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -23,7 +23,7 @@
#ifndef MOHAWK_FILE_H
#define MOHAWK_FILE_H
-#include "utils/str.h"
+#include "common/str.h"
#include "utils/stream.h"
// Main FourCC's
@@ -116,6 +116,8 @@
#define ID_BBOX MKID_BE('BBOX') // Boxes? (CSWorld, CSAmtrak)
#define ID_SYSX MKID_BE('SYSX') // MIDI Sysex
+#define tag2str(x) MohawkFile::tag2string(x).c_str()
+
struct MohawkOutputStream {
Common::SeekableSubReadStream *stream;
uint32 tag;
@@ -183,6 +185,8 @@
virtual MohawkOutputStream getRawData(uint32 tag, uint16 id);
virtual MohawkOutputStream getNextFile();
+ static Common::String tag2string(uint32 tag);
+
protected:
Common::SeekableReadStream *_mhk;
TypeTable _typeTable;
Modified: tools/trunk/engines/mohawk/util.h
===================================================================
--- tools/trunk/engines/mohawk/util.h 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/engines/mohawk/util.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -23,11 +23,8 @@
#ifndef UTIL_H
#define UTIL_H
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "common/scummsys.h"
+
#include <sys/stat.h>
#if !defined(_MSC_VER)
@@ -39,24 +36,6 @@
#include <process.h>
#endif
-
-/*
- * Some useful types
- */
-
-typedef unsigned char byte;
-typedef unsigned char uint8;
-typedef unsigned short uint16;
-typedef signed char int8;
-typedef signed short int16;
-#ifdef __amigaos4__
-#include <exec/types.h>
-#include <stdlib.h>
-#else
-typedef unsigned int uint32;
-typedef signed int int32;
-#endif
-
typedef uint32 uint;
/*
@@ -102,16 +81,12 @@
* GCC specific stuff
*/
#if defined(__GNUC__)
- #define GCC_PACK __attribute__((packed))
- #define NORETURN __attribute__((__noreturn__))
- #define GCC_PRINTF(x,y) __attribute__((format(printf, x, y)))
+ #define GCC_PACK __attribute__((packed))
+ #define NORETURN __attribute__((__noreturn__))
#else
- #define GCC_PACK
- #define GCC_PRINTF(x,y)
+ #define GCC_PACK
#endif
-#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
-
#if defined(INVERSE_MKID)
#define MKID_BE(a) ((uint32) \
(((a) >> 24) & 0x000000FF) | \
Deleted: tools/trunk/engines/mohawk/utils/str.cpp
===================================================================
--- tools/trunk/engines/mohawk/utils/str.cpp 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/engines/mohawk/utils/str.cpp 2010-01-18 15:40:49 UTC (rev 47355)
@@ -1,621 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- */
-
-#include "str.h"
-#include "util.h"
-
-//#include "engines/mohawk/utils/str.h"
-//#include "engines/mohawk/utils/util.h"
-
-#if !defined(__SYMBIAN32__)
-#include <new>
-#endif
-
-
-namespace Common {
-
-#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
-const String String::emptyString;
-#else
-const char *String::emptyString = "";
-#endif
-
-static uint32 computeCapacity(uint32 len) {
- // By default, for the capacity we use the next multiple of 32
- return ((len + 32 - 1) & ~0x1F);
-}
-
-String::String(const char *str) : _size(0), _str(_storage) {
- if (str == 0) {
- _storage[0] = 0;
- _size = 0;
- } else
- initWithCStr(str, strlen(str));
-}
-
-String::String(const char *str, uint32 len) : _size(0), _str(_storage) {
- initWithCStr(str, len);
-}
-
-String::String(const char *beginP, const char *endP) : _size(0), _str(_storage) {
- assert(endP >= beginP);
- initWithCStr(beginP, endP - beginP);
-}
-
-void String::initWithCStr(const char *str, uint32 len) {
- assert(str);
-
- // Init _storage member explicitly (ie. without calling its constructor)
- // for GCC 2.95.x compatibility (see also tracker item #1602879).
- _storage[0] = 0;
-
- _size = len;
-
- if (len >= _builtinCapacity) {
- // Not enough internal storage, so allocate more
- _extern._capacity = computeCapacity(len+1);
- _str = (char *)malloc(_extern._capacity);
- assert(_str != 0);
- }
-
- // Copy the string into the storage area
- memmove(_str, str, len);
- _str[len] = 0;
-}
-
-String::String(const String &str)
- : _size(str._size) {
- if (str.isStorageIntern()) {
- // String in internal storage: just copy it
- memcpy(_storage, str._storage, _builtinCapacity);
- _str = _storage;
- } else {
- // String in external storage
- _extern._capacity = str._extern._capacity;
- _str = str._str;
- }
- assert(_str != 0);
-}
-
-String::String(char c)
-: _size(0), _str(_storage) {
-
- _storage[0] = c;
- _storage[1] = 0;
-
- // TODO/FIXME: There is no reason for the following check -- we *do*
- // allow strings to contain 0 bytes!
- _size = (c == 0) ? 0 : 1;
-}
-
-String::~String() {
-}
-
-void String::makeUnique() {
- ensureCapacity(_size, true);
-}
-
-/**
- * Ensure that enough storage is available to store at least new_size
- * characters plus a null byte. In addition, if we currently share
- * the storage with another string, unshare it, so that we can safely
- * write to the storage.
- */
-void String::ensureCapacity(uint32 new_size, bool keep_old) {
- bool isShared = false;
- uint32 curCapacity, newCapacity;
- char *newStorage;
-
- if (isStorageIntern()) {
- isShared = false;
- curCapacity = _builtinCapacity;
- } else {
- curCapacity = _extern._capacity;
- }
-
- // Special case: If there is enough space, and we do not share
- // the storage, then there is nothing to do.
- if (!isShared && new_size < curCapacity)
- return;
-
- if (isShared && new_size < _builtinCapacity) {
- // We share the storage, but there is enough internal storage: Use that.
- newStorage = _storage;
- newCapacity = _builtinCapacity;
- } else {
- // We need to allocate storage on the heap!
-
- // Compute a suitable new capacity limit
- newCapacity = MAX(curCapacity * 2, computeCapacity(new_size+1));
-
- // Allocate new storage
- newStorage = (char *)malloc(newCapacity);
- assert(newStorage);
- }
-
- // Copy old data if needed, elsewise reset the new storage.
- if (keep_old) {
- assert(_size < newCapacity);
- memcpy(newStorage, _str, _size + 1);
- } else {
- _size = 0;
- newStorage[0] = 0;
- }
-
- // ... in favor of the new storage
- _str = newStorage;
-
- if (!isStorageIntern()) {
- // Set the ref count & capacity if we use an external storage.
- // It is important to do this *after* copying any old content,
- // else we would override data that has not yet been copied!
- _extern._capacity = newCapacity;
- }
-}
-
-String& String::operator =(const char *str) {
- uint32 len = strlen(str);
- ensureCapacity(len, false);
- _size = len;
- memmove(_str, str, len + 1);
- return *this;
-}
-
-String &String::operator =(const String &str) {
- if (&str == this)
- return *this;
-
- if (str.isStorageIntern()) {
- _size = str._size;
- _str = _storage;
- memcpy(_str, str._str, _size + 1);
- } else {
- _extern._capacity = str._extern._capacity;
- _size = str._size;
- _str = str._str;
- }
-
- return *this;
-}
-
-String& String::operator =(char c) {
- _str = _storage;
- _size = 1;
- _str[0] = c;
- _str[1] = 0;
- return *this;
-}
-
-String &String::operator +=(const char *str) {
- int len = strlen(str);
- if (len > 0) {
- ensureCapacity(_size + len, true);
-
- memcpy(_str + _size, str, len + 1);
- _size += len;
- }
- return *this;
-}
-
-String &String::operator +=(const String &str) {
- int len = str._size;
- if (len > 0) {
- ensureCapacity(_size + len, true);
-
- memcpy(_str + _size, str._str, len + 1);
- _size += len;
- }
- return *this;
-}
-
-String &String::operator +=(char c) {
- ensureCapacity(_size + 1, true);
-
- _str[_size++] = c;
- _str[_size] = 0;
-
- return *this;
-}
-
-bool String::hasPrefix(const char *x) const {
- assert(x != 0);
- // Compare x with the start of _str.
- const char *y = c_str();
- while (*x && *x == *y) {
- ++x;
- ++y;
- }
- // It's a prefix, if and only if all letters in x are 'used up' before
- // _str ends.
- return *x == 0;
-}
-
-bool String::hasSuffix(const char *x) const {
- assert(x != 0);
- // Compare x with the end of _str.
- const uint32 x_size = strlen(x);
- if (x_size > _size)
- return false;
- const char *y = c_str() + _size - x_size;
- while (*x && *x == *y) {
- ++x;
- ++y;
- }
- // It's a suffix, if and only if all letters in x are 'used up' before
- // _str ends.
- return *x == 0;
-}
-
-bool String::contains(const char *x) const {
- assert(x != 0);
- return strstr(c_str(), x) != NULL;
-}
-
-bool String::contains(char x) const {
- return strchr(c_str(), x) != NULL;
-}
-
-bool String::matchString(const char *pat, bool pathMode) const {
- return Common::matchString(c_str(), pat, pathMode);
-}
-
-bool String::matchString(const String &pat, bool pathMode) const {
- return Common::matchString(c_str(), pat.c_str(), pathMode);
-}
-
-void String::deleteLastChar() {
- if (_size > 0)
- deleteChar(_size - 1);
-}
-
-void String::deleteChar(uint32 p) {
- assert(p < _size);
-
- makeUnique();
- while (p++ < _size)
- _str[p-1] = _str[p];
- _size--;
-}
-
-void String::clear() {
- _size = 0;
- _str = _storage;
- _storage[0] = 0;
-}
-
-void String::setChar(char c, uint32 p) {
- assert(p <= _size);
-
- makeUnique();
- _str[p] = c;
-}
-
-void String::insertChar(char c, uint32 p) {
- assert(p <= _size);
-
- ensureCapacity(_size + 1, true);
- _size++;
- for (uint32 i = _size; i > p; --i)
- _str[i] = _str[i-1];
- _str[p] = c;
-}
-
-void String::toLowercase() {
- makeUnique();
- for (uint32 i = 0; i < _size; ++i)
- _str[i] = tolower(_str[i]);
-}
-
-void String::toUppercase() {
- makeUnique();
- for (uint32 i = 0; i < _size; ++i)
- _str[i] = toupper(_str[i]);
-}
-
-void String::trim() {
- if (_size == 0)
- return;
-
- makeUnique();
-
- // Trim trailing whitespace
- while (_size >= 1 && isspace(_str[_size-1]))
- _size--;
- _str[_size] = 0;
-
- // Trim leading whitespace
- char *t = _str;
- while (isspace(*t))
- t++;
-
- if (t != _str) {
- _size -= t - _str;
- memmove(_str, t, _size + 1);
- }
-}
-
-#pragma mark -
-
-bool String::operator ==(const String &x) const {
- return equals(x);
-}
-
-bool String::operator ==(const char *x) const {
- assert(x != 0);
- return equals(x);
-}
-
-bool String::operator !=(const String &x) const {
- return !equals(x);
-}
-
-bool String::operator !=(const char *x) const {
- assert(x != 0);
- return !equals(x);
-}
-
-bool String::operator < (const String &x) const {
- return compareTo(x) < 0;
-}
-
-bool String::operator <= (const String &x) const {
- return compareTo(x) <= 0;
-}
-
-bool String::operator > (const String &x) const {
- return compareTo(x) > 0;
-}
-
-bool String::operator >= (const String &x) const {
- return compareTo(x) >= 0;
-}
-
-#pragma mark -
-
-bool operator == (const char* y, const String &x) {
- return (x == y);
-}
-
-bool operator != (const char* y, const String &x) {
- return x != y;
-}
-
-#pragma mark -
-
-bool String::equals(const String &x) const {
- return (0 == compareTo(x));
-}
-
-bool String::equals(const char *x) const {
- assert(x != 0);
- return (0 == compareTo(x));
-}
-
-bool String::equalsIgnoreCase(const String &x) const {
- return (0 == compareToIgnoreCase(x));
-}
-
-bool String::equalsIgnoreCase(const char *x) const {
- assert(x != 0);
- return (0 == compareToIgnoreCase(x));
-}
-
-int String::compareTo(const String &x) const {
- return compareTo(x.c_str());
-}
-
-int String::compareTo(const char *x) const {
- assert(x != 0);
- return strcmp(c_str(), x);
-}
-
-int String::compareToIgnoreCase(const String &x) const {
- return compareToIgnoreCase(x.c_str());
-}
-
-int String::compareToIgnoreCase(const char *x) const {
- assert(x != 0);
- return scumm_stricmp(c_str(), x);
-}
-
-#pragma mark -
-
-String operator +(const String &x, const String &y) {
- String temp(x);
- temp += y;
- return temp;
-}
-
-String operator +(const char *x, const String &y) {
- String temp(x);
- temp += y;
- return temp;
-}
-
-String operator +(const String &x, const char *y) {
- String temp(x);
- temp += y;
- return temp;
-}
-
-String operator +(char x, const String &y) {
- String temp(x);
- temp += y;
- return temp;
-}
-
-String operator +(const String &x, char y) {
- String temp(x);
- temp += y;
- return temp;
-}
-
-char *ltrim(char *t) {
- while (isspace(*t))
- t++;
- return t;
-}
-
-char *rtrim(char *t) {
- int l = strlen(t) - 1;
- while (l >= 0 && isspace(t[l]))
- t[l--] = 0;
- return t;
-}
-
-char *trim(char *t) {
- return rtrim(ltrim(t));
-}
-
-Common::String lastPathComponent(const Common::String &path, const char sep) {
- const char *str = path.c_str();
- const char *last = str + path.size();
-
- // Skip over trailing slashes
- while (last > str && *(last-1) == sep)
- --last;
-
- // Path consisted of only slashes -> return empty string
- if (last == str)
- return Common::String();
-
- // Now scan the whole component
- const char *first = last - 1;
- while (first >= str && *first != sep)
- --first;
-
- if (*first == sep)
- first++;
-
- return Common::String(first, last);
-}
-
-Common::String normalizePath(const Common::String &path, const char sep) {
- if (path.empty())
- return path;
-
- const char *cur = path.c_str();
- Common::String result;
-
- // If there is a leading slash, preserve that:
- if (*cur == sep) {
- result += sep;
- while (*cur == sep)
- ++cur;
- }
-
- // Scan till the end of the String
- while (*cur != 0) {
- const char *start = cur;
-
- // Scan till the next path separator resp. the end of the string
- while (*cur != sep && *cur != 0)
- cur++;
-
- const Common::String component(start, cur);
-
- // Skip empty components and dot components, add all others
- if (!component.empty() && component != ".") {
- // Add a separator before the component, unless the result
- // string already ends with one (which happens only if the
- // path *starts* with a separator).
- if (!result.empty() && result.lastChar() != sep)
- result += sep;
-
- // Add the component
- result += component;
- }
-
- // Skip over separator chars
- while (*cur == sep)
- cur++;
- }
-
- return result;
-}
-
-bool matchString(const char *str, const char *pat, bool pathMode) {
- assert(str);
- assert(pat);
-
- const char *p = 0;
- const char *q = 0;
-
- for (;;) {
- if (pathMode && *str == '/') {
- p = 0;
- q = 0;
- if (*pat == '?')
- return false;
- }
-
- switch (*pat) {
- case '*':
- // Record pattern / string possition for backtracking
- p = ++pat;
- q = str;
- // If pattern ended with * -> match
- if (!*pat)
- return true;
- break;
-
- default:
- if (*pat != *str) {
- if (p) {
- // No match, oops -> try to backtrack
- pat = p;
- str = ++q;
- if (!*str)
- return !*pat;
- break;
- }
- else
- return false;
- }
- // fallthrough
- case '?':
- if (!*str)
- return !*pat;
- pat++;
- str++;
- }
- }
-}
-
-String tag2string(uint32 tag) {
- char str[5];
- str[0] = (char)(tag >> 24);
- str[1] = (char)(tag >> 16);
- str[2] = (char)(tag >> 8);
- str[3] = (char)tag;
- str[4] = '\0';
- // Replace non-printable chars by dot
- for (int i = 0; i < 4; ++i) {
- if (!isprint(str[i]))
- str[i] = '.';
- }
- return Common::String(str);
-}
-
-} // End of namespace Common
Deleted: tools/trunk/engines/mohawk/utils/str.h
===================================================================
--- tools/trunk/engines/mohawk/utils/str.h 2010-01-18 07:21:54 UTC (rev 47354)
+++ tools/trunk/engines/mohawk/utils/str.h 2010-01-18 15:40:49 UTC (rev 47355)
@@ -1,332 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- */
-
-#ifndef COMMON_STRING_H
-#define COMMON_STRING_H
-
-#include "common/array.h"
-
-namespace Common {
-
-/**
- * Simple string class for ScummVM. Provides automatic storage managment,
- * and overloads several operators in a 'natural' fashion, mimicking
- * the std::string class. Even provides simple iterators.
- *
- * This class tries to avoid allocating lots of small blocks on the heap,
- * since that is inefficient on several platforms supported by ScummVM.
- * Instead, small strings are stored 'inside' the string object (i.e. on
- * the stack, for stack allocated objects), and only for strings exceeding
- * a certain length do we allocate a buffer on the heap.
- */
-class String {
-protected:
- /**
- * The size of the internal storage. Increasing this means less heap
- * allocations are needed, at the cost of more stack memory usage,
- * and of course lots of wasted memory. Empirically, 90% or more of
- * all String instances are less than 32 chars long. If a platform
- * is very short on stack space, it would be possible to lower this.
- * A value of 24 still seems acceptable, though considerably worse,
- * while 16 seems to be the lowest you want to go... Anything lower
- * than 8 makes no sense, since that's the size of member _extern
- * (on 32 bit machines; 12 bytes on systems with 64bit pointers).
- */
- static const uint32 _builtinCapacity = 32 - sizeof(uint32) - sizeof(char*);
-
- /**
- * Length of the string. Stored to avoid having to call strlen
- * a lot. Yes, we limit ourselves to strings shorter than 4GB --
- * on purpose :-).
- */
- uint32 _size;
-
- /**
- * Pointer to the actual string storage. Either points to _storage,
- * or to a block allocated on the heap via malloc.
- */
- char *_str;
-
-
- union {
- /**
- * Internal string storage.
- */
- char _storage[_builtinCapacity];
- /**
- * External string storage data -- the capacity of the string
- * _str points to.
- */
- struct {
- uint32 _capacity;
- } _extern;
- };
-
- inline bool isStorageIntern() const {
- return _str == _storage;
- }
-
-public:
-#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__))
- static const String emptyString;
-#else
- static const char *emptyString;
-#endif
-
- /** Construct a new empty string. */
- String() : _size(0), _str(_storage) { _storage[0] = 0; }
-
- /** Construct a new string from the given NULL-terminated C string. */
- String(const char *str);
-
- /** Construct a new string containing exactly len characters read from address str. */
- String(const char *str, uint32 len);
-
- /** Construct a new string containing the characters between beginP (including) and endP (excluding). */
- String(const char *beginP, const char *endP);
-
- /** Construct a copy of the given string. */
- String(const String &str);
-
- /** Construct a string consisting of the given character. */
- explicit String(char c);
-
- ~String();
-
- String &operator =(const char *str);
- String &operator =(const String &str);
- String &operator =(char c);
- String &operator +=(const char *str);
- String &operator +=(const String &str);
- String &operator +=(char c);
-
- bool operator ==(const String &x) const;
- bool operator ==(const char *x) const;
- bool operator !=(const String &x) const;
- bool operator !=(const char *x) const;
-
- bool operator <(const String &x) const;
- bool operator <=(const String &x) const;
- bool operator >(const String &x) const;
- bool operator >=(const String &x) const;
-
- bool equals(const String &x) const;
- bool equalsIgnoreCase(const String &x) const;
- int compareTo(const String &x) const; // strcmp clone
- int compareToIgnoreCase(const String &x) const; // stricmp clone
-
- bool equals(const char *x) const;
- bool equalsIgnoreCase(const char *x) const;
- int compareTo(const char *x) const; // strcmp clone
- int compareToIgnoreCase(const char *x) const; // stricmp clone
-
- bool hasSuffix(const char *x) const;
- bool hasPrefix(const char *x) const;
-
- bool contains(const char *x) const;
- bool contains(char x) const;
-
- /**
- * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
- * Taken from exult/files/listfiles.cc
- *
- * Token meaning:
- * "*": any character, any amount of times.
- * "?": any character, only once.
- *
- * Example strings/patterns:
- * String: monkey.s01 Pattern: monkey.s?? => true
- * String: monkey.s101 Pattern: monkey.s?? => false
- * String: monkey.s99 Pattern: monkey.s?1 => false
- * String: monkey.s101 Pattern: monkey.s* => true
- * String: monkey.s99 Pattern: monkey.s*1 => false
- *
- * @param str Text to be matched against the given pattern.
- * @param pat Glob pattern.
- * @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly.
- *
- * @return true if str matches the pattern, false otherwise.
- */
- bool matchString(const char *pat, bool pathMode = false) const;
- bool matchString(const String &pat, bool pathMode = false) const;
-
-
- inline const char *c_str() const { return _str; }
- inline uint size() const { return _size; }
-
- inline bool empty() const { return (_size == 0); }
- char lastChar() const { return (_size > 0) ? _str[_size-1] : 0; }
-
- char operator[](int idx) const {
- assert(_str && idx >= 0 && idx < (int)_size);
- return _str[idx];
- }
-
- /** Remove the last character from the string. */
- void deleteLastChar();
-
- /** Remove the character at position p from the string. */
- void deleteChar(uint32 p);
-
- /** Set character c at position p, replacing the previous character there. */
- void setChar(char c, uint32 p);
-
- /** Set character c at position p. */
- void insertChar(char c, uint32 p);
-
- /** Clears the string, making it empty. */
- void clear();
-
- /** Convert all characters in the string to lowercase. */
- void toLowercase();
-
- /** Convert all characters in the string to uppercase. */
- void toUppercase();
-
- /**
- * Removes trailing and leading whitespaces. Uses isspace() to decide
- * what is whitespace and what not.
- */
- void trim();
-
-public:
- typedef char * iterator;
- typedef const char * const_iterator;
-
- iterator begin() {
- return _str;
- }
-
- iterator end() {
- return begin() + size();
- }
-
- const_iterator begin() const {
- return _str;
- }
-
- const_iterator end() const {
- return begin() + size();
- }
-
-protected:
- void makeUnique();
- void ensureCapacity(uint32 new_size, bool keep_old);
- void initWithCStr(const char *str, uint32 len);
-};
-
-// Append two strings to form a new (temp) string
-String operator +(const String &x, const String &y);
-
-String operator +(const char *x, const String &y);
-String operator +(const String &x, const char *y);
-
-String operator +(const String &x, char y);
-String operator +(char x, const String &y);
-
-// Some useful additional comparison operators for Strings
-bool operator == (const char *x, const String &y);
-bool operator != (const char *x, const String &y);
-
-// Utility functions to remove leading and trailing whitespaces
-extern char *ltrim(char *t);
-extern char *rtrim(char *t);
-extern char *trim(char *t);
-
-
-/**
- * Returns the last component of a given path.
- *
- * Examples:
- * /foo/bar.txt would return 'bar.txt'
- * /foo/bar/ would return 'bar'
- * /foo/./bar// would return 'bar'
- *
- * @param path the path of which we want to know the last component
- * @param sep character used to separate path components
- * @return The last component of the path.
- */
-Common::String lastPathComponent(const Common::String &path, const char sep);
-
-/**
- * Normalize a gien path to a canonical form. In particular:
- * - trailing separators are removed: /foo/bar/ -> /foo/bar
- * - double separators (= empty components) are removed: /foo//bar -> /foo/bar
- * - dot components are removed: /foo/./bar -> /foo/bar
- *
- * @todo remove double dot components: /foo/baz/../bar -> /foo/bar
- *
- * @param path the path to normalize
- * @param sep the separator token (usually '/' on Unix-style systems, or '\\' on Windows based stuff)
- * @return the normalized path
- */
-Common::String normalizePath(const Common::String &path, const char sep);
-
-
-/**
- * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
- * Taken from exult/files/listfiles.cc
- *
- * Token meaning:
- * "*": any character, any amount of times.
- * "?": any character, only once.
- *
- * Example strings/patterns:
- * String: monkey.s01 Pattern: monkey.s?? => true
- * String: monkey.s101 Pattern: monkey.s?? => false
- * String: monkey.s99 Pattern: monkey.s?1 => false
- * String: monkey.s101 Pattern: monkey.s* => true
- * String: monkey.s99 Pattern: monkey.s*1 => false
- *
- * @param str Text to be matched against the given pattern.
- * @param pat Glob pattern.
- * @param pathMode Whether to use path mode, i.e., whether slashes must be matched explicitly.
- *
- * @return true if str matches the pattern, false otherwise.
- */
-bool matchString(const char *str, const char *pat, bool pathMode = false);
-
-/**
- * Take a 32 bit value and turn it into a four character string, where each of
- * the four bytes is turned into one character. Most significant byte is printed
- * first.
- */
-String tag2string(uint32 tag);
-#define tag2str(x) Common::tag2string(x).c_str()
-
-
-class StringList : public Array<String> {
-public:
- void push_back(const char *str) {
- Array<String>::push_back(str);
- }
-
- void push_back(const String &str) {
- Array<String>::push_back(str);
- }
-};
-
-} // End of namespace Common
-
-#endif
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list