| /* |
| * Copyright 2008-2009 Katholieke Universiteit Leuven |
| * |
| * Use of this software is governed by the GNU LGPLv2.1 license |
| * |
| * Written by Sven Verdoolaege, K.U.Leuven, Departement |
| * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium |
| */ |
| |
| #include <isl/blk.h> |
| #include <isl_ctx_private.h> |
| |
| /* The maximal number of cache misses before first element is evicted */ |
| #define ISL_BLK_MAX_MISS 100 |
| |
| struct isl_blk isl_blk_empty() |
| { |
| struct isl_blk block; |
| block.size = 0; |
| block.data = NULL; |
| return block; |
| } |
| |
| static int isl_blk_is_empty(struct isl_blk block) |
| { |
| return block.size == 0 && block.data == NULL; |
| } |
| |
| static struct isl_blk isl_blk_error() |
| { |
| struct isl_blk block; |
| block.size = -1; |
| block.data = NULL; |
| return block; |
| } |
| |
| int isl_blk_is_error(struct isl_blk block) |
| { |
| return block.size == -1 && block.data == NULL; |
| } |
| |
| static struct isl_blk extend(struct isl_ctx *ctx, struct isl_blk block, |
| size_t new_n) |
| { |
| int i; |
| isl_int *p; |
| |
| if (block.size >= new_n) |
| return block; |
| |
| p = block.data; |
| block.data = isl_realloc_array(ctx, block.data, isl_int, new_n); |
| if (!block.data) { |
| free(p); |
| return isl_blk_error(); |
| } |
| |
| for (i = block.size; i < new_n; ++i) |
| isl_int_init(block.data[i]); |
| block.size = new_n; |
| |
| return block; |
| } |
| |
| static void isl_blk_free_force(struct isl_ctx *ctx, struct isl_blk block) |
| { |
| int i; |
| |
| for (i = 0; i < block.size; ++i) |
| isl_int_clear(block.data[i]); |
| free(block.data); |
| } |
| |
| struct isl_blk isl_blk_alloc(struct isl_ctx *ctx, size_t n) |
| { |
| int i; |
| struct isl_blk block; |
| |
| block = isl_blk_empty(); |
| if (n && ctx->n_cached) { |
| int best = 0; |
| for (i = 1; ctx->cache[best].size != n && i < ctx->n_cached; ++i) { |
| if (ctx->cache[best].size < n) { |
| if (ctx->cache[i].size > ctx->cache[best].size) |
| best = i; |
| } else if (ctx->cache[i].size >= n && |
| ctx->cache[i].size < ctx->cache[best].size) |
| best = i; |
| } |
| if (ctx->cache[best].size < 2 * n + 100) { |
| block = ctx->cache[best]; |
| if (--ctx->n_cached != best) |
| ctx->cache[best] = ctx->cache[ctx->n_cached]; |
| if (best == 0) |
| ctx->n_miss = 0; |
| } else if (ctx->n_miss++ >= ISL_BLK_MAX_MISS) { |
| isl_blk_free_force(ctx, ctx->cache[0]); |
| if (--ctx->n_cached != 0) |
| ctx->cache[0] = ctx->cache[ctx->n_cached]; |
| ctx->n_miss = 0; |
| } |
| } |
| |
| return extend(ctx, block, n); |
| } |
| |
| struct isl_blk isl_blk_extend(struct isl_ctx *ctx, struct isl_blk block, |
| size_t new_n) |
| { |
| if (isl_blk_is_empty(block)) |
| return isl_blk_alloc(ctx, new_n); |
| |
| return extend(ctx, block, new_n); |
| } |
| |
| void isl_blk_free(struct isl_ctx *ctx, struct isl_blk block) |
| { |
| if (isl_blk_is_empty(block) || isl_blk_is_error(block)) |
| return; |
| |
| if (ctx->n_cached < ISL_BLK_CACHE_SIZE) |
| ctx->cache[ctx->n_cached++] = block; |
| else |
| isl_blk_free_force(ctx, block); |
| } |
| |
| void isl_blk_clear_cache(struct isl_ctx *ctx) |
| { |
| int i; |
| |
| for (i = 0; i < ctx->n_cached; ++i) |
| isl_blk_free_force(ctx, ctx->cache[i]); |
| ctx->n_cached = 0; |
| } |