Blame gladeui/glade-id-allocator.c

Packit 1e8aac
/*
Packit 1e8aac
 * Copyright (C) 2004 Owen Taylor
Packit 1e8aac
 *
Packit 1e8aac
 * Authors:
Packit 1e8aac
 *   Owen Taylor  <otaylor@redhat.com>
Packit 1e8aac
 *
Packit 1e8aac
 * Modified by the Glade developers
Packit 1e8aac
 * 
Packit 1e8aac
 * This program is free software; you can redistribute it and/or modify
Packit 1e8aac
 * it under the terms of the GNU General Public License as
Packit 1e8aac
 * published by the Free Software Foundation; either version 2 of the
Packit 1e8aac
 * License, or (at your option) any later version.
Packit 1e8aac
 *
Packit 1e8aac
 * This program is distributed in the hope that it will be useful,
Packit 1e8aac
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1e8aac
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 1e8aac
 * GNU General Public License for more details.
Packit 1e8aac
 *
Packit 1e8aac
 * You should have received a copy of the GNU General Public License
Packit 1e8aac
 * along with this program; if not, write to the Free Software
Packit 1e8aac
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Packit 1e8aac
 *
Packit 1e8aac
 */
Packit 1e8aac
Packit 1e8aac
#include "config.h"
Packit 1e8aac
#include "glade-id-allocator.h"
Packit 1e8aac
Packit 1e8aac
#include <glib.h>
Packit 1e8aac
#include <string.h>
Packit 1e8aac
Packit 1e8aac
#define INITIAL_WORDS 4
Packit 1e8aac
Packit 1e8aac
struct _GladeIDAllocator
Packit 1e8aac
{
Packit 1e8aac
  guint n_words;
Packit 1e8aac
  guint32 *data;
Packit 1e8aac
};
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_id_allocator_new:
Packit 1e8aac
 *
Packit 1e8aac
 * Returns: a new #GladeIDAllocator
Packit 1e8aac
 */
Packit 1e8aac
GladeIDAllocator *
Packit 1e8aac
glade_id_allocator_new (void)
Packit 1e8aac
{
Packit 1e8aac
  GladeIDAllocator *allocator = g_slice_new (GladeIDAllocator);
Packit 1e8aac
Packit 1e8aac
  allocator->n_words = INITIAL_WORDS;
Packit 1e8aac
  allocator->data    = g_new (guint32, INITIAL_WORDS);
Packit 1e8aac
Packit 1e8aac
  memset (allocator->data, 0xff, INITIAL_WORDS * sizeof (guint32));
Packit 1e8aac
Packit 1e8aac
  return allocator;
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_id_allocator_destroy:
Packit 1e8aac
 * @allocator: a #GladeIDAllocator
Packit 1e8aac
 *
Packit 1e8aac
 * Frees @allocator and its associated memory
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_id_allocator_destroy (GladeIDAllocator *allocator)
Packit 1e8aac
{
Packit 1e8aac
  g_return_if_fail (allocator != NULL);
Packit 1e8aac
Packit 1e8aac
  g_free (allocator->data);
Packit 1e8aac
  g_slice_free (GladeIDAllocator, allocator);
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
static inline gint
Packit 1e8aac
first_set_bit (guint32 word)
Packit 1e8aac
{
Packit 1e8aac
  static const char table[16] = {
Packit 1e8aac
    4, 0, 1, 0,
Packit 1e8aac
    2, 0, 1, 0,
Packit 1e8aac
    3, 0, 1, 0,
Packit 1e8aac
    2, 0, 1, 0
Packit 1e8aac
  };
Packit 1e8aac
Packit 1e8aac
  gint result = 0;
Packit 1e8aac
Packit 1e8aac
  if ((word & 0xffff) == 0)
Packit 1e8aac
    {
Packit 1e8aac
      word >>= 16;
Packit 1e8aac
      result += 16;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if ((word & 0xff) == 0)
Packit 1e8aac
    {
Packit 1e8aac
      word >>= 8;
Packit 1e8aac
      result += 8;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  if ((word & 0xf) == 0)
Packit 1e8aac
    {
Packit 1e8aac
      word >>= 4;
Packit 1e8aac
      result += 4;
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  return result + table[word & 0xf];
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_id_allocator_alloc:
Packit 1e8aac
 * @allocator: a #GladeIDAllocator
Packit 1e8aac
 *
Packit 1e8aac
 * TODO: write me
Packit 1e8aac
 * Returns:
Packit 1e8aac
 */
Packit 1e8aac
guint
Packit 1e8aac
glade_id_allocator_allocate (GladeIDAllocator *allocator)
Packit 1e8aac
{
Packit 1e8aac
  guint i;
Packit 1e8aac
Packit 1e8aac
  g_return_val_if_fail (allocator != NULL, 0);
Packit 1e8aac
Packit 1e8aac
  for (i = 0; i < allocator->n_words; i++)
Packit 1e8aac
    {
Packit 1e8aac
      if (allocator->data[i] != 0)
Packit 1e8aac
        {
Packit 1e8aac
          gint free_bit = first_set_bit (allocator->data[i]);
Packit 1e8aac
          allocator->data[i] &= ~(1 << free_bit);
Packit 1e8aac
Packit 1e8aac
          return 32 * i + free_bit + 1;
Packit 1e8aac
        }
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  {
Packit 1e8aac
    guint n_words = allocator->n_words;
Packit 1e8aac
Packit 1e8aac
    allocator->data = g_renew (guint32, allocator->data, n_words * 2);
Packit 1e8aac
    memset (&allocator->data[n_words], 0xff, n_words * sizeof (guint32));
Packit 1e8aac
    allocator->n_words = n_words * 2;
Packit 1e8aac
Packit 1e8aac
    allocator->data[n_words] = 0xffffffff - 1;
Packit 1e8aac
Packit 1e8aac
    return 32 * n_words + 1;
Packit 1e8aac
  }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
/**
Packit 1e8aac
 * glade_id_allocator_release:
Packit 1e8aac
 * @allocator:
Packit 1e8aac
 * @id:
Packit 1e8aac
 *
Packit 1e8aac
 * TODO: write me
Packit 1e8aac
 */
Packit 1e8aac
void
Packit 1e8aac
glade_id_allocator_release (GladeIDAllocator *allocator, guint id)
Packit 1e8aac
{
Packit 1e8aac
  guint word_idx;
Packit 1e8aac
Packit 1e8aac
  g_return_if_fail (allocator != NULL);
Packit 1e8aac
Packit 1e8aac
  /* Allocated ids start with 1 */
Packit 1e8aac
  if (id > 0)
Packit 1e8aac
    {
Packit 1e8aac
      id = id - 1;
Packit 1e8aac
      word_idx = id >> 5;
Packit 1e8aac
Packit 1e8aac
      /* Tollerate releasing ids that were never allocated with the allocator 
Packit 1e8aac
       * or are out of range... when we load Glade files with huge numbers it happens
Packit 1e8aac
       * that loaded unallocated ids are out of range
Packit 1e8aac
       */
Packit 1e8aac
      if (word_idx < allocator->n_words)
Packit 1e8aac
	allocator->data[word_idx] |= 1 << (id & 31);
Packit 1e8aac
    }
Packit 1e8aac
}
Packit 1e8aac
Packit 1e8aac
#ifdef GLADE_ID_ALLOCATOR_TEST
Packit 1e8aac
int
Packit 1e8aac
main (int argc, char **argv)
Packit 1e8aac
{
Packit 1e8aac
  GladeIDAllocator *allocator = glade_id_allocator_new ();
Packit 1e8aac
  guint i;
Packit 1e8aac
  guint iter;
Packit 1e8aac
Packit 1e8aac
  for (i = 0; i < 1000; i++)
Packit 1e8aac
    {
Packit 1e8aac
      guint id = glade_id_allocator_allocate (allocator);
Packit 1e8aac
      g_assert (id == i);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  for (i = 0; i < 1000; i++)
Packit 1e8aac
    glade_id_allocator_release (allocator, i);
Packit 1e8aac
Packit 1e8aac
  for (iter = 0; iter < 10000; iter++)
Packit 1e8aac
    {
Packit 1e8aac
      for (i = 0; i < 1000; i++)
Packit 1e8aac
        glade_id_allocator_alloc (allocator);
Packit 1e8aac
Packit 1e8aac
      for (i = 0; i < 1000; i++)
Packit 1e8aac
        glade_id_allocator_release (allocator, i);
Packit 1e8aac
    }
Packit 1e8aac
Packit 1e8aac
  glade_id_allocator_destroy (allocator);
Packit 1e8aac
Packit 1e8aac
  return 0;
Packit 1e8aac
}
Packit 1e8aac
#endif