xref: /haiku/src/add-ons/kernel/file_systems/packagefs/util/StringPool.h (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef STRING_POOL_H
6 #define STRING_POOL_H
7 
8 
9 #include <SupportDefs.h>
10 
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <new>
15 
16 #include <util/AutoLock.h>
17 #include <util/OpenHashTable.h>
18 #include <util/StringHash.h>
19 
20 
21 class StringData;
22 
23 
24 class StringDataKey {
25 public:
26 	StringDataKey(const char* string, size_t length)
27 		:
28 		fString(string),
29 		fLength(length),
30 		fHash(hash_hash_string_part(string, length))
31 	{
32 	}
33 
34 	const char* String() const
35 	{
36 		return fString;
37 	}
38 
39 	size_t Length() const
40 	{
41 		return fLength;
42 	}
43 
44 	uint32 Hash() const
45 	{
46 		return fHash;
47 	}
48 
49 private:
50 	const char*	fString;
51 	size_t		fLength;
52 	uint32		fHash;
53 };
54 
55 
56 struct StringDataHashDefinition;
57 typedef BOpenHashTable<StringDataHashDefinition> StringDataHash;
58 
59 
60 class StringPool {
61 public:
62 	static	status_t			Init();
63 	static	void				Cleanup();
64 
65 	static	StringData*			Get(const char* string, size_t length);
66 	static	void				LastReferenceReleased(StringData* data);
67 
68 	static	void				DumpUsageStatistics();
69 
70 private:
71 	static	StringData*			_GetLocked(const StringDataKey& key);
72 
73 private:
74 	static	mutex				sLock;
75 	static	StringDataHash*		sStrings;
76 };
77 
78 
79 class StringData {
80 public:
81 	static void Init();
82 
83 	static StringData* Create(const StringDataKey& key)
84 	{
85 		void* data = malloc(sizeof(StringData) + key.Length() + 1);
86 		if (data == NULL)
87 			return NULL;
88 
89 		return new(data) StringData(key);
90 	}
91 
92 	static StringData* Empty()
93 	{
94 		return fEmptyString;
95 	}
96 
97 	static StringData* GetEmpty()
98 	{
99 		fEmptyString->AcquireReference();
100 		return fEmptyString;
101 	}
102 
103 	void Delete()
104 	{
105 		free(this);
106 	}
107 
108 	bool AcquireReference()
109 	{
110 		return atomic_add(&fReferenceCount, 1) == 0;
111 	}
112 
113 	void ReleaseReference()
114 	{
115 		if (atomic_add(&fReferenceCount, -1) == 1)
116 			StringPool::LastReferenceReleased(this);
117 	}
118 
119 	// debugging only
120 	int32 CountReferences() const
121 	{
122 		return fReferenceCount;
123 	}
124 
125 	const char* String() const
126 	{
127 		return fString;
128 	}
129 
130 	uint32 Hash() const
131 	{
132 		return fHash;
133 	}
134 
135 	StringData*& HashNext()
136 	{
137 		return fHashNext;
138 	}
139 
140 private:
141 	StringData(const StringDataKey& key)
142 		:
143 		fReferenceCount(1),
144 		fHash(key.Hash())
145 	{
146 		memcpy(fString, key.String(), key.Length());
147 		fString[key.Length()] = '\0';
148 	}
149 
150 	~StringData()
151 	{
152 	}
153 
154 private:
155 	static StringData*	fEmptyString;
156 
157 	StringData*	fHashNext;
158 	int32		fReferenceCount;
159 	uint32		fHash;
160 	char		fString[];
161 };
162 
163 
164 struct StringDataHashDefinition {
165 	typedef StringDataKey	KeyType;
166 	typedef	StringData		ValueType;
167 
168 	size_t HashKey(const StringDataKey& key) const
169 	{
170 		return key.Hash();
171 	}
172 
173 	size_t Hash(const StringData* value) const
174 	{
175 		return value->Hash();
176 	}
177 
178 	bool Compare(const StringDataKey& key, const StringData* value) const
179 	{
180 		return key.Hash() == value->Hash()
181 			&& strncmp(value->String(), key.String(), key.Length()) == 0
182 			&& value->String()[key.Length()] == '\0';
183 	}
184 
185 	StringData*& GetLink(StringData* value) const
186 	{
187 		return value->HashNext();
188 	}
189 };
190 
191 
192 #endif	// STRING_POOL_H
193