[Scummvm-cvs-logs] SF.net SVN: scummvm:[43986] scummvm/trunk/engines/sci

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Sun Sep 6 15:00:30 CEST 2009


Revision: 43986
          http://scummvm.svn.sourceforge.net/scummvm/?rev=43986&view=rev
Author:   fingolfin
Date:     2009-09-06 13:00:30 +0000 (Sun, 06 Sep 2009)

Log Message:
-----------
SCI: Replace "IntMapper *id_seg_map" in SegManager with a Common::HashMap<int,int>

This simplifies the code considerably. Also changed the savegame format
accordingly, which required me to bump the format version to 10. Old
saves should still load fine.

Modified Paths:
--------------
    scummvm/trunk/engines/sci/console.cpp
    scummvm/trunk/engines/sci/engine/memobj.h
    scummvm/trunk/engines/sci/engine/savegame.cpp
    scummvm/trunk/engines/sci/engine/savegame.h
    scummvm/trunk/engines/sci/engine/seg_manager.cpp
    scummvm/trunk/engines/sci/engine/seg_manager.h
    scummvm/trunk/engines/sci/engine/state.h

Modified: scummvm/trunk/engines/sci/console.cpp
===================================================================
--- scummvm/trunk/engines/sci/console.cpp	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/console.cpp	2009-09-06 13:00:30 UTC (rev 43986)
@@ -1364,7 +1364,7 @@
 				break;
 			}
 
-			DebugPrintf("  seg_ID = %d \n", mobj->getSegmentManagerId());
+			DebugPrintf("  \n");
 		}
 	}
 	DebugPrintf("\n");

Modified: scummvm/trunk/engines/sci/engine/memobj.h
===================================================================
--- scummvm/trunk/engines/sci/engine/memobj.h	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/engine/memobj.h	2009-09-06 13:00:30 UTC (rev 43986)
@@ -52,7 +52,6 @@
 
 struct MemObject : public Common::Serializable {
 	MemObjectType _type;
-	int _segManagerId; /**< Internal value used by the segMan's hash map */
 
 	typedef void (*NoteCallback)(void *param, reg_t addr);	// FIXME: Bad choice of name
 
@@ -63,7 +62,6 @@
 	virtual ~MemObject() {}
 
 	inline MemObjectType getType() const { return _type; }
-	inline int getSegmentManagerId() const { return _segManagerId; }
 
 	/**
 	 * Check whether the given offset into this memory object is valid,

Modified: scummvm/trunk/engines/sci/engine/savegame.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/savegame.cpp	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/engine/savegame.cpp	2009-09-06 13:00:30 UTC (rev 43986)
@@ -54,7 +54,6 @@
 // TODO: Many of the following sync_*() methods should be turned into member funcs
 // of the classes they are syncing.
 
-static void sync_MemObjPtr(Common::Serializer &s, MemObject *&obj);
 static void sync_songlib_t(Common::Serializer &s, SongLibrary &obj);
 
 static void sync_reg_t(Common::Serializer &s, reg_t &obj) {
@@ -190,18 +189,63 @@
 }
 
 void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
-	s.syncAsSint32LE(reserved_id);
+	s.skip(4, VER(9), VER(9));	// Obsolete: Used to be reserved_id
 	s.syncAsSint32LE(exports_wide);
 	s.skip(4, VER(9), VER(9));	// Obsolete: Used to be gc_mark_bits
 
-	id_seg_map->saveLoadWithSerializer(s);
+	if (s.isLoading()) {
+		// Reset _scriptSegMap, to be restored below
+		_scriptSegMap.clear();
 
+		if (s.getVersion() <= 9) {
+			// Skip over the old id_seg_map when loading (we now regenerate the
+			// equivalent data, in _scriptSegMap, from scratch).
+
+			s.skip(4);	// base_value
+			while (true) {
+				uint32 key;
+				s.syncAsSint32LE(key);
+				if (key == INTMAPPER_MAGIC_KEY)
+					break;
+				s.skip(4);	// idx
+			}
+		}
+	}
+
+
 	uint sync_heap_size = _heap.size();
 	s.syncAsUint32LE(sync_heap_size);
 	_heap.resize(sync_heap_size);
-	for (uint i = 0; i < sync_heap_size; ++i)
-		sync_MemObjPtr(s, _heap[i]);
+	for (uint i = 0; i < sync_heap_size; ++i) {
+		MemObject *&mobj = _heap[i];
 
+		// Sync the memobj type
+		MemObjectType type = (s.isSaving() && mobj) ? mobj->getType() : MEM_OBJ_INVALID;
+		s.syncAsUint32LE(type);
+
+		// If we were saving and mobj == 0, or if we are loading and this is an
+		// entry marked as empty -> skip to next
+		if (type == MEM_OBJ_INVALID) {
+			mobj = 0;
+			continue;
+		}
+
+		if (s.isLoading()) {
+			mobj = MemObject::createMemObject(type);
+		}
+		assert(mobj);
+
+		s.skip(4, VER(9), VER(9));	// Obsolete: Used to be _segManagerId
+
+		// Let the object sync custom data
+		mobj->saveLoadWithSerializer(s);
+
+		// If we are loading a script, hook it up in the script->segment map.
+		if (s.isLoading() && type == MEM_OBJ_SCRIPT) {
+			_scriptSegMap[((Script *)mobj)->nr] = i;
+		}
+	}
+
 	s.syncAsSint32LE(Clones_seg_id);
 	s.syncAsSint32LE(Lists_seg_id);
 	s.syncAsSint32LE(Nodes_seg_id);
@@ -421,30 +465,6 @@
 	}
 }
 
-static void sync_MemObjPtr(Common::Serializer &s, MemObject *&mobj) {
-	// Sync the memobj type
-	MemObjectType type = (s.isSaving() && mobj) ? mobj->getType() : MEM_OBJ_INVALID;
-	s.syncAsUint32LE(type);
-
-	// If we were saving and mobj == 0, or if we are loading and this is an
-	// entry marked as empty -> we are done.
-	if (type == MEM_OBJ_INVALID) {
-		mobj = 0;
-		return;
-	}
-
-	if (s.isLoading()) {
-		//assert(!mobj);
-		mobj = MemObject::createMemObject(type);
-	} else {
-		assert(mobj);
-	}
-
-	s.syncAsSint32LE(mobj->_segManagerId);
-	mobj->saveLoadWithSerializer(s);
-}
-
-
 #pragma mark -
 
 

Modified: scummvm/trunk/engines/sci/engine/savegame.h
===================================================================
--- scummvm/trunk/engines/sci/engine/savegame.h	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/engine/savegame.h	2009-09-06 13:00:30 UTC (rev 43986)
@@ -35,6 +35,11 @@
 
 struct EngineState;
 
+enum {
+	CURRENT_SAVEGAME_VERSION = 10,
+	MINIMUM_SAVEGAME_VERSION = 9
+};
+
 // Savegame metadata
 struct SavegameMetadata {
 	Common::String savegame_name;

Modified: scummvm/trunk/engines/sci/engine/seg_manager.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.cpp	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/engine/seg_manager.cpp	2009-09-06 13:00:30 UTC (rev 43986)
@@ -50,14 +50,7 @@
 
 #undef DEBUG_segMan // Define to turn on debugging
 
-#define INVALID_SCRIPT_ID -1
-
 SegManager::SegManager(ResourceManager *resMan) {
-	id_seg_map = new IntMapper();
-	reserved_id = INVALID_SCRIPT_ID;
-	id_seg_map->checkKey(reserved_id, true);	// reserve entry 0 for INVALID_SCRIPT_ID
-	reserved_id--; // reserved_id runs in the reversed direction to make sure no one will use it.
-
 	_heap.push_back(0);
 
 	Clones_seg_id = 0;
@@ -83,55 +76,60 @@
 		if (_heap[i])
 			deallocate(i, false);
 	}
+}
 
-	delete id_seg_map;
+SegmentId SegManager::findFreeSegment() const {
+	// FIXME: This is a very crude approach: We find a free segment id by scanning
+	// from the start. This can be slow if the number of segments becomes large.
+	// Optimizations are possible and easy, but I refrain from doing any until this
+	// refactoring is complete.
+	// One very simple yet probably effective approach would be to add
+	// "int firstFreeSegment", which is updated when allocating/freeing segments.
+	// There are some scenarios where it performs badly, but we should first check
+	// whether those occur at all. If so, there are easy refinements that deal
+	// with this. Finally, we could switch to a more elaborate scheme,
+	// such as keeping track of all free segments. But I doubt this is necessary.
+	uint seg = 1;
+	while (seg < _heap.size() && _heap[seg]) {
+		++seg;
+	}
+	assert(seg < 65536);
+	return seg;
 }
 
-int SegManager::findFreeId(int *id) {
-	bool was_added = false;
-	int retval = 0;
+MemObject *SegManager::allocSegment(MemObjectType type, SegmentId *segid) {
+	// Find a free segment
+	*segid = findFreeSegment();
 
-	while (!was_added) {
-		retval = id_seg_map->checkKey(reserved_id, true, &was_added);
-		*id = reserved_id--;
-		if (reserved_id < -1000000)
-			reserved_id = -10;
-		// Make sure we don't underflow
+	// Now allocate an object of the appropriate type...
+	MemObject *mem = MemObject::createMemObject(type);
+	if (!mem)
+		error("SegManager: invalid mobj");
+
+	// ... and put it into the (formerly) free segment.
+	if (*segid >= (int)_heap.size()) {
+		assert(*segid == (int)_heap.size());
+		_heap.push_back(0);
 	}
+	_heap[*segid] = mem;
 
-	return retval;
+	return mem;
 }
 
-MemObject *SegManager::allocNonscriptSegment(MemObjectType type, SegmentId *segid) {
-	// Allocates a non-script segment
-	int id;
-
-	*segid = findFreeId(&id);
-	return memObjAllocate(*segid, id, type);
-}
-
-// allocate a memory for script from heap
-// Parameters: (EngineState *) s: The state to operate on
-//             (int) script_nr: The script number to load
-// Returns   : 0 - allocation failure
-//             1 - allocated successfully
-//             seg_id - allocated segment id
 Script *SegManager::allocateScript(int script_nr, SegmentId *seg_id) {
-	bool was_added;
-	MemObject *mem;
-
-	*seg_id = id_seg_map->checkKey(script_nr, true, &was_added);
-	if (!was_added) {
+	// Check if the script already has an allocated segment. If it
+	// does have one, return it.
+	*seg_id = _scriptSegMap.getVal(script_nr, -1);
+	if (*seg_id > 0) {
 		return (Script *)_heap[*seg_id];
 	}
 
 	// allocate the MemObject
-	mem = memObjAllocate(*seg_id, script_nr, MEM_OBJ_SCRIPT);
-	if (!mem) {
-		error("allocateScript: Not enough memory");
-		return NULL;
-	}
+	MemObject *mem = allocSegment(MEM_OBJ_SCRIPT, seg_id);
 
+	// Add the script to the "script id -> segment id" hashmap
+	_scriptSegMap[script_nr] = *seg_id;
+
 	return (Script *)mem;
 }
 
@@ -212,10 +210,10 @@
 	VERIFY(check(seg), "invalid seg id");
 
 	mobj = _heap[seg];
-	id_seg_map->removeKey(mobj->getSegmentManagerId());
 
 	if (mobj->getType() == MEM_OBJ_SCRIPT) {
 		Script *scr = (Script *)mobj;
+		_scriptSegMap.erase(scr->nr);
 		if (recursive && scr->locals_segment)
 			deallocate(scr->locals_segment, recursive);
 	}
@@ -242,30 +240,6 @@
 	return 1;
 }
 
-MemObject *SegManager::memObjAllocate(SegmentId segid, int hash_id, MemObjectType type) {
-	MemObject *mem = MemObject::createMemObject(type);
-	if (!mem) {
-		warning("SegManager: invalid mobj");
-		return NULL;
-	}
-
-	if (segid >= (int)_heap.size()) {
-		assert(segid == (int)_heap.size());
-		_heap.push_back(0);
-	}
-
-	mem->_segManagerId = hash_id;
-
-	// hook it to the heap
-	_heap[segid] = mem;
-	return mem;
-}
-
-// return the seg if script_id is valid and in the map, else -1
-SegmentId SegManager::getScriptSegment(int script_id) const {
-	return id_seg_map->lookupKey(script_id);
-}
-
 Script *SegManager::getScript(const SegmentId seg) {
 	if (seg <= 0 || (uint)seg >= _heap.size()) {
 		error("SegManager::getScript(): seg id %x out of bounds", seg);
@@ -441,6 +415,11 @@
 	}
 }
 
+// return the seg if script_id is valid and in the map, else -1
+SegmentId SegManager::getScriptSegment(int script_id) const {
+	return _scriptSegMap.getVal(script_id, -1);
+}
+
 SegmentId SegManager::getScriptSegment(int script_nr, ScriptLoadType load) {
 	SegmentId segment;
 
@@ -614,7 +593,7 @@
 			VERIFY(locals->getType() == MEM_OBJ_LOCALS, "Re-used locals segment did not consist of local variables");
 			VERIFY(locals->script_id == scr->nr, "Re-used locals segment belonged to other script");
 		} else
-			locals = (LocalVariables *)allocNonscriptSegment(MEM_OBJ_LOCALS, &scr->locals_segment);
+			locals = (LocalVariables *)allocSegment(MEM_OBJ_LOCALS, &scr->locals_segment);
 
 		scr->locals_block = locals;
 		locals->script_id = scr->nr;
@@ -746,7 +725,7 @@
 */
 
 DataStack *SegManager::allocateStack(int size, SegmentId *segid) {
-	MemObject *mobj = allocNonscriptSegment(MEM_OBJ_STACK, segid);
+	MemObject *mobj = allocSegment(MEM_OBJ_STACK, segid);
 	DataStack *retval = (DataStack *)mobj;
 
 	retval->entries = (reg_t *)calloc(size, sizeof(reg_t));
@@ -756,13 +735,13 @@
 }
 
 SystemStrings *SegManager::allocateSysStrings(SegmentId *segid) {
-	return (SystemStrings *)allocNonscriptSegment(MEM_OBJ_SYS_STRINGS, segid);
+	return (SystemStrings *)allocSegment(MEM_OBJ_SYS_STRINGS, segid);
 }
 
 SegmentId SegManager::allocateStringFrags() {
 	SegmentId segid;
 
-	allocNonscriptSegment(MEM_OBJ_STRING_FRAG, &segid);
+	allocSegment(MEM_OBJ_STRING_FRAG, &segid);
 
 	return segid;
 }
@@ -811,7 +790,7 @@
 	int offset;
 
 	if (!Clones_seg_id) {
-		table = (CloneTable *)allocNonscriptSegment(MEM_OBJ_CLONES, &(Clones_seg_id));
+		table = (CloneTable *)allocSegment(MEM_OBJ_CLONES, &(Clones_seg_id));
 	} else
 		table = (CloneTable *)_heap[Clones_seg_id];
 
@@ -872,7 +851,7 @@
 	int offset;
 
 	if (!Lists_seg_id)
-		allocNonscriptSegment(MEM_OBJ_LISTS, &(Lists_seg_id));
+		allocSegment(MEM_OBJ_LISTS, &(Lists_seg_id));
 	table = (ListTable *)_heap[Lists_seg_id];
 
 	offset = table->allocEntry();
@@ -886,7 +865,7 @@
 	int offset;
 
 	if (!Nodes_seg_id)
-		allocNonscriptSegment(MEM_OBJ_NODES, &(Nodes_seg_id));
+		allocSegment(MEM_OBJ_NODES, &(Nodes_seg_id));
 	table = (NodeTable *)_heap[Nodes_seg_id];
 
 	offset = table->allocEntry();
@@ -900,7 +879,7 @@
 	int offset;
 
 	if (!Hunks_seg_id)
-		allocNonscriptSegment(MEM_OBJ_HUNK, &(Hunks_seg_id));
+		allocSegment(MEM_OBJ_HUNK, &(Hunks_seg_id));
 	table = (HunkTable *)_heap[Hunks_seg_id];
 
 	offset = table->allocEntry();
@@ -922,7 +901,7 @@
 
 byte *SegManager::allocDynmem(int size, const char *descr, reg_t *addr) {
 	SegmentId seg;
-	MemObject *mobj = allocNonscriptSegment(MEM_OBJ_DYNMEM, &seg);
+	MemObject *mobj = allocSegment(MEM_OBJ_DYNMEM, &seg);
 	*addr = make_reg(seg, 0);
 
 	DynMem &d = *(DynMem *)mobj;

Modified: scummvm/trunk/engines/sci/engine/seg_manager.h
===================================================================
--- scummvm/trunk/engines/sci/engine/seg_manager.h	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/engine/seg_manager.h	2009-09-06 13:00:30 UTC (rev 43986)
@@ -355,10 +355,11 @@
 	SciVersion sciVersion() { return _resMan->sciVersion(); }
 
 private:
-	IntMapper *id_seg_map; ///< id - script id; seg - index of heap
+	/** Map script ids to segment ids. */
+	Common::HashMap<int, SegmentId> _scriptSegMap;
+
 public: // TODO: make private
 	Common::Array<MemObject *> _heap;
-	int reserved_id;
 	int exports_wide;
 	Common::Array<Class> _classtable; /**< Table of all classes */
 	ResourceManager *_resMan;
@@ -369,9 +370,8 @@
 	SegmentId Hunks_seg_id; ///< ID of the (a) hunk segment
 
 private:
-	MemObject *allocNonscriptSegment(MemObjectType type, SegmentId *segid);
+	MemObject *allocSegment(MemObjectType type, SegmentId *segid);
 	LocalVariables *allocLocalsSegment(Script *scr, int count);
-	MemObject *memObjAllocate(SegmentId segid, int hash_id, MemObjectType type);
 	int deallocate(SegmentId seg, bool recursive);
 	int createClassTable();
 
@@ -381,7 +381,7 @@
 	int relocateBlock(Common::Array<reg_t> &block, int block_location, SegmentId segment, int location);
 	int relocateObject(Object *obj, SegmentId segment, int location);
 
-	int findFreeId(int *id);
+	SegmentId findFreeSegment() const;
 	void setScriptSize(Script &scr, int script_nr);
 	Object *scriptObjInit0(reg_t obj_pos);
 	Object *scriptObjInit11(reg_t obj_pos);

Modified: scummvm/trunk/engines/sci/engine/state.h
===================================================================
--- scummvm/trunk/engines/sci/engine/state.h	2009-09-06 12:59:56 UTC (rev 43985)
+++ scummvm/trunk/engines/sci/engine/state.h	2009-09-06 13:00:30 UTC (rev 43986)
@@ -74,9 +74,6 @@
 };
 
 enum {
-	CURRENT_SAVEGAME_VERSION = 9,
-	MINIMUM_SAVEGAME_VERSION = 9,
-
 	MAX_SAVE_DIR_SIZE = MAXPATHLEN
 };
 


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