File: SimObjectIDPool.cpp

package info (click to toggle)
spring 106.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 55,316 kB
  • sloc: cpp: 543,954; ansic: 44,800; python: 12,575; java: 12,201; awk: 5,889; sh: 1,796; asm: 1,546; xml: 655; perl: 405; php: 211; objc: 194; makefile: 76; sed: 2
file content (139 lines) | stat: -rw-r--r-- 3,813 bytes parent folder | download | duplicates (3)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */

#include "SimObjectIDPool.h"
#include "GlobalConstants.h"
#include "GlobalSynced.h"
#include "Sim/Objects/SolidObject.h"
#include "System/creg/STL_Map.h"


CR_BIND(SimObjectIDPool, )
CR_REG_METADATA(SimObjectIDPool, (
	CR_MEMBER(poolIDs),
	CR_MEMBER(freeIDs),
	CR_MEMBER(tempIDs)
))


void SimObjectIDPool::Expand(unsigned int baseID, unsigned int numIDs) {
	std::array<int, (MAX_UNITS > MAX_FEATURES)? MAX_UNITS: MAX_FEATURES> newIDs;

	assert(numIDs <= newIDs.size());

	// allocate new batch of (randomly shuffled) id's
	std::fill(newIDs.begin(), newIDs.end(), 0);
	std::generate(newIDs.begin(), newIDs.begin() + numIDs, [&baseID]() { return (baseID++); });

	// randomize so that Lua widgets can not easily determine counts
	std::random_shuffle(newIDs.begin(), newIDs.begin() + numIDs, gsRNG);
	std::random_shuffle(newIDs.begin(), newIDs.begin() + numIDs, gsRNG);

	// lambda capture ("[n = baseID]() mutable { return (n++); }") requires std=c++14
	baseID -= numIDs;

	// NOTE:
	//   any randomization would be undone by a sorted std::container
	//   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, e.g.
	//
	//     freeIDs<idx, uid> = {<0, 13>, < 1, 27>, < 2, 54>, < 3, 1>, ...}
	//     poolIDs<uid, idx> = {<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++) {
		freeIDs.insert(std::pair<unsigned int, unsigned int>(baseID + offsetID, newIDs[offsetID]));
		poolIDs.insert(std::pair<unsigned int, unsigned int>(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 auto it = freeIDs.begin();
	const unsigned int uid = it->second;

	freeIDs.erase(it);

	if (IsEmpty())
		RecycleIDs();

	return uid;
}

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

	const auto it = poolIDs.find(uid);
	const unsigned int idx = it->second;

	freeIDs.erase(idx);

	if (!IsEmpty())
		return;

	RecycleIDs();
}

void SimObjectIDPool::FreeID(unsigned int uid, 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(uid));

	if (delayed) {
		tempIDs.insert(std::pair<unsigned int, unsigned int>(poolIDs[uid], uid));
	} else {
		freeIDs.insert(std::pair<unsigned int, unsigned int>(poolIDs[uid], uid));
	}
}

bool SimObjectIDPool::RecycleID(unsigned int uid) {
	assert(poolIDs.find(uid) != poolIDs.end());

	const unsigned int idx = poolIDs[uid];
	const auto it = tempIDs.find(idx);

	if (it == tempIDs.end())
		return false;

	tempIDs.erase(idx);
	freeIDs.insert(std::pair<unsigned int, unsigned int>(idx, uid));
	return true;
}

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


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

	// check if given ID is available (to be assigned) in this pool
	const auto it = poolIDs.find(uid);
	const unsigned int idx = it->second;

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