xref: /haiku/src/add-ons/kernel/file_systems/reiserfs/Key.h (revision 1a3518cf757c2da8006753f83962da5935bbc82b)
1 // Key.h
2 //
3 // Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 //
19 // You can alternatively use *this file* under the terms of the the MIT
20 // license included in this package.
21 
22 #ifndef KEY_H
23 #define KEY_H
24 
25 #include <new>
26 
27 #include <stdio.h>
28 
29 #include <SupportDefs.h>
30 
31 #include "Debug.h"
32 #include "endianess.h"
33 
34 using std::nothrow;
35 
36 // Key
37 /*!
38 	\class Key
39 	\brief Represents the on-disk structure for a key.
40 
41 	Unfortunately there exist two different key formats and one can not
42 	always guess the right format from the data. That makes the implementation
43 	of the class a bit messy. This and the endianess awareness code, that is
44 	particularly ugly for the bitfields (hopefully at least correct).
45 */
46 class Key : private key {
47 public:
48 	Key() {}
49 	Key(const Key &k) : key(k) {}
50 	~Key() {}
51 
52 	static Key* CastFrom(key* k)
53 		{ return static_cast<Key*>(k); }
54 	static const Key* CastFrom(const key* k)
55 		{ return static_cast<const Key*>(k); }
56 
57 	void SetTo(uint32 dirID, uint32 objectID, uint64 offset, uint32 type,
58 			   uint16 version)
59 	{
60 		k_dir_id = h2le(dirID);
61 		k_objectid = h2le(objectID);
62 		if (version == KEY_FORMAT_3_5) {
63 			u.k_offset_v1.k_offset = h2le((uint32)offset);
64 			u.k_offset_v1.k_uniqueness = h2le(type);
65 		} else
66 			_SetOffsetAndType(offset, type);
67 	}
68 
69 	uint16 GuessVersion() const
70 	{
71 		// assume old format, unless detected otherwise
72 		switch (_GetType()) {
73 			case TYPE_DIRECT:
74 			case TYPE_INDIRECT:
75 			case TYPE_DIRENTRY:
76 				return KEY_FORMAT_3_6;
77 			default:
78 				return KEY_FORMAT_3_5;
79 		}
80 	}
81 	uint32 GetDirID() const { return le2h(k_dir_id); }
82 	uint32 GetObjectID() const { return le2h(k_objectid); }
83 	uint64 GetOffset(uint16 version) const
84 	{
85 		return (version == KEY_FORMAT_3_6 ? _GetOffset()
86 										  : le2h(u.k_offset_v1.k_offset));
87 	}
88 //	uint64 GetOffset() const { return GetOffset(GuessVersion()); }
89 	void SetOffset(uint64 offset, uint16 version)
90 	{
91 		if (version == KEY_FORMAT_3_6)
92 			_SetOffsetAndType(offset, _GetType());
93 		else
94 			u.k_offset_v1.k_offset = h2le(offset);
95 	}
96 	uint16 GetType(uint16 version) const
97 	{
98 		// current version
99 		if (version == KEY_FORMAT_3_6)
100 			return _GetType();
101 		// old version
102 		switch (le2h(u.k_offset_v1.k_uniqueness)) {
103 			case V1_SD_UNIQUENESS:
104 				return TYPE_STAT_DATA;
105 			case V1_INDIRECT_UNIQUENESS:
106 				return TYPE_INDIRECT;
107 			case V1_DIRECT_UNIQUENESS:
108 				return TYPE_DIRECT;
109 			case V1_DIRENTRY_UNIQUENESS:
110 				return TYPE_DIRENTRY;
111 			case V1_ANY_UNIQUENESS:
112 			default:
113 				return TYPE_ANY;
114 		}
115 	}
116 //	uint16 GetType() const { return GetType(GuessVersion()); }
117 
118 	Key &operator=(const Key &k)
119 	{
120 		*static_cast<key*>(this) = k;
121 		return *this;
122 	}
123 
124 private:
125 	// helpers for accessing k_offset_v2
126 	uint64 _GetOffset() const
127 	{
128 		#if LITTLE_ENDIAN
129 			return u.k_offset_v2.k_type;
130 		#else
131 			offset_v2 temp;
132 			*(uint64*)&temp = h2le(*(uint64*)&u.k_offset_v2);
133 			return temp.k_offset;
134 		#endif
135 	}
136 	uint32 _GetType() const
137 	{
138 		#if LITTLE_ENDIAN
139 			return u.k_offset_v2.k_type;
140 		#else
141 			offset_v2 temp;
142 			*(uint64*)&temp = h2le(*(uint64*)&u.k_offset_v2);
143 			return temp.k_type;
144 		#endif
145 	}
146 	void _SetOffsetAndType(uint64 offset, uint32 type)
147 	{
148 		u.k_offset_v2.k_offset = offset;
149 		u.k_offset_v2.k_type = type;
150 		#if !LITTLE_ENDIAN
151 			*(uint64*)&u.k_offset_v2 = h2le(*(uint64*)&u.k_offset_v2);
152 		#endif
153 	}
154 };
155 
156 
157 // VKey	-- a versioned key
158 /*!
159 	\class VKey
160 	\brief Wraps a Key and adds format version information.
161 
162 	This class is much more useful than Key. It knows its format version and
163 	adds comparison operators. Note, that the operators do NOT compare the
164 	type fields of the key. If that is needed, the Compare() method has
165 	a flag for it.
166 */
167 class VKey {
168 private:
169 	void _Unset() { if (fVersion & ALLOCATED) delete fKey; fKey = NULL; }
170 
171 public:
172 	VKey() : fKey(NULL), fVersion(KEY_FORMAT_3_5) {}
173 	VKey(const Key *k, uint32 version)
174 		: fKey(const_cast<Key*>(k)), fVersion(version) {}
175 	VKey(const Key *k) : fKey(NULL), fVersion(KEY_FORMAT_3_5) { SetTo(k); }
176 	VKey(uint32 dirID, uint32 objectID, uint64 offset, uint32 type,
177 		uint16 version)
178 		: fKey(NULL), fVersion(KEY_FORMAT_3_5)
179 	{
180 		SetTo(dirID, objectID, offset, type, version);
181 	}
182 	VKey(const VKey &k)
183 		: fKey(new(nothrow) Key(*k.fKey)), fVersion(k.fVersion | ALLOCATED) {}
184 	~VKey() { _Unset(); }
185 
186 	void SetTo(const Key *k, uint32 version)
187 	{
188 		_Unset();
189 		fKey = const_cast<Key*>(k);
190 		fVersion = version;
191 	}
192 	void SetTo(const Key *k)
193 	{
194 		_Unset();
195 		fKey = const_cast<Key*>(k);
196 		fVersion = fKey->GuessVersion();
197 	}
198 	void SetTo(uint32 dirID, uint32 objectID, uint64 offset, uint32 type,
199 			   uint16 version)
200 	{
201 		_Unset();
202 		fKey = new(nothrow) Key;
203 		if (version == KEY_FORMAT_3_5)
204 			fVersion = KEY_FORMAT_3_5 | ALLOCATED;
205 		else
206 			fVersion = KEY_FORMAT_3_6 | ALLOCATED;
207 		fKey->SetTo(dirID, objectID, offset, type, fVersion);
208 	}
209 
210 	uint16 GetVersion() const { return fVersion & VERSION_MASK; }
211 	uint32 GetDirID() const { return fKey->GetDirID(); }
212 	uint32 GetObjectID() const { return fKey->GetObjectID(); }
213 	uint64 GetOffset() const { return fKey->GetOffset(GetVersion()); }
214 	uint16 GetType() const { return fKey->GetType(GetVersion()); }
215 
216 	void SetOffset(uint64 offset)
217 		{ return fKey->SetOffset(offset, GetVersion()); }
218 
219 	int Compare(const VKey &k, bool compareTypes = false) const
220 	{
221 		if (GetDirID() < k.GetDirID())
222 			return -1;
223 		if (GetDirID() > k.GetDirID())
224 			return 1;
225 		if (GetObjectID() < k.GetObjectID())
226 			return -1;
227 		if (GetObjectID() > k.GetObjectID())
228 			return 1;
229 		int64 dOffset = (int64)GetOffset() - (int64)k.GetOffset();
230 		if (dOffset < 0)
231 			return -1;
232 		if (dOffset > 0)
233 			return 1;
234 		if (compareTypes) {
235 			int32 dType = (int32)GetType() - (int32)k.GetType();
236 			if (dType < 0)
237 				return -1;
238 			if (dType > 0)
239 				return 1;
240 		}
241 		return 0;
242 	}
243 	// Note: The operators don't compare the types! Use Compare(, true), if
244 	// you want to do that.
245 	bool operator==(const VKey &k) const { return (Compare(k) == 0); }
246 	bool operator!=(const VKey &k) const { return (Compare(k) != 0); }
247 	bool operator<(const VKey &k) const { return (Compare(k) < 0); }
248 	bool operator>(const VKey &k) const { return (Compare(k) > 0); }
249 	bool operator<=(const VKey &k) const { return (Compare(k) <= 0); }
250 	bool operator>=(const VKey &k) const { return (Compare(k) >= 0); }
251 
252 	VKey &operator=(const VKey &k)
253 	{
254 		if (!(fVersion & ALLOCATED))
255 			fKey = new(nothrow) Key;
256 		*fKey = *k.fKey;
257 		fVersion |= ALLOCATED;
258 		return *this;
259 	}
260 
261 	void Dump() const
262 	{
263 		TPRINT(("key: {%" B_PRIu32 ", %" B_PRIu32 ", %" B_PRIu64 ", %hu}\n",
264 			GetDirID(), GetObjectID(), GetOffset(), GetType()));
265 	}
266 
267 private:
268 	enum {
269 		VERSION_MASK	= KEY_FORMAT_3_5 | KEY_FORMAT_3_6,
270 		ALLOCATED		= 0x8000
271 	};
272 
273 private:
274 	Key		*fKey;
275 	uint16	fVersion;
276 };
277 
278 #endif	// KEY_H
279