Skip to content

Commit a7bf435

Browse files
Update bitwise.h
1 parent 71c3b59 commit a7bf435

File tree

1 file changed

+317
-20
lines changed

1 file changed

+317
-20
lines changed

code/logic/fossil/sys/bitwise.h

Lines changed: 317 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ static inline int fossil_sys_bitwise_has(uint64_t bits, uint64_t bit) {
119119
}
120120

121121
#include <string>
122+
#include <stdexcept>
122123

123124
/**
124125
* Fossil namespace.
@@ -127,51 +128,347 @@ namespace fossil {
127128

128129
/**
129130
* System namespace.
131+
*
132+
* Contains helpers for working with tables of bitwise flags.
133+
* The functions in this namespace act as a thin C++ wrapper around the
134+
* underlying C API for bitmask parsing, formatting, validation, and lookup.
130135
*/
131136
namespace sys {
132137

138+
/**
139+
* @class Bitwise
140+
*
141+
* @brief Utility class providing C++-style access to bitmask parsing and
142+
* manipulation functions.
143+
*
144+
* This class is a thin wrapper around the C API for working with bitwise
145+
* tables. It allows you to convert between string representations of flags
146+
* (like "read|write") and their numeric bitmask values, look up individual
147+
* flag names, and validate or count bits in a mask. Where possible, the
148+
* interface is made more idiomatic for C++ by using std::string, bool, and
149+
* exceptions for error handling.
150+
*/
133151
class Bitwise {
134152
public:
135153
/**
136-
* Parses a string like "read|write" into a bitmask using the given table.
137-
*
138-
* @param input The input string to parse.
139-
* @param table The bitwise table to use for parsing.
140-
* @return The parsed bitmask.
154+
* @brief Parse a string into a bitmask.
155+
*
156+
* Given a string containing one or more symbolic flag names separated
157+
* by the pipe character ('|'), this function returns the corresponding
158+
* numeric bitmask.
159+
*
160+
* Example:
161+
* @code
162+
* uint64_t mask = Bitwise::parse("read|write", table);
163+
* @endcode
164+
*
165+
* @param input The input string to parse (e.g., "read|write").
166+
* @param table Pointer to the bitwise table that defines valid flags.
167+
* @return A 64-bit bitmask with the corresponding bits set.
141168
*/
142169
static uint64_t parse(const std::string &input, const fossil_sys_bitwise_table_t *table) {
143170
return fossil_sys_bitwise_parse(input.c_str(), table);
144171
}
145172

146173
/**
147-
* Formats a bitmask into a string like "read|write".
148-
*
149-
* @param bits The bitmask to format.
150-
* @param table The bitwise table to use for formatting.
151-
* @param out The output buffer to write the formatted string into.
152-
* @param out_size The size of the output buffer.
153-
* @return 0 on success, or an error code on failure.
174+
* @brief Format a bitmask into a string using a caller-provided buffer.
175+
*
176+
* This is a direct wrapper around the C API. The caller is responsible
177+
* for providing a buffer of sufficient size. The formatted string will
178+
* list all set bits separated by '|'.
179+
*
180+
* Example:
181+
* @code
182+
* char buf[128];
183+
* Bitwise::format(mask, table, buf, sizeof(buf));
184+
* printf("Mask = %s\n", buf);
185+
* @endcode
186+
*
187+
* @param bits The bitmask to format.
188+
* @param table Pointer to the bitwise table that defines valid flags.
189+
* @param out Caller-provided output buffer.
190+
* @param out_size Size of the output buffer, including space for null terminator.
191+
* @return 0 on success, or a non-zero error code on failure.
154192
*/
155193
static int format(uint64_t bits, const fossil_sys_bitwise_table_t *table, char *out, size_t out_size) {
156194
return fossil_sys_bitwise_format(bits, table, out, out_size);
157195
}
158196

159197
/**
160-
* Looks up a string in the bitwise table and returns the corresponding bit.
161-
*
162-
* @param name The name to look up.
163-
* @param table The bitwise table to use for lookup.
164-
* @param out_bit Pointer to store the resulting bit.
165-
* @return 0 on success, or an error code on failure.
198+
* @brief Format a bitmask into a std::string.
199+
*
200+
* Unlike the buffer-based version, this overload allocates a temporary
201+
* buffer and returns the result as a std::string. If the buffer is not
202+
* large enough, an exception is thrown. This is the preferred C++-style
203+
* interface for most users.
204+
*
205+
* Example:
206+
* @code
207+
* std::string result = Bitwise::format(mask, table);
208+
* std::cout << "Mask = " << result << std::endl;
209+
* @endcode
210+
*
211+
* @param bits The bitmask to format.
212+
* @param table Pointer to the bitwise table that defines valid flags.
213+
* @return A std::string containing the formatted representation.
214+
*
215+
* @throws std::runtime_error if formatting fails.
216+
*/
217+
static std::string format(uint64_t bits, const fossil_sys_bitwise_table_t *table) {
218+
char buffer[1024]; // Reasonable default; adjust if tables can be very large
219+
int rc = fossil_sys_bitwise_format(bits, table, buffer, sizeof(buffer));
220+
if (rc != 0) {
221+
throw std::runtime_error("fossil_sys_bitwise_format failed");
222+
}
223+
return std::string(buffer);
224+
}
225+
226+
/**
227+
* @brief Look up a single flag name and return its corresponding bit value.
228+
*
229+
* Example:
230+
* @code
231+
* uint64_t bit;
232+
* if (Bitwise::lookup("read", table, bit) == 0) {
233+
* // bit now contains 1 << 0
234+
* }
235+
* @endcode
236+
*
237+
* @param name The flag name to look up.
238+
* @param table Pointer to the bitwise table.
239+
* @param out_bit Reference that will receive the bit value.
240+
* @return 0 if found, or non-zero if the name was not recognized.
166241
*/
167242
static int lookup(const std::string &name, const fossil_sys_bitwise_table_t *table, uint64_t &out_bit) {
168243
return fossil_sys_bitwise_lookup(name.c_str(), table, &out_bit);
169244
}
245+
246+
/**
247+
* @brief Return a bitmask containing all valid bits in the table.
248+
*
249+
* This is useful for quickly constructing masks that represent "everything".
250+
*
251+
* Example:
252+
* @code
253+
* uint64_t all_flags = Bitwise::all(table);
254+
* @endcode
255+
*
256+
* @param table Pointer to the bitwise table.
257+
* @return A mask with all defined bits set.
258+
*/
259+
static uint64_t all(const fossil_sys_bitwise_table_t *table) {
260+
return fossil_sys_bitwise_all(table);
261+
}
262+
263+
/**
264+
* @brief Validate that a bitmask contains only recognized bits.
265+
*
266+
* This is useful for catching bugs where invalid bits are accidentally set.
267+
*
268+
* Example:
269+
* @code
270+
* if (!Bitwise::validate(mask, table)) {
271+
* std::cerr << "Invalid bitmask!" << std::endl;
272+
* }
273+
* @endcode
274+
*
275+
* @param bits The bitmask to validate.
276+
* @param table Pointer to the bitwise table.
277+
* @return true if valid, false if any unknown bits are present.
278+
*/
279+
static bool validate(uint64_t bits, const fossil_sys_bitwise_table_t *table) {
280+
return fossil_sys_bitwise_validate(bits, table) == 0;
281+
}
282+
283+
/**
284+
* @brief Find the name corresponding to a single bit.
285+
*
286+
* Example:
287+
* @code
288+
* std::string name = Bitwise::name(1 << 0, table);
289+
* // name == "read"
290+
* @endcode
291+
*
292+
* @param bit The bit value to look up (must be a single bit, not a mask).
293+
* @param table Pointer to the bitwise table.
294+
* @return The name as a std::string, or an empty string if the bit is unknown.
295+
*/
296+
static std::string name(uint64_t bit, const fossil_sys_bitwise_table_t *table) {
297+
const char *n = fossil_sys_bitwise_name(bit, table);
298+
return n ? std::string(n) : std::string();
299+
}
300+
301+
/**
302+
* @brief Count how many bits are set in the mask.
303+
*
304+
* Example:
305+
* @code
306+
* size_t num_flags = Bitwise::count(mask);
307+
* @endcode
308+
*
309+
* @param bits The bitmask to count.
310+
* @return The number of set bits.
311+
*/
312+
static size_t count(uint64_t bits) {
313+
return fossil_sys_bitwise_count(bits);
314+
}
315+
316+
/**
317+
* @brief Test whether a specific bit is set in the mask.
318+
*
319+
* Example:
320+
* @code
321+
* if (Bitwise::has(mask, MY_FLAG)) {
322+
* // do something
323+
* }
324+
* @endcode
325+
*
326+
* @param bits The bitmask to check.
327+
* @param bit The bit to test.
328+
* @return true if the bit is set, false otherwise.
329+
*/
330+
static bool has(uint64_t bits, uint64_t bit) {
331+
return (bits & bit) != 0;
332+
}
333+
334+
/**
335+
* @brief Bitwise OR operator for combining flags.
336+
*
337+
* Example:
338+
* @code
339+
* uint64_t mask = Bitwise::OR(READ, WRITE);
340+
* // Or use the operator directly:
341+
* uint64_t mask = READ | WRITE;
342+
* @endcode
343+
*/
344+
static inline uint64_t OR(uint64_t lhs, uint64_t rhs) {
345+
return lhs | rhs;
346+
}
347+
348+
/**
349+
* @brief Bitwise AND operator for masking flags.
350+
*
351+
* Example:
352+
* @code
353+
* if (Bitwise::AND(mask, READ)) { ... }
354+
* // Or use the operator directly:
355+
* if (mask & READ) { ... }
356+
* @endcode
357+
*/
358+
static inline uint64_t AND(uint64_t lhs, uint64_t rhs) {
359+
return lhs & rhs;
360+
}
361+
362+
/**
363+
* @brief Bitwise XOR operator for toggling flags.
364+
*/
365+
static inline uint64_t XOR(uint64_t lhs, uint64_t rhs) {
366+
return lhs ^ rhs;
367+
}
368+
369+
/**
370+
* @brief Bitwise NOT operator for inverting a mask.
371+
*/
372+
static inline uint64_t NOT(uint64_t bits) {
373+
return ~bits;
374+
}
170375
};
171376

172-
}
377+
// ---------- Global Operator Overloads for fossil_sys_bitwise_entry_t ----------
378+
//
379+
// These allow you to work with fossil_sys_bitwise_entry_t entries as if
380+
// they were strongly-typed bitmask constants, producing uint64_t results.
381+
//
382+
383+
// --- Bitwise OR ---
384+
inline uint64_t operator|(uint64_t lhs, const fossil_sys_bitwise_entry_t &rhs) {
385+
return lhs | rhs.bit;
386+
}
387+
inline uint64_t operator|(const fossil_sys_bitwise_entry_t &lhs, uint64_t rhs) {
388+
return lhs.bit | rhs;
389+
}
390+
inline uint64_t operator|(const fossil_sys_bitwise_entry_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
391+
return lhs.bit | rhs.bit;
392+
}
393+
394+
// --- Bitwise AND ---
395+
inline uint64_t operator&(uint64_t lhs, const fossil_sys_bitwise_entry_t &rhs) {
396+
return lhs & rhs.bit;
397+
}
398+
inline uint64_t operator&(const fossil_sys_bitwise_entry_t &lhs, uint64_t rhs) {
399+
return lhs.bit & rhs;
400+
}
401+
inline uint64_t operator&(const fossil_sys_bitwise_entry_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
402+
return lhs.bit & rhs.bit;
403+
}
404+
405+
// --- Bitwise XOR ---
406+
inline uint64_t operator^(uint64_t lhs, const fossil_sys_bitwise_entry_t &rhs) {
407+
return lhs ^ rhs.bit;
408+
}
409+
inline uint64_t operator^(const fossil_sys_bitwise_entry_t &lhs, uint64_t rhs) {
410+
return lhs.bit ^ rhs;
411+
}
412+
inline uint64_t operator^(const fossil_sys_bitwise_entry_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
413+
return lhs.bit ^ rhs.bit;
414+
}
415+
416+
// --- Bitwise NOT ---
417+
inline uint64_t operator~(const fossil_sys_bitwise_entry_t &entry) {
418+
return ~entry.bit;
419+
}
420+
421+
// --- Compound Assignment Operators (modify lhs) ---
422+
inline uint64_t &operator|=(uint64_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
423+
lhs |= rhs.bit;
424+
return lhs;
425+
}
426+
inline uint64_t &operator&=(uint64_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
427+
lhs &= rhs.bit;
428+
return lhs;
429+
}
430+
inline uint64_t &operator^=(uint64_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
431+
lhs ^= rhs.bit;
432+
return lhs;
433+
}
434+
435+
// --- Comparison Operators (check equality of bits) ---
436+
inline bool operator==(uint64_t lhs, const fossil_sys_bitwise_entry_t &rhs) {
437+
return lhs == rhs.bit;
438+
}
439+
440+
inline bool operator==(const fossil_sys_bitwise_entry_t &lhs, uint64_t rhs) {
441+
return lhs.bit == rhs;
442+
}
443+
444+
inline bool operator==(const fossil_sys_bitwise_entry_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
445+
return lhs.bit == rhs.bit;
446+
}
447+
448+
inline bool operator!=(uint64_t lhs, const fossil_sys_bitwise_entry_t &rhs) {
449+
return lhs != rhs.bit;
450+
}
451+
452+
inline bool operator!=(const fossil_sys_bitwise_entry_t &lhs, uint64_t rhs) {
453+
return lhs.bit != rhs;
454+
}
455+
456+
inline bool operator!=(const fossil_sys_bitwise_entry_t &lhs, const fossil_sys_bitwise_entry_t &rhs) {
457+
return lhs.bit != rhs.bit;
458+
}
459+
460+
// --- Convenience Predicate: "Is bit set?" ---
461+
inline bool operator&&(uint64_t lhs, const fossil_sys_bitwise_entry_t &rhs) {
462+
return (lhs & rhs.bit) != 0;
463+
}
464+
465+
inline bool operator&&(const fossil_sys_bitwise_entry_t &lhs, uint64_t rhs) {
466+
return (lhs.bit & rhs) != 0;
467+
}
173468

174-
}
469+
} // namespace sys
470+
471+
} // namespace fossil
175472

176473
#endif
177474

0 commit comments

Comments
 (0)