// file: bitfield.cpp // author: Andrew Hynek // contents: implementation of the Bitfield class #include <stdarg.h> #include <string.h> #include <stdio.h> #include "bitfield.h" #include "structs.h" #include "utils.h" // ______________________________ // // static vars // ______________________________ static const int NUM_BUFFERS = 8; // I wish I could use (Bitfield::TotalWidth()+1), but that's not allowed.. static const int BUFFER_SIZE = 256; static char buffer_tab[NUM_BUFFERS][BUFFER_SIZE]; static int buffer_idx = 0; static const int LOOP_BREAK = 100; // ______________________________ // // Bitfield() // ______________________________ Bitfield::Bitfield() { Clear(); } Bitfield::Bitfield(dword offset) { Clear(); SetBit(offset); } // ______________________________ // // testing funcs // ______________________________ bool Bitfield::IsSet(dword offset) const { const int idx = offset / bits_per_var; const int flag = offset % bits_per_var; return (data[idx] & (1 << flag)); } bool Bitfield::AreAnySet(dword one, ...) const { va_list arg_list; dword offset; if (one == ENDBIT) return false; if (IsSet(one)) return true; va_start(arg_list, one); while (true) { offset = va_arg(arg_list, dword); if (offset == ENDBIT) { va_end(arg_list); return false; } else if (IsSet(offset)) { va_end(arg_list); return true; } } } int Bitfield::GetNumSet() const { int count = 0; for (int i = 0; i < TotalWidth(); i++) if (IsSet(i)) count++; return count; } bool Bitfield::AreAnyShared(const Bitfield &test) const { for (int i = 0; i < TotalWidth(); i++) if (IsSet(i) && test.IsSet(i)) return true; return false; } int Bitfield::GetNumShared(const Bitfield &test) const { int count = 0; for (int i = 0; i < BITFIELD_SIZE; i++) for (int j = 0; j < bits_per_var; j++) { const int flag = 1 << j; if ((test.data[i] & flag) && (this->data[i] & flag)) count++; } return count; } bool Bitfield::operator==(const Bitfield &two) const { return (memcmp(data, two.data, BITFIELD_SIZE*sizeof(bitfield_t)) == 0); } bool Bitfield::operator!=(const Bitfield &two) const { return (memcmp(data, two.data, BITFIELD_SIZE*sizeof(bitfield_t)) != 0); } void Bitfield::Clear() { memset(data, 0, BITFIELD_SIZE*sizeof(bitfield_t)); } void Bitfield::SetBit(dword offset) { const int idx = offset / bits_per_var; const int flag = offset % bits_per_var; data[idx] |= (1 << flag); } void Bitfield::SetBits(dword one, ...) { va_list arg_list; dword offset; if (one == ENDBIT) return; SetBit(one); va_start(arg_list, one); while (true) { offset = va_arg(arg_list, dword); if (offset != ENDBIT) SetBit(offset); else break; } va_end(arg_list); } void Bitfield::SetAll(const Bitfield &two) { for (int i = 0; i < TotalWidth(); i++) if (two.IsSet(i) && i > 0) SetBit(i); } void Bitfield::RemoveBit(dword offset) { const int idx = offset / bits_per_var; const int flag = offset % bits_per_var; data[idx] &= ~(1 << flag); } void Bitfield::RemoveBits(dword one, ...) { va_list arg_list; dword offset; if (one == ENDBIT) return; RemoveBit(one); va_start(arg_list, one); while (true) { offset = va_arg(arg_list, dword); if (offset != ENDBIT) RemoveBit(offset); else break; } va_end(arg_list); } void Bitfield::RemoveAll(const Bitfield &two) { for (int i = 0; i < TotalWidth(); i++) if (IsSet(i) && two.IsSet(i)) RemoveBit(i); } void Bitfield::ToggleBit(dword offset) { const int idx = offset / bits_per_var; const int flag = offset % bits_per_var; data[idx] ^= (1 << flag); } void Bitfield::ToggleBits(dword one, ...) { va_list arg_list; dword offset; if (one == ENDBIT) return; ToggleBit(one); va_start(arg_list, one); while (true) { offset = va_arg(arg_list, dword); if (offset != ENDBIT) ToggleBit(offset); else break; } va_end(arg_list); } const char *Bitfield::ToString() const { char *buffer = buffer_tab[buffer_idx]; char *buf_ptr = buffer; if (++buffer_idx >= NUM_BUFFERS) buffer_idx = 0; for (int i = TotalWidth()-1; i >= 0; i--) if (IsSet(i)) *(buf_ptr++) = '1'; else if (buf_ptr != buffer) *(buf_ptr++) = '0'; if (buf_ptr == buffer) { // if no flags were set, just set it to "0": strcpy(buffer, "0"); } else *buf_ptr = '\0'; return (const char *)buffer; } void Bitfield::FromString(const char *str) { const size_t len = strlen(str); dword offset = 0; Clear(); if (!len) return; const char *str_ptr = str + len - 1; while (true) { if (*str_ptr != '0') SetBit(offset); // if we're already at the beginning of the string, break if (str_ptr == str) break; str_ptr--; // if we can't hold any more bits, just break if (++offset >= ENDBIT) break; } } void Bitfield::PrintBits(char *dest, size_t dest_size, const char *names[], size_t name_cnt) { size_t len = 0; int left = dest_size - 1; bool first = true; *dest = '\0'; for (int i = 0; i < TotalWidth() && left > 0; i++) if (IsSet(i)) { size_t written; if ((unsigned)i < name_cnt && *names[i] != '\n') written = snprintf(dest + len, left, "%s%s", first? "" : ", ", names[i]); else written = snprintf(dest + len, left, "%sUNDEFINED", first? "" : ", "); left -= written; len += written; if (first) first = false; } if (left < 1) { strncpy(dest, "<TRUNCATED>", dest_size); len = MIN(dest_size-1, 11); } *(dest+len) = '\0'; }