"Fossies" - the Fresh Open Source Software Archive

Member "libmaxminddb-1.5.2/src/data-pool.c" (18 Feb 2021, 4224 Bytes) of package /linux/misc/libmaxminddb-1.5.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "data-pool.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.5.2.

    1 #include "data-pool.h"
    2 #include "maxminddb.h"
    3 
    4 #include <stdbool.h>
    5 #include <stddef.h>
    6 #include <stdlib.h>
    7 
    8 static bool can_multiply(size_t const, size_t const, size_t const);
    9 
   10 // Allocate an MMDB_data_pool_s. It initially has space for size
   11 // MMDB_entry_data_list_s structs.
   12 MMDB_data_pool_s *data_pool_new(size_t const size) {
   13     MMDB_data_pool_s *const pool = calloc(1, sizeof(MMDB_data_pool_s));
   14     if (!pool) {
   15         return NULL;
   16     }
   17 
   18     if (size == 0 ||
   19         !can_multiply(SIZE_MAX, size, sizeof(MMDB_entry_data_list_s))) {
   20         data_pool_destroy(pool);
   21         return NULL;
   22     }
   23     pool->size = size;
   24     pool->blocks[0] = calloc(pool->size, sizeof(MMDB_entry_data_list_s));
   25     if (!pool->blocks[0]) {
   26         data_pool_destroy(pool);
   27         return NULL;
   28     }
   29     pool->blocks[0]->pool = pool;
   30 
   31     pool->sizes[0] = size;
   32 
   33     pool->block = pool->blocks[0];
   34 
   35     return pool;
   36 }
   37 
   38 // Determine if we can multiply m*n. We can do this if the result will be below
   39 // the given max. max will typically be SIZE_MAX.
   40 //
   41 // We want to know if we'll wrap around.
   42 static bool can_multiply(size_t const max, size_t const m, size_t const n) {
   43     if (m == 0) {
   44         return false;
   45     }
   46 
   47     return n <= max / m;
   48 }
   49 
   50 // Clean up the data pool.
   51 void data_pool_destroy(MMDB_data_pool_s *const pool) {
   52     if (!pool) {
   53         return;
   54     }
   55 
   56     for (size_t i = 0; i <= pool->index; i++) {
   57         free(pool->blocks[i]);
   58     }
   59 
   60     free(pool);
   61 }
   62 
   63 // Claim a new struct from the pool. Doing this may cause the pool's size to
   64 // grow.
   65 MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const pool) {
   66     if (!pool) {
   67         return NULL;
   68     }
   69 
   70     if (pool->used < pool->size) {
   71         MMDB_entry_data_list_s *const element = pool->block + pool->used;
   72         pool->used++;
   73         return element;
   74     }
   75 
   76     // Take it from a new block of memory.
   77 
   78     size_t const new_index = pool->index + 1;
   79     if (new_index == DATA_POOL_NUM_BLOCKS) {
   80         // See the comment about not growing this on DATA_POOL_NUM_BLOCKS.
   81         return NULL;
   82     }
   83 
   84     if (!can_multiply(SIZE_MAX, pool->size, 2)) {
   85         return NULL;
   86     }
   87     size_t const new_size = pool->size * 2;
   88 
   89     if (!can_multiply(SIZE_MAX, new_size, sizeof(MMDB_entry_data_list_s))) {
   90         return NULL;
   91     }
   92     pool->blocks[new_index] = calloc(new_size, sizeof(MMDB_entry_data_list_s));
   93     if (!pool->blocks[new_index]) {
   94         return NULL;
   95     }
   96 
   97     // We don't need to set this, but it's useful for introspection in tests.
   98     pool->blocks[new_index]->pool = pool;
   99 
  100     pool->index = new_index;
  101     pool->block = pool->blocks[pool->index];
  102 
  103     pool->size = new_size;
  104     pool->sizes[pool->index] = pool->size;
  105 
  106     MMDB_entry_data_list_s *const element = pool->block;
  107     pool->used = 1;
  108     return element;
  109 }
  110 
  111 // Turn the structs in the array-like pool into a linked list.
  112 //
  113 // Before calling this function, the list isn't linked up.
  114 MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool) {
  115     if (!pool) {
  116         return NULL;
  117     }
  118 
  119     if (pool->index == 0 && pool->used == 0) {
  120         return NULL;
  121     }
  122 
  123     for (size_t i = 0; i <= pool->index; i++) {
  124         MMDB_entry_data_list_s *const block = pool->blocks[i];
  125 
  126         size_t size = pool->sizes[i];
  127         if (i == pool->index) {
  128             size = pool->used;
  129         }
  130 
  131         for (size_t j = 0; j < size - 1; j++) {
  132             MMDB_entry_data_list_s *const cur = block + j;
  133             cur->next = block + j + 1;
  134         }
  135 
  136         if (i < pool->index) {
  137             MMDB_entry_data_list_s *const last = block + size - 1;
  138             last->next = pool->blocks[i + 1];
  139         }
  140     }
  141 
  142     return pool->blocks[0];
  143 }
  144 
  145 #ifdef TEST_DATA_POOL
  146 
  147 #include <libtap/tap.h>
  148 #include <maxminddb_test_helper.h>
  149 
  150 static void test_can_multiply(void);
  151 
  152 int main(void) {
  153     plan(NO_PLAN);
  154     test_can_multiply();
  155     done_testing();
  156 }
  157 
  158 static void test_can_multiply(void) {
  159     { ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok"); }
  160 
  161     { ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok"); }
  162 
  163     {
  164         ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)),
  165            "1024 entry_data_list_s's are okay");
  166     }
  167 }
  168 
  169 #endif