1/*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "NameIndex.h"
8
9#include <TypeConstants.h>
10
11#include "DebugSupport.h"
12#include "IndexImpl.h"
13#include "Node.h"
14#include "TwoKeyAVLTree.h"
15#include "Volume.h"
16
17
18// #pragma mark - NameIndexPrimaryKey
19
20
21class NameIndexPrimaryKey {
22public:
23	NameIndexPrimaryKey(const Node* entry, const char* name = NULL)
24		:
25		entry(entry),
26		name(name ? name : entry->Name())
27	{
28	}
29
30	NameIndexPrimaryKey(const char* name)
31		:
32		entry(NULL),
33		name(name)
34	{
35	}
36
37	const Node*	entry;
38	const char*	name;
39};
40
41
42// #pragma mark - NameIndexGetPrimaryKey
43
44
45class NameIndexGetPrimaryKey {
46public:
47	inline NameIndexPrimaryKey operator()(const Node* a)
48	{
49		return NameIndexPrimaryKey(a);
50	}
51
52	inline NameIndexPrimaryKey operator()(const Node* a) const
53	{
54		return NameIndexPrimaryKey(a);
55	}
56};
57
58
59// #pragma mark - NameIndexPrimaryKeyCompare
60
61
62class NameIndexPrimaryKeyCompare {
63public:
64	inline int operator()(const NameIndexPrimaryKey &a,
65		const NameIndexPrimaryKey &b) const
66	{
67		if (a.entry != NULL && a.entry == b.entry)
68			return 0;
69		return strcmp(a.name, b.name);
70	}
71};
72
73
74// #pragma mark - EntryTree
75
76
77typedef TwoKeyAVLTree<Node*, NameIndexPrimaryKey, NameIndexPrimaryKeyCompare,
78	NameIndexGetPrimaryKey> _EntryTree;
79
80class NameIndex::EntryTree : public _EntryTree {
81};
82
83
84// #pragma mark -  Iterator
85
86
87struct NameIndex::IteratorPolicy {
88	typedef NameIndex										Index;
89	typedef const char*										Value;
90	typedef NameIndex::EntryTree							NodeTree;
91	typedef GenericIndexIteratorTreePolicy<IteratorPolicy>	TreePolicy;
92
93	static NodeTree* GetNodeTree(Index* index)
94	{
95		return index->fEntries;
96	}
97
98	static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
99	{
100		strlcpy((char*)buffer, node->Name(), kMaxIndexKeyLength);
101		*_keyLength = strlen(node->Name());
102	}
103};
104
105
106struct NameIndex::Iterator : public GenericIndexIterator<IteratorPolicy> {
107};
108
109
110// #pragma mark - NameIndex
111
112
113NameIndex::NameIndex()
114	:
115	Index(),
116	fEntries(NULL)
117{
118}
119
120
121NameIndex::~NameIndex()
122{
123	if (IsListening())
124		fVolume->RemoveNodeListener(this);
125
126	delete fEntries;
127	// Actually we would need to maintain a list of iterators and unset the
128	// still existing iterators here. But since the name index is deleted
129	// when the volume is unmounted, there shouldn't be any iterators left
130	// anymore.
131}
132
133
134status_t
135NameIndex::Init(Volume* volume)
136{
137	status_t error = Index::Init(volume, "name", B_STRING_TYPE, false);
138	if (error != B_OK)
139		return error;
140
141	fVolume->AddNodeListener(this, NULL);
142
143	fEntries = new(std::nothrow) EntryTree;
144	if (fEntries == NULL)
145		return B_NO_MEMORY;
146
147	return B_OK;
148}
149
150
151int32
152NameIndex::CountEntries() const
153{
154	return fEntries->CountItems();
155}
156
157
158void
159NameIndex::NodeAdded(Node* node)
160{
161	fEntries->Insert(node);
162
163	// update live queries
164	_UpdateLiveQueries(node, NULL, node->Name());
165}
166
167
168void
169NameIndex::NodeRemoved(Node* node)
170{
171	fEntries->Remove(node, node);
172
173	// update live queries
174	_UpdateLiveQueries(node, node->Name(), NULL);
175}
176
177
178void
179NameIndex::NodeChanged(Node* node, uint32 statFields,
180	const OldNodeAttributes& oldAttributes)
181{
182	// nothing to do -- the name remains the same
183}
184
185
186AbstractIndexIterator*
187NameIndex::InternalGetIterator()
188{
189	Iterator* iterator = new(std::nothrow) Iterator;
190	if (iterator != NULL) {
191		if (!iterator->SetTo(this, NULL, true)) {
192			delete iterator;
193			iterator = NULL;
194		}
195	}
196	return iterator;
197}
198
199
200AbstractIndexIterator*
201NameIndex::InternalFind(const void* _key, size_t length)
202{
203	if (length == 0)
204		return NULL;
205
206	const char* key = (const char*)_key;
207
208	// if the key is not null-terminated, copy it
209	char clonedKey[kMaxIndexKeyLength];
210	if (key[length - 1] != '\0') {
211		if (length >= kMaxIndexKeyLength)
212			length = kMaxIndexKeyLength - 1;
213
214		memcpy(clonedKey, key, length);
215		clonedKey[length] = '\0';
216		length++;
217		key = clonedKey;
218	}
219
220	Iterator* iterator = new(std::nothrow) Iterator;
221	if (iterator != NULL) {
222		if (!iterator->SetTo(this, (const char*)key)) {
223			delete iterator;
224			iterator = NULL;
225		}
226	}
227	return iterator;
228}
229
230
231void
232NameIndex::_UpdateLiveQueries(Node* entry, const char* oldName,
233	const char* newName)
234{
235	fVolume->UpdateLiveQueries(entry, Name(), Type(),
236		oldName, oldName ? strlen(oldName) : 0,
237		newName, newName ? strlen(newName) : 0);
238}
239