File: SimObjectIDPool.cpp

package info (click to toggle)
spring 98.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 41,928 kB
  • ctags: 60,665
  • sloc: cpp: 356,167; ansic: 39,434; python: 12,228; java: 12,203; awk: 5,856; sh: 1,719; xml: 997; perl: 405; php: 253; objc: 194; makefile: 72; sed: 2
file content (117 lines) | stat: -rw-r--r-- 3,293 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

#include "SimObjectIDPool.h"
#include "GlobalSynced.h"
#include "Sim/Objects/SolidObject.h"

CR_BIND(SimObjectIDPool, )
CR_REG_METADATA(SimObjectIDPool, (
	CR_MEMBER(liveIdentIndexMap),
	CR_MEMBER(liveIndexIdentMap),
	CR_MEMBER(tempIndexIdentMap)
))

void SimObjectIDPool::Expand(unsigned int baseID, unsigned int numIDs) {
	// allocate new batch of (randomly shuffled) id's
	std::vector<int> newIDs(numIDs);

	for (unsigned int offsetID = 0; offsetID < numIDs; offsetID++) {
		newIDs[offsetID] = baseID + offsetID;
	}

	// randomize so that Lua widgets can not easily determine counts
	SyncedRNG rng;
	std::random_shuffle(newIDs.begin(), newIDs.end(), rng);
	std::random_shuffle(newIDs.begin(), newIDs.end(), rng);

	// NOTE:
	//   any randomization would be undone by using a std::set as-is
	//   instead create a bi-directional mapping from indices to ID's
	//   (where the ID's are a random permutation of the index range)
	//   such that ID's can be assigned and returned to the pool with
	//   their original index
	//
	//     indexIdentMap = {<0, 13>, < 1, 27>, < 2, 54>, < 3, 1>, ...}
	//     identIndexMap = {<1,  3>, <13,  0>, <27,  1>, <54, 2>, ...}
	//
	//   (the ID --> index map is never changed at runtime!)
	for (unsigned int offsetID = 0; offsetID < numIDs; offsetID++) {
		liveIndexIdentMap.insert(IDPair(baseID + offsetID, newIDs[offsetID]));
		liveIdentIndexMap.insert(IDPair(newIDs[offsetID], baseID + offsetID));
	}
}



void SimObjectIDPool::AssignID(CSolidObject* object) {
	if (object->id < 0) {
		object->id = ExtractID();
	} else {
		ReserveID(object->id);
	}
}

unsigned int SimObjectIDPool::ExtractID() {
	// extract a random ID from the pool
	//
	// should be unreachable, UnitHandler
	// and FeatureHandler have safeguards
	assert(!IsEmpty());

	const IDMap::iterator it = liveIndexIdentMap.begin();
	const unsigned int id = it->second;

	liveIndexIdentMap.erase(it);

	if (IsEmpty()) {
		RecycleIDs();
	}

	return id;
}

void SimObjectIDPool::ReserveID(unsigned int id) {
	// reserve a chosen ID from the pool
	assert(HasID(id));
	assert(!IsEmpty());

	const IDMap::iterator it = liveIdentIndexMap.find(id);
	const unsigned int idx = it->second;

	liveIndexIdentMap.erase(idx);

	if (IsEmpty()) {
		RecycleIDs();
	}
}

void SimObjectIDPool::FreeID(unsigned int id, bool delayed) {
	// put an ID back into the pool either immediately
	// or after all remaining free ID's run out (which
	// is better iff the object count never gets close
	// to the maximum)
	assert(!HasID(id));

	if (delayed) {
		tempIndexIdentMap.insert(IDPair(liveIdentIndexMap[id], id));
	} else {
		liveIndexIdentMap.insert(IDPair(liveIdentIndexMap[id], id));
	}
}

void SimObjectIDPool::RecycleIDs() {
	// throw each ID recycled up until now back into the pool
	liveIndexIdentMap.insert(tempIndexIdentMap.begin(), tempIndexIdentMap.end());
	tempIndexIdentMap.clear();
}

bool SimObjectIDPool::HasID(unsigned int id) const {
	assert(liveIdentIndexMap.find(id) != liveIdentIndexMap.end());

	// check if given ID is available in this pool
	const IDMap::const_iterator it = liveIdentIndexMap.find(id);
	const unsigned int idx = it->second;

	return (liveIndexIdentMap.find(idx) != liveIndexIdentMap.end());
}