diff options
| author | bozo.kopic <bozo@kopic.xyz> | 2022-06-27 01:13:26 +0200 |
|---|---|---|
| committer | bozo.kopic <bozo@kopic.xyz> | 2022-06-27 01:13:26 +0200 |
| commit | 8d1d7b7b4a48187f5849548bbc6bb543d6de33ba (patch) | |
| tree | 557eff5ff465d1ff096abbcca0005dca08ca959c /src_c | |
| parent | 75cc60fd42c58cadc28f5eb4499f197604254aba (diff) | |
WIP native implementation
Diffstat (limited to 'src_c')
| -rw-r--r-- | src_c/common.c | 466 | ||||
| -rw-r--r-- | src_c/common.h | 99 | ||||
| -rw-r--r-- | src_c/csp.c | 382 | ||||
| -rw-r--r-- | src_c/csp.h | 25 | ||||
| -rw-r--r-- | src_c/main.c | 159 | ||||
| -rw-r--r-- | src_c/opcut.c | 664 | ||||
| -rw-r--r-- | src_c/opcut.h | 113 | ||||
| -rw-r--r-- | src_c/pool.c | 88 | ||||
| -rw-r--r-- | src_c/pool.h | 22 |
9 files changed, 777 insertions, 1241 deletions
diff --git a/src_c/common.c b/src_c/common.c deleted file mode 100644 index 01df99b..0000000 --- a/src_c/common.c +++ /dev/null @@ -1,466 +0,0 @@ -#define JSMN_PARENT_LINKS - -#include <stdlib.h> -#include <string.h> -#include <jsmn.h> -#include "common.h" - - -static inline bool is_token_val(char *json, jsmntok_t *token, char *val) { - return strncmp(val, json + token->start, token->end - token->start) == 0; -} - - -static int write_number(double val, FILE *stream) { - if (fprintf(stream, "%f", val) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_bool(bool val, FILE *stream) { - if (fputs((val ? "true" : "false"), stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_str(opcut_str_t *str, FILE *stream) { - if (fprintf(stream, "\"%.*s\"", str->len, str->data) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_panel(opcut_panel_t *panel, FILE *stream) { - if (write_str(&(panel->id), stream)) - return OPCUT_ERROR; - - if (fputs(":{\"width\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(panel->width, stream)) - return OPCUT_ERROR; - - if (fputs(",\"height\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(panel->height, stream)) - return OPCUT_ERROR; - - if (fputs("}", stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_item(opcut_item_t *item, FILE *stream) { - if (write_str(&(item->id), stream)) - return OPCUT_ERROR; - - if (fputs(":{\"width\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(item->width, stream)) - return OPCUT_ERROR; - - if (fputs(",\"height\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(item->height, stream)) - return OPCUT_ERROR; - - if (fputs(",\"can_rotate\":", stream) < 0) - return OPCUT_ERROR; - - if (write_bool(item->can_rotate, stream)) - return OPCUT_ERROR; - - if (fputs("}", stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_params(opcut_params_t *params, FILE *stream) { - if (fputs("{\"cut_width\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(params->cut_width, stream)) - return OPCUT_ERROR; - - if (fputs(",\"min_initial_usage\":", stream) < 0) - return OPCUT_ERROR; - - if (write_bool(params->min_initial_usage, stream)) - return OPCUT_ERROR; - - if (fputs(",\"panels\":{", stream) < 0) - return OPCUT_ERROR; - - for (opcut_panel_t *panel = params->panels; panel; panel = panel->next) { - if (write_panel(panel, stream)) - return OPCUT_ERROR; - - if (panel->next) { - if (fputs(",", stream) < 0) - return OPCUT_ERROR; - } - } - - if (fputs("},\"items\":{", stream) < 0) - return OPCUT_ERROR; - - for (opcut_item_t *item = params->items; item; item = item->next) { - if (write_item(item, stream)) - return OPCUT_ERROR; - - if (item->next) { - if (fputs(",", stream) < 0) - return OPCUT_ERROR; - } - } - - if (fputs("}}", stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_used(opcut_used_t *used, FILE *stream) { - if (fputs("{\"panel\":", stream) < 0) - return OPCUT_ERROR; - - if (write_str(&(used->panel->id), stream)) - return OPCUT_ERROR; - - if (fputs(",\"item\":", stream) < 0) - return OPCUT_ERROR; - - if (write_str(&(used->item->id), stream)) - return OPCUT_ERROR; - - if (fputs(",\"x\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(used->x, stream)) - return OPCUT_ERROR; - - if (fputs(",\"y\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(used->y, stream)) - return OPCUT_ERROR; - - if (fputs(",\"rotate\":", stream) < 0) - return OPCUT_ERROR; - - if (write_bool(used->rotate, stream)) - return OPCUT_ERROR; - - if (fputs("}", stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int write_unused(opcut_unused_t *unused, FILE *stream) { - if (fputs("{\"panel\":", stream) < 0) - return OPCUT_ERROR; - - if (write_str(&(unused->panel->id), stream)) - return OPCUT_ERROR; - - if (fputs(",\"width\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(unused->width, stream)) - return OPCUT_ERROR; - - if (fputs(",\"height\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(unused->height, stream)) - return OPCUT_ERROR; - - if (fputs(",\"x\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(unused->x, stream)) - return OPCUT_ERROR; - - if (fputs(",\"y\":", stream) < 0) - return OPCUT_ERROR; - - if (write_number(unused->y, stream)) - return OPCUT_ERROR; - - if (fputs("}", stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int read_number(char *json, double *val, jsmntok_t *token) { - if (token->type != JSMN_PRIMITIVE) - return OPCUT_ERROR; - - if (sscanf(json + token->start, "%lf", val) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} - - -static int read_bool(char *json, bool *val, jsmntok_t *token) { - if (token->type != JSMN_PRIMITIVE) - return OPCUT_ERROR; - - if (json[token->start] == 't') { - *val = true; - return OPCUT_SUCCESS; - } - - if (json[token->start] == 'f') { - *val = false; - return OPCUT_SUCCESS; - } - - return OPCUT_ERROR; -} - - -static int read_string(char *json, opcut_str_t *str, jsmntok_t *token) { - if (token->type != JSMN_STRING) - return OPCUT_ERROR; - - str->data = json + token->start; - str->len = token->end - token->start; - return OPCUT_SUCCESS; -} - - -static int read_panel(char *json, opcut_panel_t *panel, jsmntok_t *tokens, - size_t *pos) { - jsmntok_t *id_token = tokens + ((*pos)++); - jsmntok_t *panel_token = tokens + ((*pos)++); - if (panel_token->type != JSMN_OBJECT) - return OPCUT_ERROR; - - if (read_string(json, &(panel->id), id_token)) - return OPCUT_ERROR; - - panel->width = 0; - panel->height = 0; - - for (size_t i = 0; i < panel_token->size; ++i) { - jsmntok_t *key_token = tokens + ((*pos)++); - jsmntok_t *value_token = tokens + ((*pos)++); - if (key_token->type != JSMN_STRING) - return OPCUT_ERROR; - - if (is_token_val(json, key_token, "width")) { - if (read_number(json, &(panel->width), value_token)) - return OPCUT_ERROR; - - } else if (is_token_val(json, key_token, "height")) { - if (read_number(json, &(panel->height), value_token)) - return OPCUT_ERROR; - } - } - - if (panel->width <= 0 || panel->height <= 0) - return OPCUT_ERROR; - panel->area = panel->width * panel->height; - - return OPCUT_SUCCESS; -} - - -static int read_item(char *json, opcut_item_t *item, jsmntok_t *tokens, - size_t *pos) { - jsmntok_t *id_token = tokens + ((*pos)++); - jsmntok_t *item_token = tokens + ((*pos)++); - if (item_token->type != JSMN_OBJECT) - return OPCUT_ERROR; - - if (read_string(json, &(item->id), id_token)) - return OPCUT_ERROR; - - item->width = 0; - item->height = 0; - item->can_rotate = false; - - for (size_t i = 0; i < item_token->size; ++i) { - jsmntok_t *key_token = tokens + ((*pos)++); - jsmntok_t *value_token = tokens + ((*pos)++); - if (key_token->type != JSMN_STRING) - return OPCUT_ERROR; - - if (is_token_val(json, key_token, "width")) { - if (read_number(json, &(item->width), value_token)) - return OPCUT_ERROR; - - } else if (is_token_val(json, key_token, "height")) { - if (read_number(json, &(item->height), value_token)) - return OPCUT_ERROR; - - } else if (is_token_val(json, key_token, "can_rotate")) { - if (read_bool(json, &(item->can_rotate), value_token)) - return OPCUT_ERROR; - } - } - - if (item->width <= 0 || item->height <= 0) - return OPCUT_ERROR; - item->area = item->width * item->height; - - return OPCUT_SUCCESS; -} - - -static int read_params(opcut_params_t *params, char *json, jsmntok_t *tokens, - size_t *pos) { - jsmntok_t *params_token = tokens + ((*pos)++); - if (params_token->type != JSMN_OBJECT) - return OPCUT_ERROR; - - params->cut_width = 0; - params->min_initial_usage = false; - params->panels = NULL; - params->items = NULL; - params->panels_area = 0; - - for (size_t i = 0; i < params_token->size; ++i) { - jsmntok_t *key_token = tokens + ((*pos)++); - jsmntok_t *value_token = tokens + ((*pos)++); - if (key_token->type != JSMN_STRING) - return OPCUT_ERROR; - - if (is_token_val(json, key_token, "cut_width")) { - if (read_number(json, &(params->cut_width), value_token)) - return OPCUT_ERROR; - - } else if (is_token_val(json, key_token, "min_initial_usage")) { - if (read_bool(json, &(params->min_initial_usage), value_token)) - return OPCUT_ERROR; - - } else if (is_token_val(json, key_token, "panels")) { - if (value_token->type != JSMN_OBJECT) - return OPCUT_ERROR; - - for (size_t j = 0; j < value_token->size; ++j) { - opcut_panel_t *panel = opcut_pool_alloc(params->panel_pool); - if (!panel) - return OPCUT_ERROR; - - if (read_panel(json, panel, tokens, pos)) - return OPCUT_ERROR; - - panel->next = params->panels; - params->panels = panel; - params->panels_area += panel->area; - } - - } else if (is_token_val(json, key_token, "items")) { - if (value_token->type != JSMN_OBJECT) - return OPCUT_ERROR; - - for (size_t j = 0; j < value_token->size; ++j) { - opcut_item_t *item = opcut_pool_alloc(params->item_pool); - if (!item) - return OPCUT_ERROR; - - if (read_item(json, item, tokens, pos)) - return OPCUT_ERROR; - - item->next = params->items; - params->items = item; - } - } - } - - return OPCUT_SUCCESS; -} - - -int opcut_params_init(hat_allocator_t *a, opcut_params_t *params, - opcut_pool_t *panel_pool, opcut_pool_t *item_pool, - opcut_str_t *json) { - params->panel_pool = panel_pool; - params->item_pool = item_pool; - - jsmn_parser parser; - int tokens_len; - - jsmn_init(&parser); - tokens_len = jsmn_parse(&parser, json->data, json->len, NULL, 0); - if (tokens_len < 0) - return OPCUT_ERROR; - - jsmntok_t *tokens = hat_allocator_alloc(a, tokens_len * sizeof(jsmntok_t)); - if (!tokens) - return OPCUT_ERROR; - - jsmn_init(&parser); - tokens_len = jsmn_parse(&parser, json->data, json->len, tokens, tokens_len); - if (tokens_len < 0) { - hat_allocator_free(a, tokens); - return OPCUT_ERROR; - } - - size_t pos = 0; - int err = read_params(params, json->data, tokens, &pos); - - hat_allocator_free(a, tokens); - return err; -} - - -int opcut_result_write(opcut_result_t *result, FILE *stream) { - if (fputs("{\"params\":", stream) < 0) - return OPCUT_ERROR; - - if (write_params(result->params, stream)) - return OPCUT_ERROR; - - if (fputs(",\"used\":[", stream) < 0) - return OPCUT_ERROR; - - for (opcut_used_t *used = result->used; used; used = used->next) { - if (write_used(used, stream)) - return OPCUT_ERROR; - - if (used->next) { - if (fputs(",", stream) < 0) - return OPCUT_ERROR; - } - } - - if (fputs("],\"unused\":[", stream) < 0) - return OPCUT_ERROR; - - for (opcut_unused_t *unused = result->unused; unused; - unused = unused->next) { - if (write_unused(unused, stream)) - return OPCUT_ERROR; - - if (unused->next) { - if (fputs(",", stream) < 0) - return OPCUT_ERROR; - } - } - - if (fputs("]}\n", stream) < 0) - return OPCUT_ERROR; - - return OPCUT_SUCCESS; -} diff --git a/src_c/common.h b/src_c/common.h deleted file mode 100644 index 5f0b976..0000000 --- a/src_c/common.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef OPCUT_COMMON_H -#define OPCUT_COMMON_H - -#include <stdbool.h> -#include <stdio.h> -#include <hat/allocator.h> -#include "pool.h" - -#define OPCUT_SUCCESS 0 -#define OPCUT_ERROR 1 -#define OPCUT_UNSOLVABLE 42 - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - char *data; - size_t len; -} opcut_str_t; - -typedef struct opcut_panel_t { - opcut_str_t id; - double width; - double height; - - // internal - struct opcut_panel_t *next; - double area; -} opcut_panel_t; - -typedef struct opcut_item_t { - opcut_str_t id; - double width; - double height; - bool can_rotate; - - // internal - struct opcut_item_t *next; - double area; -} opcut_item_t; - -typedef struct { - double cut_width; - bool min_initial_usage; - opcut_panel_t *panels; - opcut_item_t *items; - - // internal - opcut_pool_t *panel_pool; - opcut_pool_t *item_pool; - double panels_area; -} opcut_params_t; - -typedef struct opcut_used_t { - opcut_panel_t *panel; - opcut_item_t *item; - double x; - double y; - bool rotate; - - // internal - struct opcut_used_t *next; -} opcut_used_t; - -typedef struct opcut_unused_t { - opcut_panel_t *panel; - double width; - double height; - double x; - double y; - - // internal - struct opcut_unused_t *next; - double area; - bool initial; -} opcut_unused_t; - -typedef struct { - opcut_params_t *params; - opcut_used_t *used; - opcut_unused_t *unused; - - // internal - opcut_pool_t *used_pool; - opcut_pool_t *unused_pool; -} opcut_result_t; - - -int opcut_params_init(hat_allocator_t *a, opcut_params_t *params, - opcut_pool_t *panel_pool, opcut_pool_t *item_pool, - opcut_str_t *json); -int opcut_result_write(opcut_result_t *result, FILE *stream); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src_c/csp.c b/src_c/csp.c deleted file mode 100644 index 7d837bf..0000000 --- a/src_c/csp.c +++ /dev/null @@ -1,382 +0,0 @@ -#include "csp.h" -#include "common.h" - - -#define FITNESS_K 0.03 - - -typedef struct { - size_t unused_initial_count; - double fitness; -} fitness_t; - - -static void sort_panels(opcut_panel_t **first, opcut_panel_t **last) { - if (!*first) { - if (last) - *last = NULL; - return; - } - - opcut_panel_t *pivot_first = *first; - opcut_panel_t *pivot_last = *first; - opcut_panel_t *left_first = NULL; - opcut_panel_t *right_first = NULL; - - for (opcut_panel_t *panel = (*first)->next; panel;) { - opcut_panel_t *next = panel->next; - if (panel->area > pivot_first->area) { - panel->next = left_first; - left_first = panel; - } else if (panel->area < pivot_first->area) { - panel->next = right_first; - right_first = panel; - } else { - pivot_last->next = panel; - pivot_last = panel; - } - panel = next; - } - - opcut_panel_t *left_last; - opcut_panel_t *right_last; - sort_panels(&left_first, &left_last); - sort_panels(&right_first, &right_last); - - *first = (left_first ? left_first : pivot_first); - if (left_last) - left_last->next = pivot_first; - pivot_last->next = right_first; - if (last) - *last = (right_last ? right_last : pivot_last); -} - - -static void sort_items(opcut_item_t **first, opcut_item_t **last) { - if (!*first) { - if (last) - *last = NULL; - return; - } - - opcut_item_t *pivot_first = *first; - opcut_item_t *pivot_last = *first; - opcut_item_t *left_first = NULL; - opcut_item_t *right_first = NULL; - - for (opcut_item_t *item = (*first)->next; item;) { - opcut_item_t *next = item->next; - if (item->area > pivot_first->area) { - item->next = left_first; - left_first = item; - } else if (item->area < pivot_first->area) { - item->next = right_first; - right_first = item; - } else { - pivot_last->next = item; - pivot_last = item; - } - item = next; - } - - opcut_item_t *left_last; - opcut_item_t *right_last; - sort_items(&left_first, &left_last); - sort_items(&right_first, &right_last); - - *first = (left_first ? left_first : pivot_first); - if (left_last) - left_last->next = pivot_first; - pivot_last->next = right_first; - if (last) - *last = (right_last ? right_last : pivot_last); -} - - -static inline int compare_fitness(fitness_t *f1, fitness_t *f2) { - return (f1->unused_initial_count == f2->unused_initial_count - ? f1->fitness - f2->fitness - : f1->unused_initial_count - f2->unused_initial_count); -} - - -static void calculate_fitness(opcut_result_t *result, fitness_t *fitness) { - fitness->fitness = 0; - - for (opcut_panel_t *panel = result->params->panels; panel; - panel = panel->next) { - double min_used_area = 0; - double used_areas = 0; - for (opcut_used_t *used = result->used; used; used = used->next) { - if (used->panel != panel) - continue; - if (min_used_area == 0 || used->item->area < min_used_area) - min_used_area = used->item->area; - used_areas = used->item->area; - } - - double max_unused_area = 0; - for (opcut_unused_t *unused = result->unused; unused; - unused = unused->next) { - if (unused->panel != panel) - continue; - if (max_unused_area == 0 || unused->area > max_unused_area) - max_unused_area = unused->area; - } - - fitness->fitness += - (panel->area - used_areas) / result->params->panels_area; - fitness->fitness -= - FITNESS_K * min_used_area * max_unused_area / - (result->params->panels_area * result->params->panels_area); - } - - fitness->unused_initial_count = 0; - if (result->params->min_initial_usage) { - for (opcut_unused_t *unused = result->unused; unused; - unused = unused->next) { - if (unused->initial) - fitness->unused_initial_count += 1; - } - } -} - - -static inline bool item_fits_unused(opcut_item_t *item, opcut_unused_t *unused, - bool rotate) { - if (rotate && !item->can_rotate) - return false; - - double item_width = (rotate ? item->height : item->width); - double item_height = (rotate ? item->width : item->height); - - return unused->height >= item_height && unused->width >= item_width; -} - - -static int cut_item_from_unused(opcut_result_t *result, opcut_item_t *item, - opcut_unused_t *unused, bool rotate, - bool vertical) { - double item_width = (rotate ? item->height : item->width); - double item_height = (rotate ? item->width : item->height); - if (unused->height < item_height || unused->width < item_width) - return OPCUT_ERROR; - - opcut_used_t *used = opcut_pool_alloc(result->used_pool); - if (!used) - return OPCUT_ERROR; - *used = (opcut_used_t){.panel = unused->panel, - .item = item, - .x = unused->x, - .y = unused->y, - .rotate = rotate, - .next = result->used}; - result->used = used; - - - double width; - double height; - - width = unused->width - item_width - result->params->cut_width; - if (width > 0) { - height = (vertical ? unused->height : item_height); - opcut_unused_t *new_unused = opcut_pool_alloc(result->unused_pool); - if (!new_unused) - return OPCUT_ERROR; - *new_unused = (opcut_unused_t){.panel = unused->panel, - .width = width, - .height = height, - .x = unused->x + item_width + - result->params->cut_width, - .y = unused->y, - .next = result->unused, - .area = width * height, - .initial = false}; - result->unused = new_unused; - } - - height = unused->height - item_height - result->params->cut_width; - if (height > 0) { - width = (vertical ? item_width : unused->width); - opcut_unused_t *new_unused = opcut_pool_alloc(result->unused_pool); - if (!new_unused) - return OPCUT_ERROR; - *new_unused = (opcut_unused_t){.panel = unused->panel, - .width = width, - .height = height, - .x = unused->x, - .y = unused->y + item_height + - result->params->cut_width, - .next = result->unused, - .area = width * height, - .initial = false}; - result->unused = new_unused; - } - - return OPCUT_SUCCESS; -} - - -static int copy_unused(opcut_result_t *result, opcut_unused_t *exclude) { - opcut_unused_t *unused = NULL; - for (opcut_unused_t *i = result->unused; i; i = i->next) { - if (i == exclude) - continue; - - opcut_unused_t *temp = opcut_pool_alloc(result->unused_pool); - if (!temp) - return OPCUT_ERROR; - - *temp = *i; - temp->next = unused; - unused = temp; - } - - result->unused = NULL; - while (unused) { - opcut_unused_t *next = unused->next; - unused->next = result->unused; - result->unused = unused; - unused = next; - } - - return OPCUT_SUCCESS; -} - - -static void free_unused(opcut_result_t *result) { - while (result->unused) { - opcut_unused_t *next = result->unused->next; - opcut_pool_free(result->unused_pool, result->unused); - result->unused = next; - } -} - - -static void free_used(opcut_result_t *result, opcut_used_t *last_used) { - while (result->used && result->used != last_used) { - opcut_used_t *next = result->used->next; - opcut_pool_free(result->used_pool, result->used); - result->used = next; - } -} - - -static int calculate_greedy(opcut_result_t *result, opcut_item_t *items, - bool forward_greedy) { - for (opcut_item_t *item = items; item; item = item->next) { - opcut_result_t best_result; - fitness_t best_fitness; - bool solvable = false; - - for (opcut_unused_t *unused = result->unused; unused; - unused = unused->next) { - for (size_t rotate = 0; rotate < 2; ++rotate) { - if (!item_fits_unused(item, unused, rotate)) - continue; - - for (size_t vertical = 0; vertical < 2; ++vertical) { - opcut_result_t temp_result = *result; - if (copy_unused(&temp_result, unused)) - return OPCUT_ERROR; - - if (cut_item_from_unused(&temp_result, item, unused, rotate, - vertical)) - return OPCUT_ERROR; - - fitness_t temp_fitness; - if (!forward_greedy) { - calculate_fitness(&temp_result, &temp_fitness); - - } else { - opcut_result_t greedy_result = temp_result; - if (copy_unused(&greedy_result, temp_result.unused)) - return OPCUT_ERROR; - - int err = - calculate_greedy(&greedy_result, item->next, false); - - if (!err) { - calculate_fitness(&greedy_result, &temp_fitness); - free_used(&greedy_result, temp_result.used); - free_unused(&greedy_result); - - } else if (err == OPCUT_UNSOLVABLE) { - free_used(&greedy_result, temp_result.used); - free_used(&temp_result, result->used); - free_unused(&greedy_result); - free_unused(&temp_result); - continue; - - } else { - return err; - } - } - - if (!solvable) { - best_result = temp_result; - best_fitness = temp_fitness; - solvable = true; - - } else if (compare_fitness(&temp_fitness, &best_fitness) < - 0) { - free_used(&best_result, result->used); - free_unused(&best_result); - best_result = temp_result; - best_fitness = temp_fitness; - - } else { - free_used(&temp_result, result->used); - free_unused(&temp_result); - } - } - } - } - - if (!solvable) - return OPCUT_UNSOLVABLE; - - free_unused(result); - *result = best_result; - } - - return OPCUT_SUCCESS; -} - - -int opcut_calculate(opcut_pool_t *used_pool, opcut_pool_t *unused_pool, - opcut_method_t method, opcut_params_t *params, - opcut_result_t *result) { - result->used_pool = used_pool; - result->unused_pool = unused_pool; - result->params = params; - result->used = NULL; - result->unused = NULL; - - sort_panels(&(params->panels), NULL); - sort_items(&(params->items), NULL); - - for (opcut_panel_t *panel = params->panels; panel; panel = panel->next) { - opcut_unused_t *unused = opcut_pool_alloc(unused_pool); - if (!unused) - return OPCUT_ERROR; - - *unused = (opcut_unused_t){.panel = panel, - .width = panel->width, - .height = panel->height, - .x = 0, - .y = 0, - .next = result->unused, - .area = panel->area, - .initial = true}; - result->unused = unused; - } - - if (method == OPCUT_METHOD_GREEDY) - return calculate_greedy(result, params->items, false); - - if (method == OPCUT_METHOD_FORWARD_GREEDY) - return calculate_greedy(result, params->items, true); - - return OPCUT_ERROR; -} diff --git a/src_c/csp.h b/src_c/csp.h deleted file mode 100644 index c88c749..0000000 --- a/src_c/csp.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef OPCUT_CSP_H -#define OPCUT_CSP_H - -#include <stddef.h> -#include "common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - OPCUT_METHOD_GREEDY, - OPCUT_METHOD_FORWARD_GREEDY -} opcut_method_t; - - -int opcut_calculate(opcut_pool_t *used_pool, opcut_pool_t *unused_pool, - opcut_method_t method, opcut_params_t *params, - opcut_result_t *result); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src_c/main.c b/src_c/main.c deleted file mode 100644 index d49db74..0000000 --- a/src_c/main.c +++ /dev/null @@ -1,159 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <argparse.h> -#include <hat/libc_allocator.h> -#include "csp.h" - - -typedef struct { - opcut_method_t method; - char *input_path; - char *output_path; -} args_t; - - -static int parse_args(args_t *args, int argc, char **argv) { - char *method = NULL; - char *output_path = NULL; - - char *usages[] = { - "opcut-calculate [options] [[--] -|path]", - NULL, - }; - - struct argparse_option options[] = { - OPT_HELP(), OPT_STRING(0, "method", &method, "calculate method"), - OPT_STRING(0, "output", &output_path, "output path"), OPT_END()}; - - struct argparse argparse; - argparse_init(&argparse, options, (const char *const *)usages, 0); - argc = argparse_parse(&argparse, argc, (const char **)argv); - - if (method && strcmp(method, "greedy") == 0) { - args->method = OPCUT_METHOD_GREEDY; - } else if (method && strcmp(method, "forward_greedy") == 0) { - args->method = OPCUT_METHOD_FORWARD_GREEDY; - } else { - return OPCUT_ERROR; - } - - if (!argc) { - args->input_path = NULL; - } else if (argc == 1) { - if (strcmp(argv[0], "-") == 0) { - args->input_path = NULL; - } else { - args->input_path = argv[0]; - } - } else { - return OPCUT_ERROR; - } - - if (output_path && strcmp(output_path, "-") == 0) { - args->output_path = NULL; - } else { - args->output_path = output_path; - } - - return OPCUT_SUCCESS; -} - - -static int read_stream(hat_allocator_t *a, FILE *stream, opcut_str_t *json) { - size_t size = 0; - - while (!(json->len < size)) { - size += 4096; - char *data = hat_allocator_realloc(a, size, json->data); - if (!data) - return OPCUT_ERROR; - - json->data = data; - json->len += fread(json->data + json->len, 1, size - json->len, stream); - } - - return OPCUT_SUCCESS; -} - - -int main(int argc, char **argv) { - hat_allocator_t *a = &hat_libc_allocator; - opcut_pool_t *panel_pool = opcut_pool_create(a, sizeof(opcut_panel_t)); - opcut_pool_t *item_pool = opcut_pool_create(a, sizeof(opcut_item_t)); - opcut_pool_t *used_pool = opcut_pool_create(a, sizeof(opcut_used_t)); - opcut_pool_t *unused_pool = opcut_pool_create(a, sizeof(opcut_unused_t)); - - args_t args; - FILE *input_stream = NULL; - FILE *output_stream = NULL; - opcut_str_t json = {.data = NULL, .len = 0}; - opcut_params_t params; - opcut_result_t result; - int exit_code; - - if (!panel_pool || !item_pool || !used_pool || !unused_pool) { - fprintf(stderr, "error creating memory pools\n"); - goto cleanup; - } - - exit_code = parse_args(&args, argc, argv); - if (exit_code) { - fprintf(stderr, "error parsing command line arguments\n"); - goto cleanup; - } - - input_stream = (args.input_path ? fopen(args.input_path, "r") : stdin); - if (!input_stream) { - fprintf(stderr, "error opening input stream\n"); - exit_code = OPCUT_ERROR; - goto cleanup; - } - - output_stream = (args.output_path ? fopen(args.output_path, "w") : stdout); - if (!output_stream) { - fprintf(stderr, "error opening output stream\n"); - exit_code = OPCUT_ERROR; - goto cleanup; - } - - exit_code = read_stream(a, input_stream, &json); - if (exit_code) { - fprintf(stderr, "error reading input stream\n"); - goto cleanup; - } - - exit_code = opcut_params_init(a, ¶ms, panel_pool, item_pool, &json); - if (exit_code) { - fprintf(stderr, "error parsing calculation parameters\n"); - goto cleanup; - } - - exit_code = - opcut_calculate(used_pool, unused_pool, args.method, ¶ms, &result); - if (exit_code) { - fprintf(stderr, "calculation error\n"); - goto cleanup; - } - - exit_code = opcut_result_write(&result, output_stream); - -cleanup: - - if (json.data) - hat_allocator_free(a, json.data); - if (output_stream) - fclose(output_stream); - if (input_stream) - fclose(input_stream); - if (unused_pool) - opcut_pool_destroy(unused_pool); - if (used_pool) - opcut_pool_destroy(used_pool); - if (item_pool) - opcut_pool_destroy(item_pool); - if (panel_pool) - opcut_pool_destroy(panel_pool); - - return exit_code; -} diff --git a/src_c/opcut.c b/src_c/opcut.c new file mode 100644 index 0000000..43345d3 --- /dev/null +++ b/src_c/opcut.c @@ -0,0 +1,664 @@ +#include "opcut.h" + +#define PAGE_SIZE 4096 +#define FITNESS_K 0.03 + + +typedef struct mem_header_t { + struct mem_header_t *next; +} mem_header_t; + +typedef struct { + opcut_malloc_t malloc; + opcut_free_t free; + size_t item_size; + mem_header_t *blocks; + mem_header_t *items; +} mem_pool_t; + +struct opcut_allocator_t { + opcut_free_t free; + mem_pool_t *panel; + mem_pool_t *item; + mem_pool_t *params; + mem_pool_t *used; + mem_pool_t *unused; + mem_pool_t *result; +}; + +typedef struct { + size_t unused_initial_count; + double fitness; +} fitness_t; + + +static void mem_pool_add_block(mem_pool_t *pool) { + size_t items_per_block = (PAGE_SIZE - sizeof(mem_header_t)) / + (sizeof(mem_header_t) + pool->item_size); + if (items_per_block < 1) + items_per_block = 1; + + mem_header_t *block = pool->malloc( + sizeof(mem_header_t) + + items_per_block * (sizeof(mem_header_t) + pool->item_size)); + if (!block) + return; + block->next = pool->blocks; + pool->blocks = block; + + for (size_t i = 0; i < items_per_block; ++i) { + mem_header_t *header = (void *)block + sizeof(mem_header_t) + + i * (sizeof(mem_header_t) + pool->item_size); + header->next = pool->items; + pool->items = header; + } +} + + +static mem_pool_t *mem_pool_create(opcut_malloc_t malloc, opcut_free_t free, + size_t item_size) { + mem_pool_t *pool = malloc(sizeof(mem_pool_t)); + if (!pool) + return NULL; + + if (item_size % sizeof(void *) != 0) + item_size += sizeof(void *) - (item_size % sizeof(void *)); + + pool->malloc = malloc; + pool->free = free; + pool->item_size = item_size; + pool->blocks = NULL; + pool->items = NULL; + + return pool; +} + + +static void mem_pool_destroy(mem_pool_t *pool) { + while (pool->blocks) { + mem_header_t *block = pool->blocks; + pool->blocks = block->next; + pool->free(block); + } + pool->free(pool); +} + + +static void *mem_pool_alloc(mem_pool_t *pool) { + if (!pool->items) + mem_pool_add_block(pool); + + if (!pool->items) + return NULL; + + mem_header_t *header = pool->items; + pool->items = header->next; + return header + 1; +} + + +static void mem_pool_free(mem_pool_t *pool, void *item) { + mem_header_t *header = (mem_header_t *)item - 1; + header->next = pool->items; + pool->items = header; +} + + +static void sort_items(opcut_item_t **first, opcut_item_t **last) { + if (!*first) { + if (last) + *last = NULL; + return; + } + + opcut_item_t *pivot_first = *first; + opcut_item_t *pivot_last = *first; + opcut_item_t *left_first = NULL; + opcut_item_t *right_first = NULL; + + for (opcut_item_t *item = (*first)->next; item;) { + opcut_item_t *next = item->next; + if (item->area > pivot_first->area) { + item->next = left_first; + left_first = item; + } else if (item->area < pivot_first->area) { + item->next = right_first; + right_first = item; + } else { + pivot_last->next = item; + pivot_last = item; + } + item = next; + } + + opcut_item_t *left_last; + opcut_item_t *right_last; + sort_items(&left_first, &left_last); + sort_items(&right_first, &right_last); + + *first = (left_first ? left_first : pivot_first); + if (left_last) + left_last->next = pivot_first; + pivot_last->next = right_first; + if (last) + *last = (right_last ? right_last : pivot_last); +} + + +static void sort_unused(opcut_unused_t **first, opcut_unused_t **last) { + if (!*first) { + if (last) + *last = NULL; + return; + } + + opcut_unused_t *pivot_first = *first; + opcut_unused_t *pivot_last = *first; + opcut_unused_t *left_first = NULL; + opcut_unused_t *right_first = NULL; + + for (opcut_unused_t *unused = (*first)->next; unused;) { + opcut_unused_t *next = unused->next; + if (unused->area > pivot_first->area) { + unused->next = left_first; + left_first = unused; + } else if (unused->area < pivot_first->area) { + unused->next = right_first; + right_first = unused; + } else { + pivot_last->next = unused; + pivot_last = unused; + } + unused = next; + } + + opcut_unused_t *left_last; + opcut_unused_t *right_last; + sort_unused(&left_first, &left_last); + sort_unused(&right_first, &right_last); + + *first = (left_first ? left_first : pivot_first); + if (left_last) + left_last->next = pivot_first; + pivot_last->next = right_first; + if (last) + *last = (right_last ? right_last : pivot_last); +} + + +static inline int compare_fitness(fitness_t *f1, fitness_t *f2) { + return (f1->unused_initial_count == f2->unused_initial_count + ? f1->fitness - f2->fitness + : f1->unused_initial_count - f2->unused_initial_count); +} + + +static void calculate_fitness(opcut_result_t *result, fitness_t *fitness) { + fitness->fitness = 0; + + for (opcut_panel_t *panel = result->params->panels; panel; + panel = panel->next) { + double min_used_area = 0; + double used_areas = 0; + for (opcut_used_t *used = result->used; used; used = used->next) { + if (used->panel != panel) + continue; + if (min_used_area == 0 || used->item->area < min_used_area) + min_used_area = used->item->area; + used_areas = used->item->area; + } + + double max_unused_area = 0; + for (opcut_unused_t *unused = result->unused; unused; + unused = unused->next) { + if (unused->panel != panel) + continue; + if (max_unused_area == 0 || unused->area > max_unused_area) + max_unused_area = unused->area; + } + + fitness->fitness += + (panel->area - used_areas) / result->params->panels_area; + fitness->fitness -= + FITNESS_K * min_used_area * max_unused_area / + (result->params->panels_area * result->params->panels_area); + } + + fitness->unused_initial_count = 0; + if (result->params->min_initial_usage) { + for (opcut_unused_t *unused = result->unused; unused; + unused = unused->next) { + if (unused->initial) + fitness->unused_initial_count += 1; + } + } +} + + +static inline bool item_fits_unused(opcut_item_t *item, opcut_unused_t *unused, + bool rotate) { + if (rotate && !item->can_rotate) + return false; + + double item_width = (rotate ? item->height : item->width); + double item_height = (rotate ? item->width : item->height); + + return unused->height >= item_height && unused->width >= item_width; +} + + +static int cut_item_from_unused(opcut_allocator_t *a, opcut_result_t *result, + opcut_item_t *item, opcut_unused_t *unused, + bool rotate, bool vertical) { + double item_width = (rotate ? item->height : item->width); + double item_height = (rotate ? item->width : item->height); + if (unused->height < item_height || unused->width < item_width) + return OPCUT_ERROR; + + opcut_used_t *used = mem_pool_alloc(a->used); + if (!used) + return OPCUT_ERROR; + *used = (opcut_used_t){.panel = unused->panel, + .item = item, + .x = unused->x, + .y = unused->y, + .rotate = rotate, + .next = result->used}; + result->used = used; + + + double width; + double height; + + width = unused->width - item_width - result->params->cut_width; + if (width > 0) { + height = (vertical ? unused->height : item_height); + opcut_unused_t *new_unused = mem_pool_alloc(a->unused); + if (!new_unused) + return OPCUT_ERROR; + *new_unused = (opcut_unused_t){.panel = unused->panel, + .width = width, + .height = height, + .x = unused->x + item_width + + result->params->cut_width, + .y = unused->y, + .next = result->unused, + .area = width * height, + .initial = false}; + result->unused = new_unused; + } + + height = unused->height - item_height - result->params->cut_width; + if (height > 0) { + width = (vertical ? item_width : unused->width); + opcut_unused_t *new_unused = mem_pool_alloc(a->unused); + if (!new_unused) + return OPCUT_ERROR; + *new_unused = (opcut_unused_t){.panel = unused->panel, + .width = width, + .height = height, + .x = unused->x, + .y = unused->y + item_height + + result->params->cut_width, + .next = result->unused, + .area = width * height, + .initial = false}; + result->unused = new_unused; + } + + return OPCUT_SUCCESS; +} + + +static int copy_unused(opcut_allocator_t *a, opcut_result_t *result, + opcut_unused_t *exclude) { + opcut_unused_t *unused = NULL; + for (opcut_unused_t *i = result->unused; i; i = i->next) { + if (i == exclude) + continue; + + opcut_unused_t *temp = mem_pool_alloc(a->unused); + if (!temp) + return OPCUT_ERROR; + + *temp = *i; + temp->next = unused; + unused = temp; + } + + result->unused = NULL; + while (unused) { + opcut_unused_t *next = unused->next; + unused->next = result->unused; + result->unused = unused; + unused = next; + } + + return OPCUT_SUCCESS; +} + + +static void free_unused(opcut_allocator_t *a, opcut_result_t *result) { + while (result->unused) { + opcut_unused_t *next = result->unused->next; + mem_pool_free(a->unused, result->unused); + result->unused = next; + } +} + + +static void free_used(opcut_allocator_t *a, opcut_result_t *result, + opcut_used_t *last_used) { + while (result->used && result->used != last_used) { + opcut_used_t *next = result->used->next; + mem_pool_free(a->used, result->used); + result->used = next; + } +} + + +static int calculate_greedy(opcut_allocator_t *a, opcut_result_t *result, + opcut_item_t *items, bool forward_greedy) { + for (opcut_item_t *item = items; item; item = item->next) { + opcut_result_t best_result; + fitness_t best_fitness; + bool solvable = false; + + for (opcut_unused_t *unused = result->unused; unused; + unused = unused->next) { + for (size_t rotate = 0; rotate < 2; ++rotate) { + if (!item_fits_unused(item, unused, rotate)) + continue; + + for (size_t vertical = 0; vertical < 2; ++vertical) { + opcut_result_t temp_result = *result; + if (copy_unused(a, &temp_result, unused)) + return OPCUT_ERROR; + + if (cut_item_from_unused(a, &temp_result, item, unused, + rotate, vertical)) + return OPCUT_ERROR; + + fitness_t temp_fitness; + if (!forward_greedy) { + calculate_fitness(&temp_result, &temp_fitness); + + } else { + opcut_result_t greedy_result = temp_result; + if (copy_unused(a, &greedy_result, temp_result.unused)) + return OPCUT_ERROR; + + int err = calculate_greedy(a, &greedy_result, + item->next, false); + + if (!err) { + calculate_fitness(&greedy_result, &temp_fitness); + free_used(a, &greedy_result, temp_result.used); + free_unused(a, &greedy_result); + + } else if (err == OPCUT_UNSOLVABLE) { + free_used(a, &greedy_result, temp_result.used); + free_used(a, &temp_result, result->used); + free_unused(a, &greedy_result); + free_unused(a, &temp_result); + continue; + + } else { + return err; + } + } + + if (!solvable) { + best_result = temp_result; + best_fitness = temp_fitness; + solvable = true; + + } else if (compare_fitness(&temp_fitness, &best_fitness) < + 0) { + free_used(a, &best_result, result->used); + free_unused(a, &best_result); + best_result = temp_result; + best_fitness = temp_fitness; + + } else { + free_used(a, &temp_result, result->used); + free_unused(a, &temp_result); + } + } + } + } + + if (!solvable) + return OPCUT_UNSOLVABLE; + + free_unused(a, result); + *result = best_result; + } + + return OPCUT_SUCCESS; +} + + +opcut_allocator_t *opcut_allocator_create(opcut_malloc_t malloc, + opcut_free_t free) { + opcut_allocator_t *a = malloc(sizeof(opcut_allocator_t)); + if (!a) + return NULL; + + a->free = free; + a->panel = NULL; + a->item = NULL; + a->params = NULL; + a->used = NULL; + a->unused = NULL; + a->result = NULL; + + a->panel = mem_pool_create(malloc, free, sizeof(opcut_panel_t)); + if (!a->panel) + goto error_cleanup; + + a->item = mem_pool_create(malloc, free, sizeof(opcut_item_t)); + if (!a->item) + goto error_cleanup; + + a->params = mem_pool_create(malloc, free, sizeof(opcut_params_t)); + if (!a->params) + goto error_cleanup; + + a->used = mem_pool_create(malloc, free, sizeof(opcut_used_t)); + if (!a->used) + goto error_cleanup; + + a->unused = mem_pool_create(malloc, free, sizeof(opcut_unused_t)); + if (!a->unused) + goto error_cleanup; + + a->result = mem_pool_create(malloc, free, sizeof(opcut_result_t)); + if (!a->result) + goto error_cleanup; + + return a; + +error_cleanup: + opcut_allocator_destroy(a); + return NULL; +} + + +void opcut_allocator_destroy(opcut_allocator_t *a) { + if (a->panel) + a->free(a->panel); + + if (a->item) + a->free(a->item); + + if (a->params) + a->free(a->params); + + if (a->used) + a->free(a->used); + + if (a->unused) + a->free(a->unused); + + if (a->result) + a->free(a->result); + + a->free(a); +} + + +opcut_panel_t *opcut_panel_create(opcut_allocator_t *a, char *id, double width, + double height, opcut_panel_t *next) { + opcut_panel_t *panel = mem_pool_alloc(a->panel); + if (!panel) + return NULL; + + panel->id = id; + panel->width = width; + panel->height = height; + panel->next = next; + panel->area = width * height; + + return panel; +} + + +opcut_item_t *opcut_item_create(opcut_allocator_t *a, char *id, double width, + double height, bool can_rotate, + opcut_item_t *next) { + opcut_item_t *item = mem_pool_alloc(a->item); + if (!item) + return NULL; + + item->id = id; + item->width = width; + item->height = height; + item->can_rotate = can_rotate; + item->next = next; + item->area = width * height; + + return item; +} + + +opcut_params_t *opcut_params_create(opcut_allocator_t *a, double cut_width, + bool min_initial_usage, + opcut_panel_t *panels, + opcut_item_t *items) { + opcut_params_t *params = mem_pool_alloc(a->params); + if (!params) + return NULL; + + params->cut_width = cut_width; + params->min_initial_usage = min_initial_usage; + params->panels = panels; + params->items = items; + params->panels_area = 0; + + for (opcut_panel_t *panel = params->panels; panel; panel = panel->next) + params->panels_area += panel->area; + + return params; +} + + +opcut_used_t *opcut_used_create(opcut_allocator_t *a, opcut_panel_t *panel, + opcut_item_t *item, double x, double y, + bool rotate, opcut_used_t *next) { + opcut_used_t *used = mem_pool_alloc(a->used); + if (!used) + return NULL; + + used->panel = panel; + used->item = item; + used->x = x; + used->y = y; + used->rotate = rotate; + used->next = next; + + return used; +} + + +opcut_unused_t *opcut_unused_create(opcut_allocator_t *a, opcut_panel_t *panel, + double width, double height, double x, + double y, bool rotate, + opcut_unused_t *next) { + opcut_unused_t *unused = mem_pool_alloc(a->unused); + if (!unused) + return NULL; + + unused->panel = panel; + unused->width = width; + unused->height = height; + unused->x = x; + unused->y = y; + unused->next = next; + unused->area = width * height; + unused->initial = true; + + return unused; +} + + +opcut_result_t *opcut_result_create(opcut_allocator_t *a, + opcut_params_t *params, opcut_used_t *used, + opcut_unused_t *unused) { + opcut_result_t *result = mem_pool_alloc(a->result); + if (!result) + return NULL; + + result->params = params; + result->used = used; + result->unused = unused; + + return result; +} + + +int opcut_calculate(opcut_allocator_t *a, int method, opcut_result_t *result) { + opcut_item_t *used_items = NULL; + opcut_item_t *unused_items = NULL; + + for (opcut_item_t *item = result->params->items; item;) { + bool is_used = false; + opcut_item_t *next = item->next; + + for (opcut_used_t *used = result->used; used && !is_used; + used = used->next) + is_used = used->item == item; + + if (is_used) { + item->next = used_items; + used_items = item; + + } else { + item->next = unused_items; + unused_items = item; + } + + item = next; + } + + sort_items(&used_items, NULL); + sort_items(&unused_items, NULL); + + result->params->items = used_items; + for (opcut_item_t *item = result->params->items; item; item = item->next) { + if (!item->next) { + item->next = unused_items; + break; + } + } + + sort_unused(&(result->unused), NULL); + + if (method == OPCUT_METHOD_GREEDY) + return calculate_greedy(a, result, unused_items, false); + + if (method == OPCUT_METHOD_FORWARD_GREEDY) + return calculate_greedy(a, result, unused_items, true); + + return OPCUT_ERROR; +} diff --git a/src_c/opcut.h b/src_c/opcut.h new file mode 100644 index 0000000..de4ae3c --- /dev/null +++ b/src_c/opcut.h @@ -0,0 +1,113 @@ +#ifndef OPCUT_H +#define OPCUT_H + +#include <stddef.h> +#include <stdbool.h> + +#define OPCUT_SUCCESS 0 +#define OPCUT_ERROR 1 +#define OPCUT_UNSOLVABLE 42 + +#define OPCUT_METHOD_GREEDY 0 +#define OPCUT_METHOD_FORWARD_GREEDY 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*opcut_malloc_t)(size_t n); +typedef void (*opcut_free_t)(void *p); +typedef struct opcut_allocator_t opcut_allocator_t; + +typedef struct opcut_panel_t { + char *id; + double width; + double height; + + // internal + struct opcut_panel_t *next; + double area; +} opcut_panel_t; + +typedef struct opcut_item_t { + char *id; + double width; + double height; + bool can_rotate; + + // internal + struct opcut_item_t *next; + double area; +} opcut_item_t; + +typedef struct { + double cut_width; + bool min_initial_usage; + opcut_panel_t *panels; + opcut_item_t *items; + + // internal + double panels_area; +} opcut_params_t; + +typedef struct opcut_used_t { + opcut_panel_t *panel; + opcut_item_t *item; + double x; + double y; + bool rotate; + + // internal + struct opcut_used_t *next; +} opcut_used_t; + +typedef struct opcut_unused_t { + opcut_panel_t *panel; + double width; + double height; + double x; + double y; + + // internal + struct opcut_unused_t *next; + double area; + bool initial; +} opcut_unused_t; + +typedef struct { + opcut_params_t *params; + opcut_used_t *used; + opcut_unused_t *unused; +} opcut_result_t; + + +opcut_allocator_t *opcut_allocator_create(opcut_malloc_t malloc, + opcut_free_t free); +void opcut_allocator_destroy(opcut_allocator_t *a); + +opcut_panel_t *opcut_panel_create(opcut_allocator_t *a, char *id, double width, + double height, opcut_panel_t *next); +opcut_item_t *opcut_item_create(opcut_allocator_t *a, char *id, double width, + double height, bool can_rotate, + opcut_item_t *next); +opcut_params_t *opcut_params_create(opcut_allocator_t *a, double cut_width, + bool min_initial_usage, + opcut_panel_t *panels, opcut_item_t *items); +opcut_used_t *opcut_used_create(opcut_allocator_t *a, opcut_panel_t *panel, + opcut_item_t *item, double x, double y, + bool rotate, opcut_used_t *next); +opcut_unused_t *opcut_unused_create(opcut_allocator_t *a, opcut_panel_t *panel, + double width, double height, double x, + double y, bool rotate, + opcut_unused_t *next); +opcut_result_t *opcut_result_create(opcut_allocator_t *a, + opcut_params_t *params, opcut_used_t *used, + opcut_unused_t *unused); + +int opcut_calculate(opcut_allocator_t *a, int method, opcut_result_t *result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src_c/pool.c b/src_c/pool.c deleted file mode 100644 index 4bd8250..0000000 --- a/src_c/pool.c +++ /dev/null @@ -1,88 +0,0 @@ -#include <stdlib.h> -#include "pool.h" - - -#define PAGE_SIZE 4096 - - -typedef struct header_t { - struct header_t *next; -} header_t; - - -struct opcut_pool_t { - hat_allocator_t *a; - size_t item_size; - header_t *blocks; - header_t *items; -}; - - -static void allocate_block(opcut_pool_t *pool) { - size_t items_per_block = - (PAGE_SIZE - sizeof(header_t)) / (sizeof(header_t) + pool->item_size); - if (items_per_block < 1) - items_per_block = 1; - - header_t *block = hat_allocator_alloc( - pool->a, sizeof(header_t) + - items_per_block * (sizeof(header_t) + pool->item_size)); - if (!block) - return; - block->next = pool->blocks; - pool->blocks = block; - - for (size_t i = 0; i < items_per_block; ++i) { - header_t *header = (void *)block + sizeof(header_t) + - i * (sizeof(header_t) + pool->item_size); - header->next = pool->items; - pool->items = header; - } -} - - -opcut_pool_t *opcut_pool_create(hat_allocator_t *a, size_t item_size) { - opcut_pool_t *pool = hat_allocator_alloc(a, sizeof(opcut_pool_t)); - if (!pool) - return NULL; - - if (item_size % sizeof(void *) != 0) - item_size += sizeof(void *) - (item_size % sizeof(void *)); - - pool->a = a; - pool->item_size = item_size; - pool->blocks = NULL; - pool->items = NULL; - - return pool; -} - - -void opcut_pool_destroy(opcut_pool_t *pool) { - while (pool->blocks) { - header_t *block = pool->blocks; - pool->blocks = block->next; - hat_allocator_free(pool->a, block); - } - hat_allocator_free(pool->a, pool); -} - - -void *opcut_pool_alloc(opcut_pool_t *pool) { - if (!pool->items) - allocate_block(pool); - - if (!pool->items) - return NULL; - - header_t *header = pool->items; - pool->items = header->next; - return header + 1; -} - - -void opcut_pool_free(opcut_pool_t *pool, void *item) { - header_t *header = (header_t *)item - 1; - header->next = pool->items; - pool->items = header; -} diff --git a/src_c/pool.h b/src_c/pool.h deleted file mode 100644 index e6ac0b2..0000000 --- a/src_c/pool.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef OPCUT_POOL_H -#define OPCUT_POOL_H - -#include <stddef.h> -#include <hat/allocator.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct opcut_pool_t opcut_pool_t; - -opcut_pool_t *opcut_pool_create(hat_allocator_t *a, size_t item_size); -void opcut_pool_destroy(opcut_pool_t *pool); -void *opcut_pool_alloc(opcut_pool_t *pool); -void opcut_pool_free(opcut_pool_t *pool, void *item); - -#ifdef __cplusplus -} -#endif - -#endif |
