File: Object.cpp

package info (click to toggle)
spring 104.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 47,512 kB
  • sloc: cpp: 391,093; ansic: 79,943; python: 12,356; java: 12,201; awk: 5,889; sh: 1,826; xml: 655; makefile: 486; perl: 405; php: 211; objc: 194; sed: 2
file content (120 lines) | stat: -rw-r--r-- 3,391 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
118
119
120
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */


#include "System/Object.h"
#include "System/ContainerUtil.h"
#include "System/creg/STL_Map.h"
#include "System/Log/ILog.h"
#include "System/Platform/CrashHandler.h"

CR_BIND(CObject, )

CR_REG_METADATA(CObject, (
	CR_MEMBER(sync_id),

	CR_MEMBER(detached),

	CR_MEMBER(listening),
	CR_MEMBER(listeners),
	CR_MEMBER(listenersDepTbl),
	CR_MEMBER(listeningDepTbl)
))

std::atomic<std::int64_t> CObject::cur_sync_id(0);



static bool VectorInsertSorted(std::vector<CObject*>& v, CObject* o)
{
	return (spring::VectorInsertUniqueSorted(v, o, [](const CObject* a, const CObject* b) { return (a->GetSyncID() < b->GetSyncID()); }));
}

static bool VectorEraseSorted(std::vector<CObject*>& v, CObject* o)
{
	return (spring::VectorEraseUniqueSorted(v, o, [](const CObject* a, const CObject* b) { return (a->GetSyncID() < b->GetSyncID()); }));
}



CObject::CObject() : detached(false), listeners(), listening()
{
	// Note1: this static var is shared between all different types of classes synced & unsynced (CUnit, CFeature, CProjectile, ...)
	//  Still it doesn't break syncness even when synced objects have different sync_ids between clients as long as the sync_id is
	//  creation time dependent and monotonously increasing, so the _order_ remains between clients.

	// Use atomic fetch-and-add, so threads don't read half written data nor write old (= smaller) numbers
	sync_id = ++cur_sync_id;

	assert((sync_id + 1) > sync_id); // check for overflow
}


CObject::~CObject()
{
	assert(!detached);
	detached = true;

	for (const auto& p: listenersDepTbl) {
		assert(p.first >= DEPENDENCE_ATTACKER && p.first < DEPENDENCE_COUNT);
		assert(p.second < listeners.size());

		for (CObject* obj: listeners[p.second]) {
			obj->DependentDied(this);

			const auto jt = obj->listeningDepTbl.find(p.first);

			if (jt == obj->listeningDepTbl.end())
				continue;

			VectorEraseSorted(obj->listening[ jt->second ], this);
		}
	}

	for (const auto& p: listeningDepTbl) {
		assert(p.first >= DEPENDENCE_ATTACKER && p.first < DEPENDENCE_COUNT);
		assert(p.second < listening.size());

		for (CObject* obj: listening[p.second]) {
			const auto jt = obj->listenersDepTbl.find(p.first);

			if (jt == obj->listenersDepTbl.end())
				continue;

			VectorEraseSorted(obj->listeners[ jt->second ], this);
		}
	}
}


// NOTE:
//   we can be listening to a single object from several different places
//   objects are responsible for not adding the same dependence more than
//   once, and preferably try to delete the dependence ASAP in order not
//   to waste memory
void CObject::AddDeathDependence(CObject* obj, DependenceType dep)
{
	assert(!detached && !obj->detached);

	// check this explicitly
	if (detached || obj->detached)
		return;

	VectorInsertSorted(const_cast<TSyncSafeSet&>(     GetListening(dep)),  obj);
	VectorInsertSorted(const_cast<TSyncSafeSet&>(obj->GetListeners(dep)), this);
}


void CObject::DeleteDeathDependence(CObject* obj, DependenceType dep)
{
	assert(!detached);

	if (detached || obj->detached)
		return;

	const auto it =      listeningDepTbl.find(dep);
	const auto jt = obj->listenersDepTbl.find(dep);

	if (it !=      listeningDepTbl.end()) VectorEraseSorted(     listening[ it->second ],  obj);
	if (jt != obj->listenersDepTbl.end()) VectorEraseSorted(obj->listeners[ jt->second ], this);
}