1// NodeChildTable.h
2
3#ifndef NODE_CHILD_TABLE_H
4#define NODE_CHILD_TABLE_H
5
6#include "AllocationInfo.h"
7#include "Debug.h"
8#include "Misc.h"
9#include "Node.h"
10#include "OpenHashTable.h"
11
12// NodeChildHashElement
13template<typename ParentNode, typename NodeChild>
14class NodeChildHashElement : public OpenHashElement {
15private:
16	typedef NodeChildHashElement<ParentNode, NodeChild> Element;
17public:
18
19	NodeChildHashElement() : OpenHashElement(), fID(-1), fChild(NULL)
20	{
21		fNext = -1;
22	}
23
24	static inline uint32 HashFor(vnode_id id, const char *name)
25	{
26		return node_child_hash(id, name);
27	}
28
29	static inline uint32 HashFor(ParentNode *parent, NodeChild *child)
30	{
31		return node_child_hash(parent->GetID(), child->GetName());
32	}
33
34	inline uint32 Hash() const
35	{
36		return HashFor(fID, fChild->GetName());
37	}
38
39	inline bool Equals(vnode_id id, const char *name)
40	{
41		return (fID == id && !strcmp(fChild->GetName(), name));
42	}
43
44	inline bool operator==(const OpenHashElement &_element) const
45	{
46		const Element &element = static_cast<const Element&>(_element);
47		return Equals(element.fID, element.fChild->GetName());
48	}
49
50	inline void Adopt(Element &element)
51	{
52		fID = element.fID;
53		fChild = element.fChild;
54	}
55
56	vnode_id	fID;
57	NodeChild	*fChild;
58};
59
60// NodeChildTable
61template<typename ParentNode, typename NodeChild>
62class NodeChildTable {
63public:
64	NodeChildTable();
65	~NodeChildTable();
66
67	status_t InitCheck() const;
68
69	status_t AddNodeChild(ParentNode *node, NodeChild *child);
70	status_t AddNodeChild(vnode_id, NodeChild *child);
71	status_t RemoveNodeChild(ParentNode *node, NodeChild *child);
72	status_t RemoveNodeChild(vnode_id id, NodeChild *child);
73	status_t RemoveNodeChild(vnode_id id, const char *name);
74	NodeChild *GetNodeChild(vnode_id id, const char *name);
75
76protected:
77	typedef NodeChildHashElement<ParentNode, NodeChild>	Element;
78
79private:
80	Element *_FindElement(vnode_id id, const char *name) const;
81
82protected:
83	OpenHashElementArray<Element>							fElementArray;
84	OpenHashTable<Element, OpenHashElementArray<Element> >	fTable;
85};
86
87// define convenient instantiation types
88
89// DirectoryEntryTable
90class DirectoryEntryTable : public NodeChildTable<Directory, Entry> {
91public:
92	DirectoryEntryTable()	{}
93	~DirectoryEntryTable()	{}
94
95	void GetAllocationInfo(AllocationInfo &info)
96	{
97		info.AddDirectoryEntryTableAllocation(fTable.ArraySize(),
98											  fTable.VectorSize(),
99											  sizeof(Element),
100											  fTable.CountElements());
101	}
102};
103
104// NodeAttributeTable
105class NodeAttributeTable : public NodeChildTable<Node, Attribute> {
106public:
107	NodeAttributeTable()	{}
108	~NodeAttributeTable()	{}
109
110	void GetAllocationInfo(AllocationInfo &info)
111	{
112		info.AddNodeAttributeTableAllocation(fTable.ArraySize(),
113											 fTable.VectorSize(),
114											 sizeof(Element),
115											 fTable.CountElements());
116	}
117};
118
119
120// NodeChildTable implementation
121
122// constructor
123template<typename ParentNode, typename NodeChild>
124NodeChildTable<ParentNode, NodeChild>::NodeChildTable()
125	: fElementArray(1000),
126	  fTable(1000, &fElementArray)
127{
128}
129
130// destructor
131template<typename ParentNode, typename NodeChild>
132NodeChildTable<ParentNode, NodeChild>::~NodeChildTable()
133{
134}
135
136// InitCheck
137template<typename ParentNode, typename NodeChild>
138status_t
139NodeChildTable<ParentNode, NodeChild>::InitCheck() const
140{
141	RETURN_ERROR(fTable.InitCheck() && fElementArray.InitCheck()
142				 ? B_OK : B_NO_MEMORY);
143}
144
145// AddNodeChild
146template<typename ParentNode, typename NodeChild>
147status_t
148NodeChildTable<ParentNode, NodeChild>::AddNodeChild(ParentNode *node,
149													NodeChild *child)
150{
151	status_t error = (node && child ? B_OK : B_BAD_VALUE);
152	if (error == B_OK)
153		error = AddNodeChild(node->GetID(), child);
154	return error;
155}
156
157// AddNodeChild
158template<typename ParentNode, typename NodeChild>
159status_t
160NodeChildTable<ParentNode, NodeChild>::AddNodeChild(vnode_id id,
161													NodeChild *child)
162{
163	status_t error = (child ? B_OK : B_BAD_VALUE);
164	if (error == B_OK) {
165		Element *element = fTable.Add(Element::HashFor(id, child->GetName()));
166		if (element) {
167			element->fID = id;
168			element->fChild = child;
169		} else
170			SET_ERROR(error, B_NO_MEMORY);
171	}
172	return error;
173}
174
175// RemoveNodeChild
176template<typename ParentNode, typename NodeChild>
177status_t
178NodeChildTable<ParentNode, NodeChild>::RemoveNodeChild(ParentNode *node,
179													   NodeChild *child)
180{
181	status_t error = (node && child ? B_OK : B_BAD_VALUE);
182	if (error == B_OK)
183		error = RemoveNodeChild(node->GetID(), child->GetName());
184	return error;
185}
186
187// RemoveNodeChild
188template<typename ParentNode, typename NodeChild>
189status_t
190NodeChildTable<ParentNode, NodeChild>::RemoveNodeChild(vnode_id id,
191													   NodeChild *child)
192{
193	status_t error = (child ? B_OK : B_BAD_VALUE);
194	if (error == B_OK)
195		error = RemoveNodeChild(id, child->GetName());
196	return error;
197}
198
199// RemoveNodeChild
200template<typename ParentNode, typename NodeChild>
201status_t
202NodeChildTable<ParentNode, NodeChild>::RemoveNodeChild(vnode_id id,
203													   const char *name)
204{
205	status_t error = B_OK;
206	if (Element *element = _FindElement(id, name))
207		fTable.Remove(element);
208	else
209		error = B_ERROR;
210	return error;
211}
212
213// GetNodeChild
214template<typename ParentNode, typename NodeChild>
215NodeChild *
216NodeChildTable<ParentNode, NodeChild>::GetNodeChild(vnode_id id,
217													const char *name)
218{
219	NodeChild *child = NULL;
220	if (Element *element = _FindElement(id, name))
221		child = element->fChild;
222	return child;
223}
224
225// _FindElement
226template<typename ParentNode, typename NodeChild>
227typename NodeChildTable<ParentNode, NodeChild>::Element *
228NodeChildTable<ParentNode, NodeChild>::_FindElement(vnode_id id,
229													const char *name) const
230{
231	Element *element = fTable.FindFirst(Element::HashFor(id, name));
232	while (element && !element->Equals(id, name)) {
233		if (element->fNext >= 0)
234			element = fTable.ElementAt(element->fNext);
235		else
236			element = NULL;
237	}
238	return element;
239}
240
241
242// undefine the PRINT from <Debug.h>
243//#undef PRINT
244
245#endif	// NODE_CHILD_TABLE_H
246