1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "VariablesViewStateHistory.h"
8
9#include <new>
10
11#include "FunctionID.h"
12#include "VariablesViewState.h"
13
14
15// #pragma mark - Key
16
17
18struct VariablesViewStateHistory::Key {
19	thread_id	threadID;
20	FunctionID*	functionID;
21
22	Key(thread_id threadID, FunctionID* functionID)
23		:
24		threadID(threadID),
25		functionID(functionID)
26	{
27	}
28
29	uint32 HashValue() const
30	{
31		return functionID->HashValue() ^ threadID;
32	}
33
34	bool operator==(const Key& other) const
35	{
36		return threadID == other.threadID && *functionID == *other.functionID;
37	}
38};
39
40
41// #pragma mark - StateEntry
42
43
44struct VariablesViewStateHistory::StateEntry : Key, VariablesViewNodeInfo {
45	StateEntry*			next;
46	VariablesViewState*	state;
47
48	StateEntry(thread_id threadID, FunctionID* functionID)
49		:
50		Key(threadID, functionID),
51		state(NULL)
52	{
53		functionID->AcquireReference();
54	}
55
56	~StateEntry()
57	{
58		functionID->ReleaseReference();
59		if (state != NULL)
60			state->ReleaseReference();
61	}
62
63	void SetState(VariablesViewState* state)
64	{
65		if (state == this->state)
66			return;
67
68		if (state != NULL)
69			state->AcquireReference();
70
71		if (this->state != NULL)
72			this->state->ReleaseReference();
73
74		this->state = state;
75	}
76};
77
78
79struct VariablesViewStateHistory::StateEntryHashDefinition {
80	typedef Key			KeyType;
81	typedef	StateEntry	ValueType;
82
83	size_t HashKey(const Key& key) const
84	{
85		return key.HashValue();
86	}
87
88	size_t Hash(const StateEntry* value) const
89	{
90		return HashKey(*value);
91	}
92
93	bool Compare(const Key& key, const StateEntry* value) const
94	{
95		return key == *value;
96	}
97
98	StateEntry*& GetLink(StateEntry* value) const
99	{
100		return value->next;
101	}
102};
103
104
105VariablesViewStateHistory::VariablesViewStateHistory()
106	:
107	fStates(NULL)
108{
109}
110
111
112VariablesViewStateHistory::~VariablesViewStateHistory()
113{
114	if (fStates != NULL) {
115		StateEntry* entry = fStates->Clear(true);
116
117		while (entry != NULL) {
118			StateEntry* next = entry->next;
119			delete entry;
120			entry = next;
121		}
122
123		delete fStates;
124	}
125}
126
127
128status_t
129VariablesViewStateHistory::Init()
130{
131	fStates = new(std::nothrow) StateTable;
132	if (fStates == NULL)
133		return B_NO_MEMORY;
134
135	return fStates->Init();
136}
137
138
139VariablesViewState*
140VariablesViewStateHistory::GetState(thread_id threadID, FunctionID* functionID)
141	const
142{
143	// first try an exact match with the thread ID
144	if (threadID >= 0) {
145		StateEntry* stateEntry = fStates->Lookup(Key(threadID, functionID));
146		if (stateEntry != NULL)
147			return stateEntry->state;
148	}
149
150	// just match the function ID
151	StateEntry* stateEntry = fStates->Lookup(Key(-1, functionID));
152	return stateEntry != NULL ? stateEntry->state : NULL;
153}
154
155
156VariablesViewState*
157VariablesViewStateHistory::GetState(FunctionID* functionID) const
158{
159	StateEntry* stateEntry = fStates->Lookup(Key(-1, functionID));
160	return stateEntry != NULL ? stateEntry->state : NULL;
161}
162
163
164status_t
165VariablesViewStateHistory::SetState(thread_id threadID, FunctionID* functionID,
166	VariablesViewState* state)
167{
168	// Make sure the default entry for the function exists.
169	StateEntry* defaultEntry = fStates->Lookup(Key(-1, functionID));
170	bool newDefaultEntry = false;
171
172	if (defaultEntry == NULL) {
173		defaultEntry = new(std::nothrow) StateEntry(-1, functionID);
174		if (defaultEntry == NULL)
175			return B_NO_MEMORY;
176		fStates->Insert(defaultEntry);
177		newDefaultEntry = true;
178	}
179
180	// If we have a valid thread ID, make sure the respective entry for the
181	// function exists.
182	StateEntry* threadEntry = NULL;
183	if (threadID >= 0) {
184		threadEntry = fStates->Lookup(Key(threadID, functionID));
185
186		if (threadEntry == NULL) {
187			threadEntry = new(std::nothrow) StateEntry(threadID, functionID);
188			if (threadEntry == NULL) {
189				if (newDefaultEntry) {
190					fStates->Remove(defaultEntry);
191					delete defaultEntry;
192				}
193				return B_NO_MEMORY;
194			}
195			fStates->Insert(threadEntry);
196		}
197	}
198
199	defaultEntry->SetState(state);
200	if (threadEntry != NULL)
201		threadEntry->SetState(state);
202
203	return B_OK;
204}
205