range-set: New function range_set_allocate_fully.
authorBen Pfaff <blp@gnu.org>
Tue, 5 May 2009 14:03:24 +0000 (07:03 -0700)
committerBen Pfaff <blp@gnu.org>
Sun, 7 Jun 2009 04:11:03 +0000 (21:11 -0700)
src/libpspp/range-set.c
src/libpspp/range-set.h
tests/libpspp/range-set-test.c

index c13fc33f618453aa759c01364fc8e67e5f3edb47..78253be6ad94c8556966cfa61015363b60deb0a0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -274,6 +274,36 @@ 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 = first_node (rs); node != NULL; node = next_node (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
index 83e5db6f8181d2097f14f60b88d3f1ed7b5800bc..665447f697ecb24ab77fa614b55647667f791dc7 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -39,6 +39,8 @@ void range_set_delete (struct range_set *,
                        unsigned long int start, unsigned long int width);
 bool range_set_allocate (struct range_set *, unsigned long int request,
                          unsigned long int *start, unsigned long int *width);
+bool range_set_allocate_fully (struct range_set *, unsigned long int request,
+                               unsigned long int *start);
 bool range_set_contains (const struct range_set *, unsigned long int position);
 
 bool range_set_is_empty (const struct range_set *);
index 894c679726b3f946baac3922448905becff92634..b0eb7abbf81f5249fb2b29131a4a1351e9c2b726 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009 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
@@ -288,6 +288,60 @@ test_allocate (void)
       }
 }
 
+/* Tests all possible full allocations in all possible range sets
+   (up to a small maximum number of bits). */
+static void
+test_allocate_fully (void)
+{
+  const int positions = 9;
+  unsigned int init_pat;
+  int request;
+
+  for (init_pat = 0; init_pat < (1u << positions); init_pat++)
+    for (request = 1; request <= positions + 1; request++)
+      {
+        struct range_set *rs;
+        unsigned long int start, expect_start;
+        bool success, expect_success;
+        unsigned int final_pat;
+        int i;
+
+        /* Figure out expected results. */
+        expect_success = false;
+        expect_start = 0;
+        final_pat = init_pat;
+        for (i = 0; i < positions - request + 1; i++)
+          {
+            int j;
+
+            final_pat = init_pat;
+            for (j = i; j < i + request; j++)
+              {
+                if (!(init_pat & (1u << j)))
+                  goto next;
+                final_pat &= ~(1u << j);
+              }
+
+            expect_success = true;
+            expect_start = i;
+            break;
+          next:
+            final_pat = init_pat;
+          }
+
+        /* Test. */
+        rs = make_pattern (init_pat);
+        success = range_set_allocate_fully (rs, request, &start);
+        check_pattern (rs, final_pat);
+        range_set_destroy (rs);
+
+        /* Check results. */
+        check (success == expect_success);
+        if (expect_success)
+          check (start == expect_start);
+      }
+}
+
 /* Tests freeing a range set through a pool. */
 static void
 test_pool (void)
@@ -329,6 +383,7 @@ main (void)
   run_test (test_insert, "insert");
   run_test (test_delete, "delete");
   run_test (test_allocate, "allocate");
+  run_test (test_allocate_fully, "allocate_fully");
   run_test (test_pool, "pool");
   putchar ('\n');