aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--peru.yaml7
-rw-r--r--playground/.gitignore2
-rwxr-xr-xplayground/calculate.sh4
-rwxr-xr-xplayground/generate_output.sh2
-rwxr-xr-xplayground/native-calculate.sh8
-rw-r--r--playground/params.json16
-rw-r--r--playground/params.yaml12
-rw-r--r--requirements.pip.dev.txt2
-rw-r--r--src_c/common.c69
-rw-r--r--src_c/common.h21
-rw-r--r--src_c/csp.c14
-rw-r--r--src_c/csp.h23
-rw-r--r--src_c/main.c145
-rw-r--r--src_doit/c.py8
14 files changed, 255 insertions, 78 deletions
diff --git a/peru.yaml b/peru.yaml
index 5bccd4e..da8ee8a 100644
--- a/peru.yaml
+++ b/peru.yaml
@@ -1,6 +1,13 @@
imports:
jsmn: deps/jsmn
+ argparse: deps/argparse
git module jsmn:
url: https://github.com/zserge/jsmn
pick: jsmn.h
+
+git module argparse:
+ url: https://github.com/cofyc/argparse
+ pick:
+ - argparse.c
+ - argparse.h
diff --git a/playground/.gitignore b/playground/.gitignore
index 70dafff..81442ae 100644
--- a/playground/.gitignore
+++ b/playground/.gitignore
@@ -1,3 +1,3 @@
-/result.yaml
+/result.json
/output.pdf
/output.svg
diff --git a/playground/calculate.sh b/playground/calculate.sh
index 2db0ada..bff0e14 100755
--- a/playground/calculate.sh
+++ b/playground/calculate.sh
@@ -3,6 +3,6 @@
. $(dirname -- "$0")/env.sh
exec $PYTHON -m opcut calculate \
- --params $RUN_PATH/params.yaml \
- --result $RUN_PATH/result.yaml \
+ --params $RUN_PATH/params.json \
+ --result $RUN_PATH/result.json \
"$@"
diff --git a/playground/generate_output.sh b/playground/generate_output.sh
index 1eaae94..0139233 100755
--- a/playground/generate_output.sh
+++ b/playground/generate_output.sh
@@ -4,6 +4,6 @@
exec $PYTHON -m opcut generate_output \
--output-type pdf \
- --result $RUN_PATH/result.yaml \
+ --result $RUN_PATH/result.json \
--output $RUN_PATH/output.pdf \
"$@"
diff --git a/playground/native-calculate.sh b/playground/native-calculate.sh
new file mode 100755
index 0000000..06756ba
--- /dev/null
+++ b/playground/native-calculate.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+. $(dirname -- "$0")/env.sh
+
+exec $ROOT_PATH/build/c/opcut-calculate \
+ --method greedy \
+ --output result.json \
+ params.json
diff --git a/playground/params.json b/playground/params.json
new file mode 100644
index 0000000..789505c
--- /dev/null
+++ b/playground/params.json
@@ -0,0 +1,16 @@
+{
+ "cut_width": 1,
+ "panels": {
+ "p1": {
+ "width": 50,
+ "height": 50
+ }
+ },
+ "items": {
+ "i1": {
+ "width": 5,
+ "height": 5,
+ "can_rotate": true
+ }
+ }
+}
diff --git a/playground/params.yaml b/playground/params.yaml
deleted file mode 100644
index 605acec..0000000
--- a/playground/params.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
----
-cut_width: 1
-panels:
- p1:
- width: 50
- height: 50
-items:
- i1:
- width: 5
- height: 5
- can_rotate: true
-...
diff --git a/requirements.pip.dev.txt b/requirements.pip.dev.txt
index cf3f526..951d881 100644
--- a/requirements.pip.dev.txt
+++ b/requirements.pip.dev.txt
@@ -4,7 +4,7 @@ build ~= 0.7.0
doit ~= 0.33.1
flake8 ~= 3.9.2
furo >= 2021.10.9
-hat-doit ~= 0.7.2
+hat-doit ~= 0.7.3
peru >= 1.3.0
pytest ~= 6.2.5
pytest-asyncio ~= 0.15.1
diff --git a/src_c/common.c b/src_c/common.c
index d7135a6..5aca7a8 100644
--- a/src_c/common.c
+++ b/src_c/common.c
@@ -28,7 +28,7 @@ static int write_bool(bool val, FILE *stream) {
static int write_str(opcut_str_t *str, FILE *stream) {
- if (fprintf(stream, "\"%*s\"", str->len, str->data) < 0)
+ if (fprintf(stream, "\"%.*s\"", str->len, str->data) < 0)
return OPCUT_ERROR;
return OPCUT_SUCCESS;
@@ -36,13 +36,10 @@ static int write_str(opcut_str_t *str, FILE *stream) {
static int write_panel(opcut_panel_t *panel, FILE *stream) {
- if (fputs("{\"id\":", stream) < 0)
- return OPCUT_ERROR;
-
if (write_str(&(panel->id), stream))
return OPCUT_ERROR;
- if (fputs(",\"width\":", stream) < 0)
+ if (fputs(":{\"width\":", stream) < 0)
return OPCUT_ERROR;
if (write_number(panel->width, stream))
@@ -62,13 +59,10 @@ static int write_panel(opcut_panel_t *panel, FILE *stream) {
static int write_item(opcut_item_t *item, FILE *stream) {
- if (fputs("{\"id\":", stream) < 0)
- return OPCUT_ERROR;
-
if (write_str(&(item->id), stream))
return OPCUT_ERROR;
- if (fputs(",\"width\":", stream) < 0)
+ if (fputs(":{\"width\":", stream) < 0)
return OPCUT_ERROR;
if (write_number(item->width, stream))
@@ -106,7 +100,7 @@ static int write_params(opcut_params_t *params, FILE *stream) {
if (write_bool(params->min_initial_usage, stream))
return OPCUT_ERROR;
- if (fputs("\"panels\":[", stream) < 0)
+ if (fputs(",\"panels\":{", stream) < 0)
return OPCUT_ERROR;
for (size_t i = 0; i < params->panels_len; ++i) {
@@ -119,7 +113,7 @@ static int write_params(opcut_params_t *params, FILE *stream) {
}
}
- if (fputs("],\"items\":[", stream) < 0)
+ if (fputs("},\"items\":{", stream) < 0)
return OPCUT_ERROR;
for (size_t i = 0; i < params->items_len; ++i) {
@@ -132,7 +126,7 @@ static int write_params(opcut_params_t *params, FILE *stream) {
}
}
- if (fputs("]}", stream) < 0)
+ if (fputs("}}", stream) < 0)
return OPCUT_ERROR;
return OPCUT_SUCCESS;
@@ -261,7 +255,7 @@ static int read_panel(char *json, opcut_panel_t *panel, jsmntok_t *tokens,
if (panel_token->type != JSMN_OBJECT)
return OPCUT_ERROR;
- if (!read_string(json, &(panel->id), id_token))
+ if (read_string(json, &(panel->id), id_token))
return OPCUT_ERROR;
panel->width = 0;
@@ -294,7 +288,7 @@ static int read_item(char *json, opcut_item_t *item, jsmntok_t *tokens,
if (item_token->type != JSMN_OBJECT)
return OPCUT_ERROR;
- if (!read_string(json, &(item->id), id_token))
+ if (read_string(json, &(item->id), id_token))
return OPCUT_ERROR;
item->width = 0;
@@ -367,7 +361,7 @@ static int read_params(char *json, opcut_params_t *params, jsmntok_t *tokens,
goto error_cleanup;
for (size_t j = 0; j < params->panels_len; ++j) {
- if (!read_panel(json, params->panels + j, tokens, pos))
+ if (read_panel(json, params->panels + j, tokens, pos))
goto error_cleanup;
}
@@ -386,7 +380,7 @@ static int read_params(char *json, opcut_params_t *params, jsmntok_t *tokens,
goto error_cleanup;
for (size_t j = 0; j < params->items_len; ++j) {
- if (!read_item(json, params->items + j, tokens, pos))
+ if (read_item(json, params->items + j, tokens, pos))
goto error_cleanup;
}
}
@@ -409,6 +403,16 @@ error_cleanup:
}
+int opcut_str_resize(opcut_str_t *str, size_t size) {
+ char *data = realloc(str->data, size);
+ if (!data)
+ return OPCUT_ERROR;
+
+ str->data = data;
+ return OPCUT_SUCCESS;
+}
+
+
int opcut_params_init(opcut_params_t *params, opcut_str_t *json) {
jsmn_parser parser;
int tokens_len;
@@ -432,15 +436,6 @@ int opcut_params_init(opcut_params_t *params, opcut_str_t *json) {
}
-void opcut_params_destroy(opcut_params_t *params) {
- if (params->panels)
- free(params->panels);
-
- if (params->items)
- free(params->items);
-}
-
-
int opcut_result_write(opcut_result_t *result, FILE *stream) {
if (fputs("{\"params\":", stream) < 0)
return OPCUT_ERROR;
@@ -479,3 +474,27 @@ int opcut_result_write(opcut_result_t *result, FILE *stream) {
return OPCUT_SUCCESS;
}
+
+
+void opcut_str_destroy(opcut_str_t *str) {
+ if (str->data)
+ free(str->data);
+}
+
+
+void opcut_params_destroy(opcut_params_t *params) {
+ if (params->panels)
+ free(params->panels);
+
+ if (params->items)
+ free(params->items);
+}
+
+
+void opcut_result_destroy(opcut_result_t *result) {
+ if (result->used)
+ free(result->used);
+
+ if (result->unused)
+ free(result->unused);
+}
diff --git a/src_c/common.h b/src_c/common.h
index 16aeb9b..42fed63 100644
--- a/src_c/common.h
+++ b/src_c/common.h
@@ -8,6 +8,21 @@
#define OPCUT_ERROR 1
#define OPCUT_UNSOLVABLE 2
+#define OPCUT_STR_EMPTY ((opcut_str_t){.data = NULL, .len = 0})
+#define OPCUT_PARAMS_EMPTY \
+ ((opcut_params_t){.cut_width = 0, \
+ .min_initial_usage = false, \
+ .panels = NULL, \
+ .panels_len = 0, \
+ .items = NULL, \
+ .items_len = 0})
+#define OPCUT_RESULT_EMPTY \
+ ((opcut_result_t){.params = NULL, \
+ .used = NULL, \
+ .used_len = 0, \
+ .unused = NULL, \
+ .unused_len = 0})
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -64,10 +79,14 @@ typedef struct {
} opcut_result_t;
+int opcut_str_resize(opcut_str_t *str, size_t size);
int opcut_params_init(opcut_params_t *params, opcut_str_t *json);
-void opcut_params_destroy(opcut_params_t *params);
int opcut_result_write(opcut_result_t *result, FILE *stream);
+void opcut_str_destroy(opcut_str_t *str);
+void opcut_params_destroy(opcut_params_t *params);
+void opcut_result_destroy(opcut_result_t *result);
+
#ifdef __cplusplus
}
#endif
diff --git a/src_c/csp.c b/src_c/csp.c
new file mode 100644
index 0000000..1e555dc
--- /dev/null
+++ b/src_c/csp.c
@@ -0,0 +1,14 @@
+#include "csp.h"
+
+
+int opcut_calculate(opcut_method_t method, opcut_params_t *params,
+ opcut_result_t *result) {
+
+ result->params = params;
+ result->used = NULL;
+ result->used_len = 0;
+ result->unused = NULL;
+ result->unused_len = 0;
+
+ return OPCUT_SUCCESS;
+}
diff --git a/src_c/csp.h b/src_c/csp.h
new file mode 100644
index 0000000..2cccf50
--- /dev/null
+++ b/src_c/csp.h
@@ -0,0 +1,23 @@
+#ifndef OPCUT_POOL_H
+#define OPCUT_POOL_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_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
index 9cc71ed..9648f7c 100644
--- a/src_c/main.c
+++ b/src_c/main.c
@@ -1,24 +1,74 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <argparse.h>
#include "common.h"
+#include "csp.h"
-static int read_stdin(opcut_str_t *json) {
- size_t json_data_size = 0;
- json->data = NULL;
- json->len = 0;
+typedef struct {
+ opcut_method_t method;
+ char *input_path;
+ char *output_path;
+} args_t;
- while (!(json->len < json_data_size)) {
- char *old_json_data = json->data;
- json_data_size += 4096;
- json->data = realloc(json->data, json_data_size);
- if (!json->data) {
- free(old_json_data);
- return OPCUT_ERROR;
+
+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];
}
- json->len +=
- fread(json->data + json->len, 1, json_data_size - json->len, stdin);
+ } 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(FILE *stream, opcut_str_t *json) {
+ size_t size = 0;
+
+ while (!(json->len < size)) {
+ size += 4096;
+ if (opcut_str_resize(json, size))
+ return OPCUT_ERROR;
+
+ json->len += fread(json->data + json->len, 1, size - json->len, stream);
}
return OPCUT_SUCCESS;
@@ -26,32 +76,63 @@ static int read_stdin(opcut_str_t *json) {
int main(int argc, char **argv) {
- char *method = NULL;
- for (size_t i = 1; i < argc - 1; ++i) {
- if (strcmp("--method", argv[i]) == 0)
- method = argv[++i];
+ args_t args;
+ FILE *input_stream = NULL;
+ FILE *output_stream = NULL;
+ opcut_str_t json = OPCUT_STR_EMPTY;
+ opcut_params_t params = OPCUT_PARAMS_EMPTY;
+ opcut_result_t result = OPCUT_RESULT_EMPTY;
+ int exit_code;
+
+ exit_code = parse_args(&args, argc, argv);
+ if (exit_code) {
+ fprintf(stderr, "error parsing command line arguments\n");
+ goto cleanup;
}
- opcut_str_t json;
- if (!read_stdin(&json))
- return OPCUT_ERROR;
+ 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;
+ }
- opcut_params_t params;
- if (!opcut_params_init(&params, &json)) {
- free(json.data);
- return OPCUT_ERROR;
+ 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(input_stream, &json);
+ if (exit_code) {
+ fprintf(stderr, "error reading input stream\n");
+ goto cleanup;
+ }
+
+ exit_code = opcut_params_init(&params, &json);
+ if (exit_code) {
+ fprintf(stderr, "error parsing calculation parameters\n");
+ goto cleanup;
+ }
+
+ exit_code = opcut_calculate(args.method, &params, &result);
+ if (exit_code) {
+ fprintf(stderr, "calculation error\n");
+ goto cleanup;
}
- opcut_result_t result = {.params = &params,
- .used = NULL,
- .used_len = 0,
- .unused = NULL,
- .unused_len = 0};
+ exit_code = opcut_result_write(&result, output_stream);
- size_t res = opcut_result_write(&result, stdout);
+cleanup:
+ opcut_result_destroy(&result);
opcut_params_destroy(&params);
- free(json.data);
+ opcut_str_destroy(&json);
+ if (output_stream)
+ fclose(output_stream);
+ if (input_stream)
+ fclose(input_stream);
- return res;
+ return exit_code;
}
diff --git a/src_doit/c.py b/src_doit/c.py
index 618dd8d..8318d10 100644
--- a/src_doit/c.py
+++ b/src_doit/c.py
@@ -33,8 +33,10 @@ def task_c_dep():
_build = CBuild(
- src_paths=[*src_c_dir.rglob('*.c')],
- src_dir=src_c_dir,
+ src_paths=[*src_c_dir.rglob('*.c'),
+ *(deps_dir / 'argparse').rglob('*.c')],
build_dir=build_c_dir,
- cc_flags=['-fPIC', '-O2', f'-I{deps_dir / "jsmn"}'],
+ cc_flags=['-fPIC', '-O2',
+ f'-I{deps_dir / "jsmn"}',
+ f'-I{deps_dir / "argparse"}'],
task_dep=['deps'])