xref: /haiku/src/kits/package/PackageInfoSet.cpp (revision 9f81ca838ce7b92b5689e57d3f86765db4705a7b)
1 /*
2  * Copyright 2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe <zooey@hirschkaefer.de>
7  *		Ingo Weinhold <ingo_weinhold@gmx.de>
8  */
9 
10 
11 #include <package/PackageInfoSet.h>
12 
13 #include <new>
14 
15 #include <Referenceable.h>
16 
17 #include <AutoDeleter.h>
18 
19 #include <util/OpenHashTable.h>
20 
21 #include <package/PackageInfo.h>
22 
23 
24 namespace BPackageKit {
25 
26 
27 // #pragma mark - PackageInfo
28 
29 
30 struct BPackageInfoSet::PackageInfo : public BPackageInfo {
31 	PackageInfo*	hashNext;
32 	PackageInfo*	listNext;
33 
PackageInfoBPackageKit::BPackageInfoSet::PackageInfo34 	PackageInfo(const BPackageInfo& other)
35 		:
36 		BPackageInfo(other),
37 		listNext(NULL)
38 	{
39 	}
40 
DeleteListBPackageKit::BPackageInfoSet::PackageInfo41 	void DeleteList()
42 	{
43 		PackageInfo* info = this;
44 		while (info != NULL) {
45 			PackageInfo* next = info->listNext;
46 			delete info;
47 			info = next;
48 		}
49 	}
50 };
51 
52 
53 // #pragma mark - PackageInfoHashDefinition
54 
55 
56 struct BPackageInfoSet::PackageInfoHashDefinition {
57 	typedef const char*		KeyType;
58 	typedef	PackageInfo		ValueType;
59 
HashKeyBPackageKit::BPackageInfoSet::PackageInfoHashDefinition60 	size_t HashKey(const char* key) const
61 	{
62 		return BString::HashValue(key);
63 	}
64 
HashBPackageKit::BPackageInfoSet::PackageInfoHashDefinition65 	size_t Hash(const PackageInfo* value) const
66 	{
67 		return value->Name().HashValue();
68 	}
69 
CompareBPackageKit::BPackageInfoSet::PackageInfoHashDefinition70 	bool Compare(const char* key, const PackageInfo* value) const
71 	{
72 		return value->Name() == key;
73 	}
74 
GetLinkBPackageKit::BPackageInfoSet::PackageInfoHashDefinition75 	PackageInfo*& GetLink(PackageInfo* value) const
76 	{
77 		return value->hashNext;
78 	}
79 };
80 
81 
82 // #pragma mark - PackageMap
83 
84 
85 struct BPackageInfoSet::PackageMap : public BReferenceable,
86 	public BOpenHashTable<PackageInfoHashDefinition> {
87 
PackageMapBPackageKit::BPackageInfoSet::PackageMap88 	PackageMap()
89 		:
90 		fCount(0)
91 	{
92 	}
93 
~PackageMapBPackageKit::BPackageInfoSet::PackageMap94 	~PackageMap()
95 	{
96 		DeleteAllPackageInfos();
97 	}
98 
CreateBPackageKit::BPackageInfoSet::PackageMap99 	static PackageMap* Create()
100 	{
101 		PackageMap* map = new(std::nothrow) PackageMap;
102 		if (map == NULL || map->Init() != B_OK) {
103 			delete map;
104 			return NULL;
105 		}
106 
107 		return map;
108 	}
109 
CloneBPackageKit::BPackageInfoSet::PackageMap110 	PackageMap* Clone() const
111 	{
112 		PackageMap* newMap = Create();
113 		if (newMap == NULL)
114 			return NULL;
115 		ObjectDeleter<PackageMap> newMapDeleter(newMap);
116 
117 		for (BPackageInfoSet::Iterator it(this); it.HasNext();) {
118 			const BPackageInfo* info = it.Next();
119 			if (newMap->AddNewPackageInfo(*info) != B_OK)
120 				return NULL;
121 		}
122 
123 		return newMapDeleter.Detach();
124 	}
125 
AddPackageInfoBPackageKit::BPackageInfoSet::PackageMap126 	void AddPackageInfo(PackageInfo* info)
127 	{
128 		if (PackageInfo* oldInfo = Lookup(info->Name())) {
129 			info->listNext = oldInfo->listNext;
130 			oldInfo->listNext = info;
131 		} else
132 			Insert(info);
133 
134 		fCount++;
135 	}
136 
AddNewPackageInfoBPackageKit::BPackageInfoSet::PackageMap137 	status_t AddNewPackageInfo(const BPackageInfo& oldInfo)
138 	{
139 		PackageInfo* info = new(std::nothrow) PackageInfo(oldInfo);
140 		if (info == NULL)
141 			return B_NO_MEMORY;
142 		ObjectDeleter<PackageInfo> infoDeleter(info);
143 
144 		status_t error = info->InitCheck();
145 		if (error != B_OK)
146 			return error;
147 
148 		AddPackageInfo(infoDeleter.Detach());
149 
150 		return B_OK;
151 	}
152 
DeleteAllPackageInfosBPackageKit::BPackageInfoSet::PackageMap153 	void DeleteAllPackageInfos()
154 	{
155 		PackageInfo* info = Clear(true);
156 		while (info != NULL) {
157 			PackageInfo* next = info->hashNext;
158 			info->DeleteList();
159 			info = next;
160 		}
161 	}
162 
CountPackageInfosBPackageKit::BPackageInfoSet::PackageMap163 	uint32 CountPackageInfos() const
164 	{
165 		return fCount;
166 	}
167 
168 private:
169 	uint32	fCount;
170 };
171 
172 
173 // #pragma mark - Iterator
174 
175 
Iterator(const PackageMap * map)176 BPackageInfoSet::Iterator::Iterator(const PackageMap* map)
177 	:
178 	fMap(map),
179 	fNextInfo(map != NULL ? map->GetIterator().Next() : NULL)
180 {
181 }
182 
183 
184 bool
HasNext() const185 BPackageInfoSet::Iterator::HasNext() const
186 {
187 	return fNextInfo != NULL;
188 }
189 
190 
191 const BPackageInfo*
Next()192 BPackageInfoSet::Iterator::Next()
193 {
194 	BPackageInfo* result = fNextInfo;
195 
196 	if (fNextInfo != NULL) {
197 		if (fNextInfo->listNext != NULL) {
198 			// get next in list
199 			fNextInfo = fNextInfo->listNext;
200 		} else {
201 			// get next in hash table
202 			PackageMap::Iterator iterator
203 				= fMap->GetIterator(fNextInfo->Name());
204 			iterator.Next();
205 			fNextInfo = iterator.Next();
206 		}
207 	}
208 
209 	return result;
210 }
211 
212 
213 // #pragma mark - BPackageInfoSet
214 
215 
BPackageInfoSet()216 BPackageInfoSet::BPackageInfoSet()
217 	:
218 	fPackageMap(NULL)
219 {
220 }
221 
222 
~BPackageInfoSet()223 BPackageInfoSet::~BPackageInfoSet()
224 {
225 	if (fPackageMap != NULL)
226 		fPackageMap->ReleaseReference();
227 }
228 
229 
BPackageInfoSet(const BPackageInfoSet & other)230 BPackageInfoSet::BPackageInfoSet(const BPackageInfoSet& other)
231 	:
232 	fPackageMap(other.fPackageMap)
233 {
234 	if (fPackageMap != NULL)
235 		fPackageMap->AcquireReference();
236 }
237 
238 
239 status_t
AddInfo(const BPackageInfo & info)240 BPackageInfoSet::AddInfo(const BPackageInfo& info)
241 {
242 	if (!_CopyOnWrite())
243 		return B_NO_MEMORY;
244 
245 	return fPackageMap->AddNewPackageInfo(info);
246 }
247 
248 
249 void
MakeEmpty()250 BPackageInfoSet::MakeEmpty()
251 {
252 	if (fPackageMap == NULL || fPackageMap->CountPackageInfos() == 0)
253 		return;
254 
255 	// If our map is shared, just set it to NULL.
256 	if (fPackageMap->CountReferences() != 1) {
257 		fPackageMap->ReleaseReference();
258 		fPackageMap = NULL;
259 		return;
260 	}
261 
262 	// Our map is not shared -- make it empty.
263 	fPackageMap->DeleteAllPackageInfos();
264 }
265 
266 
267 uint32
CountInfos() const268 BPackageInfoSet::CountInfos() const
269 {
270 	if (fPackageMap == NULL)
271 		return 0;
272 
273 	return fPackageMap->CountPackageInfos();
274 }
275 
276 
277 BPackageInfoSet::Iterator
GetIterator() const278 BPackageInfoSet::GetIterator() const
279 {
280 	return Iterator(fPackageMap);
281 }
282 
283 
284 BPackageInfoSet&
operator =(const BPackageInfoSet & other)285 BPackageInfoSet::operator=(const BPackageInfoSet& other)
286 {
287 	if (other.fPackageMap == fPackageMap)
288 		return *this;
289 
290 	if (fPackageMap != NULL)
291 		fPackageMap->ReleaseReference();
292 
293 	fPackageMap = other.fPackageMap;
294 
295 	if (fPackageMap != NULL)
296 		fPackageMap->AcquireReference();
297 
298 	return *this;
299 }
300 
301 
302 bool
_CopyOnWrite()303 BPackageInfoSet::_CopyOnWrite()
304 {
305 	if (fPackageMap == NULL) {
306 		fPackageMap = PackageMap::Create();
307 		return fPackageMap != NULL;
308 	}
309 
310 	if (fPackageMap->CountReferences() == 1)
311 		return true;
312 
313 	PackageMap* newMap = fPackageMap->Clone();
314 	if (newMap == NULL)
315 		return false;
316 
317 	fPackageMap->ReleaseReference();
318 	fPackageMap = newMap;
319 	return true;
320 }
321 
322 
323 }	// namespace BPackageKit
324