Added SILC Bit Operations API.
[silc.git] / lib / silcutil / silcbitops.c
diff --git a/lib/silcutil/silcbitops.c b/lib/silcutil/silcbitops.c
new file mode 100644 (file)
index 0000000..4eeca57
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+
+  silcbitops.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2007 Pekka Riikonen
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+
+#include "silc.h"
+
+#define SILC_BIT_POS(bit) (bit / SILC_BIT_SIZE)
+#define SILC_BIT_MASK(bit) (1UL << (bit % SILC_BIT_SIZE))
+
+/* Set bit */
+
+SilcBool silc_bit_set(volatile unsigned long *bitmap, SilcUInt32 bitmap_size,
+                     SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit);
+
+  if (!bitmap || pos >= bitmap_size)
+    return FALSE;
+
+  bitmap[pos] |= mask;
+  return TRUE;
+}
+
+/* Clear bit */
+
+SilcBool silc_bit_clear(volatile unsigned long *bitmap, SilcUInt32 bitmap_size,
+                       SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit);
+
+  if (!bitmap || pos >= bitmap_size)
+    return FALSE;
+
+  bitmap[pos] &= ~mask;
+  return TRUE;
+}
+
+/* Toggle bit */
+
+SilcBool silc_bit_toggle(volatile unsigned long *bitmap,
+                        SilcUInt32 bitmap_size, SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit);
+
+  if (!bitmap || pos >= bitmap_size)
+    return FALSE;
+
+  bitmap[pos] ^= mask;
+  return TRUE;
+}
+
+/* Set bit and return old value */
+
+int silc_bit_test_and_set(volatile unsigned long *bitmap,
+                         SilcUInt32 bitmap_size, SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit), ret;
+
+  if (!bitmap || pos >= bitmap_size)
+    return -1;
+
+  ret = bitmap[pos];
+  bitmap[pos] ^= mask;
+
+  return (ret & mask) != 0;
+}
+
+/* Clear bit and return old value */
+
+int silc_bit_test_and_clear(volatile unsigned long *bitmap,
+                           SilcUInt32 bitmap_size, SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit), ret;
+
+  if (!bitmap || pos >= bitmap_size)
+    return -1;
+
+  ret = bitmap[pos];
+  bitmap[pos] &= ~mask;
+
+  return (ret & mask) != 0;
+}
+
+/* Toggle bit and return old value */
+
+int silc_bit_test_and_toggle(volatile unsigned long *bitmap,
+                            SilcUInt32 bitmap_size, SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit), ret;
+
+  if (!bitmap || pos >= bitmap_size)
+    return -1;
+
+  ret = bitmap[pos];
+  bitmap[pos] ^= mask;
+
+  return (ret & mask) != 0;
+}
+
+/* Return bit value */
+
+int silc_bit_get(volatile unsigned long *bitmap, SilcUInt32 bitmap_size,
+                SilcUInt32 bit)
+{
+  SilcUInt32 pos = SILC_BIT_POS(bit);
+  unsigned long mask = SILC_BIT_MASK(bit);
+
+  if (!bitmap || pos >= bitmap_size)
+    return -1;
+
+  return (bitmap[pos] & mask) != 0;
+}
+
+/* Return first set bit number */
+
+int silc_bit_ffs(volatile unsigned long *bitmap, SilcUInt32 bitmap_size)
+{
+  return silc_bit_fns(bitmap, bitmap_size, 0);
+}
+
+/* Return first zero bit number */
+
+int silc_bit_ffz(volatile unsigned long *bitmap, SilcUInt32 bitmap_size)
+{
+  return silc_bit_fnz(bitmap, bitmap_size, 0);
+}
+
+/* Return next set bit number */
+
+int silc_bit_fns(volatile unsigned long *bitmap, SilcUInt32 bitmap_size,
+                SilcUInt32 offset)
+{
+  register SilcUInt32 i;
+
+  if (!bitmap || offset >= bitmap_size * SILC_BIT_SIZE)
+    return -1;
+
+  for (i = offset; i < bitmap_size * SILC_BIT_SIZE; i++)
+    if (bitmap[SILC_BIT_POS(i)] & SILC_BIT_MASK(i))
+      return i;
+
+  return -1;
+}
+
+/* Return next zero bit number */
+
+int silc_bit_fnz(volatile unsigned long *bitmap, SilcUInt32 bitmap_size,
+                SilcUInt32 offset)
+{
+  register SilcUInt32 i;
+
+  if (!bitmap || offset >= bitmap_size * SILC_BIT_SIZE)
+    return -1;
+
+  for (i = offset; i < bitmap_size * SILC_BIT_SIZE; i++)
+    if ((bitmap[SILC_BIT_POS(i)] & SILC_BIT_MASK(i)) == 0)
+      return i;
+
+  return -1;
+}
+
+/* Clear bitmap */
+
+void silc_bit_clear_bitmap(volatile unsigned long *bitmap,
+                          SilcUInt32 bitmap_size)
+{
+  if (!bitmap)
+    return;
+  memset((void *)bitmap, 0, bitmap_size * 8);
+}