1/* Utility - some helper classes
2 *
3 * Copyright 2001-2006, Axel D��rfler, axeld@pinc-software.de
4 * This file may be used under the terms of the MIT License.
5 */
6#ifndef UTILITY_H
7#define UTILITY_H
8
9
10#include "bfs_endian.h"
11
12
13// Simple array, used for the duplicate handling in the B+Tree,
14// and for the log entries.
15
16struct sorted_array {
17	public:
18		off_t	count;
19
20#if __MWERKS__
21		off_t	values[1];
22#else
23		off_t	values[0];
24#endif
25
26		off_t CountItems() const { return BFS_ENDIAN_TO_HOST_INT64(count); }
27		off_t ValueAt(int32 index) const { return BFS_ENDIAN_TO_HOST_INT64(values[index]); }
28		inline int32 Find(off_t value) const;
29		void Insert(off_t value);
30		bool Remove(off_t value);
31
32	private:
33		bool _FindInternal(off_t value, int32 &index) const;
34};
35
36
37inline int32
38sorted_array::Find(off_t value) const
39{
40	int32 i;
41	return _FindInternal(value, i) ? i : -1;
42}
43
44
45// The BlockArray reserves a multiple of "blockSize" and
46// maintain array size for new entries.
47// This is used for the in-memory log entries before they
48// are written to disk.
49
50class BlockArray {
51	public:
52		BlockArray(int32 blockSize);
53		~BlockArray();
54
55		int32 Find(off_t value);
56		status_t Insert(off_t value);
57		status_t Remove(off_t value);
58
59		void MakeEmpty();
60
61		int32 CountItems() const { return fArray != NULL ? fArray->CountItems() : 0; }
62		int32 BlocksUsed() const { return fArray != NULL ? ((fArray->CountItems() + 1) * sizeof(off_t) + fBlockSize - 1) / fBlockSize : 0; }
63		sorted_array *Array() const { return fArray; }
64		int32 Size() const { return fSize; }
65
66	private:
67		sorted_array *fArray;
68		int32	fBlockSize;
69		int32	fSize;
70		int32	fMaxBlocks;
71};
72
73
74// Some atomic operations that are somehow missing in BeOS:
75//
76//	_atomic_test_and_set(value, newValue, testAgainst)
77//		sets "value" to "newValue", if "value" is equal to "testAgainst"
78//	_atomic_set(value, newValue)
79//		sets "value" to "newValue"
80
81#if _NO_INLINE_ASM
82	// Note that these atomic versions *don't* work as expected!
83	// They are only used for single processor user space tests
84	// (and don't even work correctly there)
85	inline int32
86	_atomic_test_and_set(volatile int32 *value, int32 newValue, int32 testAgainst)
87	{
88		int32 oldValue = *value;
89		if (oldValue == testAgainst)
90			*value = newValue;
91
92		return oldValue;
93	}
94
95	inline void
96	_atomic_set(volatile int32 *value, int32 newValue)
97	{
98		*value = newValue;
99	}
100#elif __INTEL__
101	inline int32
102	_atomic_test_and_set(volatile int32 *value, int32 newValue, int32 testAgainst)
103	{
104		int32 oldValue;
105		asm volatile("lock; cmpxchg %%ecx, (%%edx)"
106			: "=a" (oldValue) : "a" (testAgainst), "c" (newValue), "d" (value));
107		return oldValue;
108	}
109
110	inline void
111	_atomic_set(volatile int32 *value, int32 newValue)
112	{
113		asm volatile("lock; xchg %%eax, (%%edx)"
114			: : "a" (newValue), "d" (value));
115	}
116#elif __POWERPC__ && __MWERKS__ /* GCC has different assembler syntax */
117inline asm int32
118	_atomic_set(volatile int32 *value, int32)
119	{
120		loop:
121			dcbf	r0, r3;
122			lwarx	r0, 0, r3;
123			stwcx.	r4, 0, r3;
124			bc        5, 2, loop
125		mr r3,r5;
126		isync;
127		blr;
128	}
129
130inline asm int32
131	_atomic_test_and_set(volatile int32 *value, int32 newValue, int32 testAgainst)
132	{
133		loop:
134			dcbf	r0, r3;
135			lwarx	r0, 0, r3;
136			cmpw	r5, r0;
137			bne		no_dice;
138			stwcx.	r4, 0, r3;
139			bc      5, 2, loop
140
141		mr 		r3,r0;
142		isync;
143		blr;
144
145		no_dice:
146			stwcx.	r0, 0, r3;
147			mr 		r3,r0;
148			isync;
149			blr;
150	}
151
152#else
153#	error The macros _atomic_set(), and _atomic_test_and_set() are not defined for the target processor
154#endif
155
156
157extern "C" size_t strlcpy(char *dest, char const *source, size_t length);
158
159
160#endif	/* UTILITY_H */
161