X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Frange-set.c;h=fc02f3720f8128d638ef67e1d81100fb4f9fe781;hb=refs%2Fbuilds%2F20121219032034%2Fpspp;hp=e0dc076bba152a10aeaeb47e03ef3b0ba099021e;hpb=f5c108becd49d78f4898cab11352291f5689d24e;p=pspp
diff --git a/src/libpspp/range-set.c b/src/libpspp/range-set.c
index e0dc076bba..fc02f3720f 100644
--- a/src/libpspp/range-set.c
+++ b/src/libpspp/range-set.c
@@ -1,20 +1,18 @@
-/* PSPP - computes sample statistics.
- Copyright (C) 2007 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2007, 2009, 2011 Free Software Foundation, Inc.
- 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; either version 2 of the
- License, or (at your option) any later version.
+ 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, either version 3 of the License, or
+ (at your option) any later version.
- 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.
+ 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.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this program. If not, see . */
/* Bitmap, implemented as a balanced binary tree. */
@@ -25,45 +23,21 @@
#include
-#include
+#include "libpspp/range-set.h"
#include
#include
-#include
-#include
-#include
-#include
-
-#include "xalloc.h"
-
-/* A set of ranges. */
-struct range_set
- {
- struct pool *pool; /* Pool for freeing range_set. */
- struct bt bt; /* Tree of range_set_nodes. */
-
- /* Cache. */
- unsigned long int cache_start; /* Start of region. */
- unsigned long int cache_end; /* One past end of region. */
- bool cache_value; /* Is the region in the set? */
- };
-
-/* A node in the range set. */
-struct range_set_node
- {
- struct bt_node bt_node; /* Binary tree node. */
- unsigned long int start; /* Start of region. */
- unsigned long int end; /* One past end of region. */
- };
-
-static struct range_set_node *bt_to_rs_node (const struct bt_node *);
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/pool.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
+
static int compare_range_set_nodes (const struct bt_node *,
const struct bt_node *,
const void *aux);
-static struct range_set_node *first_node (const struct range_set *);
-static struct range_set_node *next_node (const struct range_set *,
- const struct range_set_node *);
static void delete_node (struct range_set *, struct range_set_node *);
static struct range_set_node *delete_node_get_next (struct range_set *,
struct range_set_node *);
@@ -109,7 +83,8 @@ range_set_clone (const struct range_set *old, struct pool *pool)
struct range_set_node *node;
new = range_set_create_pool (pool);
- for (node = first_node (old); node != NULL; node = next_node (old, node))
+ for (node = range_set_first__ (old); node != NULL;
+ node = range_set_next__ (old, node))
insert_node (new, node->start, node->end);
return new;
}
@@ -123,7 +98,7 @@ range_set_destroy (struct range_set *rs)
if (rs->pool != NULL)
pool_unregister (rs->pool, rs);
while (!range_set_is_empty (rs))
- delete_node (rs, first_node (rs));
+ delete_node (rs, range_set_first__ (rs));
free (rs);
}
}
@@ -131,8 +106,8 @@ range_set_destroy (struct range_set *rs)
/* Inserts the region starting at START and extending for WIDTH
into RS. */
void
-range_set_insert (struct range_set *rs,
- unsigned long int start, unsigned long int width)
+range_set_set1 (struct range_set *rs,
+ unsigned long int start, unsigned long int width)
{
unsigned long int end = start + width;
struct range_set_node *node;
@@ -152,7 +127,7 @@ range_set_insert (struct range_set *rs,
{
/* New region does not overlap NODE, but it might
overlap the next node. */
- insert_just_before (rs, start, end, next_node (rs, node));
+ insert_just_before (rs, start, end, range_set_next__ (rs, node));
}
else if (end > node->end)
{
@@ -173,15 +148,15 @@ range_set_insert (struct range_set *rs,
{
/* New region starts before any existing region, but it
might overlap the first region. */
- insert_just_before (rs, start, end, first_node (rs));
+ insert_just_before (rs, start, end, range_set_first__ (rs));
}
}
-/* Inserts the region starting at START and extending for WIDTH
+/* Deletes the region starting at START and extending for WIDTH
from RS. */
void
-range_set_delete (struct range_set *rs,
- unsigned long int start, unsigned long int width)
+range_set_set0 (struct range_set *rs,
+ unsigned long int start, unsigned long int width)
{
unsigned long int end = start + width;
struct range_set_node *node;
@@ -196,7 +171,7 @@ range_set_delete (struct range_set *rs,
node = find_node_le (rs, start);
if (node == NULL)
- node = first_node (rs);
+ node = range_set_first__ (rs);
while (node != NULL && end > node->start)
{
@@ -230,11 +205,11 @@ range_set_delete (struct range_set *rs,
/* Region to delete covers only right part of
node. */
node->end = start;
- node = next_node (rs, node);
+ node = range_set_next__ (rs, node);
}
}
else
- node = next_node (rs, node);
+ node = range_set_next__ (rs, node);
}
}
@@ -254,7 +229,7 @@ range_set_allocate (struct range_set *rs, unsigned long int request,
assert (request > 0);
- node = first_node (rs);
+ node = range_set_first__ (rs);
if (node == NULL)
return false;
node_width = node->end - node->start;
@@ -276,12 +251,43 @@ range_set_allocate (struct range_set *rs, unsigned long int request,
return true;
}
+/* Scans RS for and deletes the first contiguous run of REQUEST
+ 1-bits. If successful, sets *START to the position of the
+ first 1-bit deleted and returns true If RS does not contain a
+ run of REQUEST or more contiguous 1-bits, returns false and
+ does not modify RS. */
+bool
+range_set_allocate_fully (struct range_set *rs, unsigned long int request,
+ unsigned long int *start)
+{
+ struct range_set_node *node;
+
+ assert (request > 0);
+
+ for (node = range_set_first__ (rs); node != NULL;
+ node = range_set_next__ (rs, node))
+ {
+ unsigned long int node_width = node->end - node->start;
+ if (node_width >= request)
+ {
+ *start = node->start;
+ if (node_width > request)
+ node->start += request;
+ else
+ delete_node (rs, node);
+ rs->cache_end = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
/* Returns true if there is a 1-bit at the given POSITION in RS,
false otherwise. */
bool
range_set_contains (const struct range_set *rs_, unsigned long int position)
{
- struct range_set *rs = (struct range_set *) rs_;
+ struct range_set *rs = CONST_CAST (struct range_set *, rs_);
if (position < rs->cache_end && position >= rs->cache_start)
return rs->cache_value;
else
@@ -298,7 +304,7 @@ range_set_contains (const struct range_set *rs_, unsigned long int position)
}
else
{
- struct range_set_node *next = next_node (rs, node);
+ struct range_set_node *next = range_set_next__ (rs, node);
rs->cache_start = node->end;
rs->cache_end = next != NULL ? next->start : ULONG_MAX;
rs->cache_value = false;
@@ -307,7 +313,7 @@ range_set_contains (const struct range_set *rs_, unsigned long int position)
}
else
{
- node = first_node (rs);
+ node = range_set_first__ (rs);
rs->cache_start = 0;
rs->cache_end = node != NULL ? node->start : ULONG_MAX;
rs->cache_value = false;
@@ -316,67 +322,40 @@ range_set_contains (const struct range_set *rs_, unsigned long int position)
}
}
-/* Returns true if RS contains no 1-bits, false otherwise. */
-bool
-range_set_is_empty (const struct range_set *rs)
-{
- return bt_count (&rs->bt) == 0;
-}
-
-/* Returns the node representing the first contiguous region of
- 1-bits in RS, or a null pointer if RS is empty.
- Any call to range_set_insert, range_set_delete, or
- range_set_allocate invalidates the returned node. */
-const struct range_set_node *
-range_set_first (const struct range_set *rs)
-{
- return first_node (rs);
-}
-
-/* If NODE is nonnull, returns the node representing the next
- contiguous region of 1-bits in RS following NODE, or a null
- pointer if NODE is the last region in RS.
- If NODE is null, returns the first region in RS, as for
- range_set_first.
- Any call to range_set_insert, range_set_delete, or
- range_set_allocate invalidates the returned node. */
-const struct range_set_node *
-range_set_next (const struct range_set *rs, const struct range_set_node *node)
-{
- return (node != NULL
- ? next_node (rs, (struct range_set_node *) node)
- : first_node (rs));
-}
-
-/* Returns the position of the first 1-bit in NODE. */
+/* Returns the smallest position of a 1-bit greater than or
+ equal to START. Returns ULONG_MAX if there is no 1-bit with
+ position greater than or equal to START. */
unsigned long int
-range_set_node_get_start (const struct range_set_node *node)
+range_set_scan (const struct range_set *rs_, unsigned long int start)
{
- return node->start;
-}
-
-/* Returns one past the position of the last 1-bit in NODE. */
-unsigned long int
-range_set_node_get_end (const struct range_set_node *node)
-{
- return node->end;
-}
-
-/* Returns the number of contiguous 1-bits in NODE. */
-unsigned long int
-range_set_node_get_width (const struct range_set_node *node)
-{
- return node->end - node->start;
+ struct range_set *rs = CONST_CAST (struct range_set *, rs_);
+ unsigned long int retval = ULONG_MAX;
+ struct bt_node *bt_node;
+
+ if (start < rs->cache_end && start >= rs->cache_start && rs->cache_value)
+ return start;
+ bt_node = rs->bt.root;
+ while (bt_node != NULL)
+ {
+ struct range_set_node *node = range_set_node_from_bt__ (bt_node);
+ if (start < node->start)
+ {
+ retval = node->start;
+ bt_node = node->bt_node.down[0];
+ }
+ else if (start >= node->end)
+ bt_node = node->bt_node.down[1];
+ else
+ {
+ rs->cache_start = node->start;
+ rs->cache_end = node->end;
+ rs->cache_value = true;
+ return start;
+ }
+ }
+ return retval;
}
-/* Returns the range_set_node corresponding to the given
- BT_NODE. Returns a null pointer if BT_NODE is null. */
-static struct range_set_node *
-bt_to_rs_node (const struct bt_node *bt_node)
-{
- return bt_node ? bt_data (bt_node, struct range_set_node, bt_node) : NULL;
-}
-
/* Compares `range_set_node's A and B and returns a strcmp-like
return value. */
static int
@@ -384,28 +363,12 @@ compare_range_set_nodes (const struct bt_node *a_,
const struct bt_node *b_,
const void *aux UNUSED)
{
- const struct range_set_node *a = bt_to_rs_node (a_);
- const struct range_set_node *b = bt_to_rs_node (b_);
+ const struct range_set_node *a = range_set_node_from_bt__ (a_);
+ const struct range_set_node *b = range_set_node_from_bt__ (b_);
return a->start < b->start ? -1 : a->start > b->start;
}
-/* Returns the first range_set_node in RS,
- or a null pointer if RS is empty. */
-static struct range_set_node *
-first_node (const struct range_set *rs)
-{
- return bt_to_rs_node (bt_first (&rs->bt));
-}
-
-/* Returns the next range_set_node in RS after NODE,
- or a null pointer if NODE is the last node in RS. */
-static struct range_set_node *
-next_node (const struct range_set *rs, const struct range_set_node *node)
-{
- return bt_to_rs_node (bt_next (&rs->bt, &node->bt_node));
-}
-
/* Deletes NODE from RS and frees it. */
static void
delete_node (struct range_set *rs, struct range_set_node *node)
@@ -419,7 +382,7 @@ delete_node (struct range_set *rs, struct range_set_node *node)
static struct range_set_node *
delete_node_get_next (struct range_set *rs, struct range_set_node *node)
{
- struct range_set_node *next = next_node (rs, node);
+ struct range_set_node *next = range_set_next__ (rs, node);
delete_node (rs, node);
return next;
}
@@ -434,7 +397,7 @@ find_node_le (const struct range_set *rs, unsigned long int position)
{
struct range_set_node tmp;
tmp.start = position;
- return bt_to_rs_node (bt_find_le (&rs->bt, &tmp.bt_node));
+ return range_set_node_from_bt__ (bt_find_le (&rs->bt, &tmp.bt_node));
}
/* Creates a new region with the given START and END, inserts the
@@ -487,7 +450,8 @@ merge_node_with_successors (struct range_set *rs, struct range_set_node *node)
{
struct range_set_node *next;
- while ((next = next_node (rs, node)) != NULL && node->end >= next->start)
+ while ((next = range_set_next__ (rs, node)) != NULL
+ && node->end >= next->start)
{
if (next->end > node->end)
node->end = next->end;