1 /*
2  * CEventQueue.cc
3  *
4  * Copyright 2014-2018 D. Mitch Bailey  cvc at shuharisystem dot com
5  *
6  * This file is part of cvc.
7  *
8  * cvc is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * cvc is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with cvc.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  * You can download cvc from https://github.com/d-m-bailey/cvc.git
22  */
23 
24 #include "CEventQueue.hh"
25 
ResetQueue(deviceId_t theDeviceCount)26 void CEventQueue::ResetQueue(deviceId_t theDeviceCount) {
27 	queueArray.clear();
28 	queueArray.resize(theDeviceCount, UNKNOWN_DEVICE);
29 	enqueueCount = dequeueCount = requeueCount = 0;
30 	queueStart = false;
31 	virtualNet_v.lastUpdate = 0;
32 }
33 
IsNextMainQueue()34 bool CEventQueue::IsNextMainQueue() {
35 	if ( mainQueue.empty() ) return false;
36 	if ( delayQueue.empty() ) return true;
37 	// for SIM_QUEUE, mainQueue has priority always. for MIN/MAX_QUEUE, mainQueue has priority if not later key
38 	return ( queueType == SIM_QUEUE || ( mainQueue.begin()->first <= delayQueue.begin()->first ) );
39 }
40 
AddEvent(eventKey_t theEventKey,deviceId_t theDeviceIndex,queuePosition_t theQueuePosition)41 void CEventQueue::AddEvent(eventKey_t theEventKey, deviceId_t theDeviceIndex, queuePosition_t theQueuePosition) {
42 	// theDelay = 1 : front of delay queue
43 	// theDelay = 2 : back of delay queue
44 	// theDelay = 0 : back of main queue
45 	// theDelay = -1 : front of main queue (mos diode)
46 	// theDelay = -2 : skip (shouldn't be here)
47 	// theDelay = -3 : front of main queue (HiZ)
48 	if ( queueType == MAX_QUEUE ) theEventKey = - theEventKey;
49 	switch (theQueuePosition) {
50 		case QUEUE_HIZ:
51 		case MOS_DIODE: { mainQueue[theEventKey].push_front(theDeviceIndex); break; }
52 		case MAIN_BACK: { mainQueue[theEventKey].push_back(theDeviceIndex); break; }
53 		case DELAY_FRONT: { delayQueue[theEventKey].push_front(theDeviceIndex); break; }
54 		case DELAY_BACK: { delayQueue[theEventKey].push_back(theDeviceIndex); break; }
55 		default: { throw EFatalError("invalid queue delay " + to_string<int>((int) theQueuePosition)); }
56 	}
57 	enqueueCount++;
58 	if ( --printCounter <= 0 ) PrintStatus();
59 	if (gDebug_cvc) cout << "Adding to queue(" << gEventQueueTypeMap[queueType] << ") device: " << theDeviceIndex << "@" << theEventKey << "+" << theQueuePosition << endl;
60   }
61 
GetMainEvent()62 deviceId_t CEventQueue::GetMainEvent() {
63 	deviceId_t myDeviceIndex = mainQueue.begin()->second.pop_front(); //mainQueue.begin()->second.front();
64 	if ( mainQueue.begin()->second.empty() ) {
65 		mainQueue.erase(mainQueue.begin());
66 	}
67 	dequeueCount++;
68 	if ( --printCounter <= 0 ) PrintStatus();
69 	return myDeviceIndex;
70 }
71 
GetDelayEvent()72 deviceId_t CEventQueue::GetDelayEvent() {
73 	deviceId_t myDeviceIndex = delayQueue.begin()->second.pop_front(); //delayQueue.begin()->second.front();
74 	if ( delayQueue.begin()->second.empty() ) {
75 		delayQueue.erase(delayQueue.begin());
76 	}
77 	dequeueCount++;
78 	if ( --printCounter <= 0 ) PrintStatus();
79 	return myDeviceIndex;
80 }
81 
GetEvent()82 deviceId_t CEventQueue::GetEvent() {
83 	if ( IsNextMainQueue() ) {
84 		return GetMainEvent();
85 	} else {
86 		return GetDelayEvent();
87 	}
88 }
89 
AddLeak(deviceId_t theDevice,CConnection & theConnections)90 void CEventQueue::AddLeak(deviceId_t theDevice, CConnection& theConnections) {
91 	string	myKey;
92 	if ( theConnections.sourcePower_p->powerId < theConnections.drainPower_p->powerId ) {
93 		myKey = to_string<int>(theConnections.sourcePower_p->powerId) + " " + to_string<int>(theConnections.drainPower_p->powerId);
94 	} else {
95 		myKey = to_string<int>(theConnections.drainPower_p->powerId) + " " + to_string<int>(theConnections.sourcePower_p->powerId);
96 	}
97 	leakMap[myKey].push_front(theDevice);
98 	if (gDebug_cvc) cout << "leak key " << myKey << " map size " << leakMap.size() << " list size " << leakMap[myKey].listSize << endl;
99 }
100 
Print(string theIndentation)101 void CEventQueue::Print(string theIndentation) {
102 	string myIndentation = theIndentation + " ";
103 	cout << theIndentation << "EventQueue(" << gEventQueueTypeMap[queueType] << ")> start" << endl;
104 	cout << myIndentation << "Counts (enqueue/dequeue/requeue) " << enqueueCount << "/" << dequeueCount << "/" << requeueCount << endl;
105 	cout << myIndentation << "Main Queue>" << endl;
106 	for (CEventSubQueue::iterator eventPair_pit = mainQueue.begin(); eventPair_pit != mainQueue.end(); eventPair_pit++) {
107 		cout << myIndentation << "Time: " << eventPair_pit->first << " (" << eventPair_pit->second.size() << "):";
108 		for (deviceId_t device_it = eventPair_pit->second.first, myLastDevice = UNKNOWN_DEVICE;
109 				device_it != UNKNOWN_DEVICE && device_it != myLastDevice;
110 				myLastDevice = device_it, device_it = queueArray[device_it]) {
111 			cout  << " " << device_it;
112 		}
113 		cout << endl;
114 	}
115 	cout << myIndentation << "Delay Queue>" << endl;
116 	for (CEventSubQueue::iterator eventPair_pit = delayQueue.begin(); eventPair_pit != delayQueue.end(); eventPair_pit++) {
117 		cout << myIndentation << "Time: " << eventPair_pit->first << " (" << eventPair_pit->second.size() << "):";
118 		for (deviceId_t device_it = eventPair_pit->second.first, myLastDevice = UNKNOWN_DEVICE;
119 				device_it != UNKNOWN_DEVICE && device_it != myLastDevice;
120 				myLastDevice = device_it, device_it = queueArray[device_it]) {
121 			cout  << " " << device_it;
122 		}
123 		cout << endl;
124 	}
125 	leakMap.Print(myIndentation);
126 	cout << theIndentation << "EventQueue> end" << endl;
127 }
128 
operator [](eventKey_t theEventKey)129 CEventList& CEventSubQueue::operator[] (eventKey_t theEventKey) {
130 	CEventSubQueue::iterator myItem_it = find(theEventKey);
131 	if ( myItem_it == end() ) {
132 		pair<CEventSubQueue::iterator, bool> myResult;
133 		myResult = insert(make_pair(theEventKey, CEventList(queueArray)));
134 		return (myResult.first->second);
135 	} else {
136 		return (myItem_it->second);
137 	}
138 }
139 
QueueTime(eventQueue_t theQueueType)140 eventKey_t CEventSubQueue::QueueTime(eventQueue_t theQueueType) {
141 	if ( size() == 0 ) return MAX_EVENT_TIME;
142 	return ( begin()->first );
143 }
144 
QueueTime()145 eventKey_t CEventQueue::QueueTime() {
146 	if ( (! queueStart) || (delayQueue.empty() && mainQueue.empty()) ) return 0;
147 	if ( queueType == MAX_QUEUE ) {
148 		return (- min(mainQueue.QueueTime(queueType), delayQueue.QueueTime(queueType)));
149 	} else {
150 		return (min(mainQueue.QueueTime(queueType), delayQueue.QueueTime(queueType)));
151 	}
152 }
153 
Later(eventKey_t theEventKey)154 bool CEventQueue::Later(eventKey_t theEventKey) {
155 	if ( queueType == MAX_QUEUE ) {
156 		return ( theEventKey < QueueTime() );
157 	} else {
158 		return ( theEventKey > QueueTime() );
159 	}
160 }
161 
Later(eventKey_t theFirstKey,eventKey_t theSecondKey)162 bool CEventQueue::Later(eventKey_t theFirstKey, eventKey_t theSecondKey) {
163 	if ( queueType == MAX_QUEUE ) {
164 		return ( theFirstKey < theSecondKey );
165 	} else {
166 		return ( theFirstKey > theSecondKey );
167 	}
168 }
169 
Print(string theIndentation)170 void CLeakList::Print(string theIndentation) {
171 	cout << theIndentation << "LeakList>";
172 	for (CLeakList::iterator device_pit = begin(); device_pit != end(); device_pit++) {
173 		cout  << " " << *device_pit;
174 	}
175 	cout << endl;
176 }
177 
PrintLeakKey(string theKey)178 string CLeakMap::PrintLeakKey(string theKey) {
179 	unsigned int myFirstKey = from_string<unsigned int>(theKey.substr(0, theKey.find(" ")));
180 	unsigned int mySecondKey = from_string<unsigned int>(theKey.substr(theKey.find(" ")));
181 	string myFirstPowerName = "", mySecondPowerName = "";
182 	for (CPowerPtrList::iterator power_ppit = powerPtrList_p->begin(); power_ppit != powerPtrList_p->end(); power_ppit++) {
183 		if ( (*power_ppit)->powerId == myFirstKey ) myFirstPowerName = string((*power_ppit)->powerSignal());
184 		if ( (*power_ppit)->powerId == mySecondKey ) mySecondPowerName = string((*power_ppit)->powerSignal());
185 	}
186 	return (myFirstPowerName + ":" + mySecondPowerName);
187 }
188 
Print(string theIndentation)189 void CLeakMap::Print(string theIndentation) {
190 	string myIndentation = theIndentation + " ";
191 	cout << theIndentation << "LeakMap(" << size() << ")> start" << endl;
192 	for (CLeakMap::iterator leakPair_pit = begin(); leakPair_pit != end(); leakPair_pit++) {
193 		cout << myIndentation << "Key: " << PrintLeakKey(leakPair_pit->first) << " :(" << leakPair_pit->second.listSize << ") ";
194 		leakPair_pit->second.Print("");
195 	}
196 	cout << theIndentation << "LeakMap> end" << endl;
197 }
198 
PrintStatus(int theNextPrintCount)199 void CEventQueue::PrintStatus(int theNextPrintCount) {
200 	cout << gEventQueueTypeMap[queueType] << " Counts (size/enqueue/requeue) " << enqueueCount - dequeueCount<< "/" <<  enqueueCount << "/" << requeueCount << "\r" << std::flush;
201 	printCounter = theNextPrintCount;
202 }
203 
push_back(deviceId_t theDevice)204 void CEventList::push_back(deviceId_t theDevice) {
205 	if (queueArray[theDevice] != UNKNOWN_DEVICE) throw EQueueError(to_string<deviceId_t> (theDevice));
206 	queueArray[theDevice] = theDevice;
207 	if ( first == UNKNOWN_DEVICE ) {
208 		assert(second == UNKNOWN_DEVICE);
209 		first = theDevice;
210 	} else {
211 		assert(second != UNKNOWN_DEVICE);
212 		queueArray[second] = theDevice;
213 	}
214 	eventListSize++;
215 	second = theDevice;
216 }
217 
push_front(deviceId_t theDevice)218 void CEventList::push_front(deviceId_t theDevice) {
219 	if (queueArray[theDevice] != UNKNOWN_DEVICE) throw EQueueError(to_string<deviceId_t> (theDevice));
220 	if ( first == UNKNOWN_DEVICE ) {
221 		assert(second == UNKNOWN_DEVICE);
222 		second = theDevice;
223 		queueArray[theDevice] = theDevice;
224 	} else {
225 		assert(second != UNKNOWN_DEVICE);
226 		queueArray[theDevice] = first;
227 	}
228 	eventListSize++;
229 	first = theDevice;
230 }
231 
pop_front()232 deviceId_t CEventList::pop_front() {
233 	if (first == UNKNOWN_DEVICE) throw EQueueError("empty queue");
234 	deviceId_t myDevice;
235 	myDevice = first;
236 	if ( first == queueArray[first] ) { // last element in queue
237 		first = second = UNKNOWN_DEVICE;
238 	} else {
239 		first = queueArray[first];
240 	}
241 	queueArray[myDevice] = UNKNOWN_DEVICE;
242 	eventListSize--;
243 	return(myDevice);
244 }
245 
front()246 inline deviceId_t CEventList::front() {
247 	return(first);
248 }
249 
empty()250 bool CEventList::empty() {
251 	return(first == UNKNOWN_DEVICE);
252 }
253 
254