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