1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef __nsCheapSets_h__
39 : #define __nsCheapSets_h__
40 :
41 : #include "nsTHashtable.h"
42 : #include "mozilla/StandardInteger.h"
43 :
44 : /**
45 : * A set that takes up minimal size when there are 0 or 1 entries in the set.
46 : * Use for cases where sizes of 0 and 1 are even slightly common.
47 : */
48 : template<typename EntryType>
49 : class nsCheapSet
50 : {
51 : public:
52 : typedef typename EntryType::KeyType KeyType;
53 :
54 0 : nsCheapSet() : mState(ZERO)
55 : {
56 0 : }
57 0 : ~nsCheapSet()
58 : {
59 0 : switch (mState) {
60 : case ZERO:
61 0 : break;
62 : case ONE:
63 0 : GetSingleEntry()->~EntryType();
64 0 : break;
65 : case MANY:
66 0 : delete mUnion.table;
67 0 : break;
68 : default:
69 0 : NS_NOTREACHED("bogus state");
70 0 : break;
71 : }
72 0 : }
73 :
74 : nsresult Put(const KeyType aVal);
75 :
76 : void Remove(const KeyType aVal);
77 :
78 0 : bool Contains(const KeyType aVal)
79 : {
80 0 : switch (mState) {
81 : case ZERO:
82 0 : return false;
83 : case ONE:
84 0 : return GetSingleEntry()->KeyEquals(EntryType::KeyToPointer(aVal));
85 : case MANY:
86 0 : return !!mUnion.table->GetEntry(aVal);
87 : default:
88 0 : NS_NOTREACHED("bogus state");
89 0 : return false;
90 : }
91 : }
92 :
93 : private:
94 0 : EntryType* GetSingleEntry()
95 : {
96 0 : return reinterpret_cast<EntryType*>(&mUnion.singleEntry[0]);
97 : }
98 :
99 : enum SetState {
100 : ZERO,
101 : ONE,
102 : MANY
103 : };
104 :
105 : union {
106 : nsTHashtable<EntryType> *table;
107 : char singleEntry[sizeof(EntryType)];
108 : } mUnion;
109 : enum SetState mState;
110 : };
111 :
112 : template<typename EntryType>
113 : nsresult
114 0 : nsCheapSet<EntryType>::Put(const KeyType aVal)
115 : {
116 0 : switch (mState) {
117 : case ZERO:
118 0 : new (GetSingleEntry()) EntryType(EntryType::KeyToPointer(aVal));
119 0 : mState = ONE;
120 0 : return NS_OK;
121 : case ONE:
122 : {
123 0 : nsTHashtable<EntryType> *table = new nsTHashtable<EntryType>();
124 0 : if (!table) {
125 0 : return NS_ERROR_OUT_OF_MEMORY;
126 : }
127 0 : if (!table->Init()) {
128 0 : return NS_ERROR_FAILURE;
129 : }
130 0 : EntryType *entry = GetSingleEntry();
131 0 : if (!table->PutEntry(entry->GetKey())) {
132 0 : return NS_ERROR_OUT_OF_MEMORY;
133 : }
134 0 : entry->~EntryType();
135 0 : mUnion.table = table;
136 0 : mState = MANY;
137 : }
138 : // Fall through.
139 : case MANY:
140 0 : if (!mUnion.table->PutEntry(aVal)) {
141 0 : return NS_ERROR_OUT_OF_MEMORY;
142 : }
143 0 : return NS_OK;
144 : default:
145 0 : NS_NOTREACHED("bogus state");
146 0 : return NS_OK;
147 : }
148 : }
149 :
150 : template<typename EntryType>
151 : void
152 : nsCheapSet<EntryType>::Remove(const KeyType aVal)
153 : {
154 : switch (mState) {
155 : case ZERO:
156 : break;
157 : case ONE:
158 : if (Contains(aVal)) {
159 : GetSingleEntry()->~EntryType();
160 : mState = ZERO;
161 : }
162 : break;
163 : case MANY:
164 : mUnion.table->RemoveEntry(aVal);
165 : break;
166 : default:
167 : NS_NOTREACHED("bogus state");
168 : break;
169 : }
170 : }
171 :
172 : #endif
|