From 00c2e99d2ee866f21f4c78d7b01cd65711723ef9 Mon Sep 17 00:00:00 2001 From: John Ralls Date: Mon, 30 Aug 2021 13:14:19 -0700 Subject: [PATCH] Convert the Scheme RelativeDatePeriod lookup table to a std::vector. From a Scheme alist. The vector can be used to find the scheme symbol as a direct lookup, which isn't possible with an alist, and can be searched for the Scheme symbol match more quickly than an alist can. --- libgnucash/app-utils/gnc-option-date.hpp | 3 + libgnucash/app-utils/gnc-optiondb.i | 223 ++++++++++++++---- .../app-utils/test/test-gnc-optiondb.scm | 8 +- 3 files changed, 180 insertions(+), 54 deletions(-) diff --git a/libgnucash/app-utils/gnc-option-date.hpp b/libgnucash/app-utils/gnc-option-date.hpp index 8d4e65529c..82f963d607 100644 --- a/libgnucash/app-utils/gnc-option-date.hpp +++ b/libgnucash/app-utils/gnc-option-date.hpp @@ -73,6 +73,9 @@ enum class RelativeDatePeriod : int END_ACCOUNTING_PERIOD, }; +constexpr unsigned relative_date_periods = + static_cast(RelativeDatePeriod::END_ACCOUNTING_PERIOD) + 2; + using RelativeDatePeriodVec = std::vector; bool gnc_relative_date_is_single(RelativeDatePeriod); diff --git a/libgnucash/app-utils/gnc-optiondb.i b/libgnucash/app-utils/gnc-optiondb.i index 9bc3c13414..1fbbf575a5 100644 --- a/libgnucash/app-utils/gnc-optiondb.i +++ b/libgnucash/app-utils/gnc-optiondb.i @@ -427,6 +427,18 @@ gnc_option_test_book_destroy(QofBook* book) $1 = scm_is_signed_integer($input, INT64_MAX, INT64_MIN); } +%typemap(in) RelativeDatePeriod (RelativeDatePeriod rdp) +{ + if (scm_is_integer($input)) + rdp = (RelativeDatePeriod) scm_to_int($input); + else if (scm_is_symbol($input)) + rdp = scm_relative_date_get_period($input); + else + rdp = RelativeDatePeriod::TODAY; + + $1 = rdp; +} + %typemap(in) RelativeDatePeriodVec& (RelativeDatePeriodVec period_set) { auto len = scm_is_true($input) ? scm_to_size_t(scm_length($input)) : 0; @@ -626,61 +638,149 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB); %header %{ + static std::vector reldate_values{}; + inline size_t index_of(RelativeDatePeriod per) + { + return static_cast(per) + 1; + } + + static void init_reldate_values() + { + if (!reldate_values.empty()) + return; + std::vector tmp (relative_date_periods, SCM_BOOL_F); + using rdp = RelativeDatePeriod; + tmp[index_of(rdp::ABSOLUTE)] = + scm_from_utf8_symbol("absolute"); + tmp[index_of(rdp::TODAY)] = + scm_from_utf8_symbol("today"); + tmp[index_of(rdp::ONE_WEEK_AGO)] = + scm_from_utf8_symbol("one-week-ago"); + tmp[index_of(rdp::ONE_WEEK_AHEAD)] = + scm_from_utf8_symbol("one-week-ahead"); + tmp[index_of(rdp::ONE_MONTH_AGO)] = + scm_from_utf8_symbol("one-month-ago"); + tmp[index_of(rdp::ONE_MONTH_AHEAD)] = + scm_from_utf8_symbol("one-month-ahead"); + tmp[index_of(rdp::THREE_MONTHS_AGO)] = + scm_from_utf8_symbol("three-months-ago"); + tmp[index_of(rdp::THREE_MONTHS_AHEAD)] = + scm_from_utf8_symbol("three-months-ahead"); + tmp[index_of(rdp::SIX_MONTHS_AGO)] = + scm_from_utf8_symbol("six-months-ago"); + tmp[index_of(rdp::SIX_MONTHS_AHEAD)] = + scm_from_utf8_symbol("six-months-ahead"); + tmp[index_of(rdp::ONE_YEAR_AGO)] = + scm_from_utf8_symbol("one-year-ago"); + tmp[index_of(rdp::ONE_YEAR_AHEAD)] = + scm_from_utf8_symbol("one-year-ahead"); + tmp[index_of(rdp::START_THIS_MONTH)] = + scm_from_utf8_symbol("start-this-month"); + tmp[index_of(rdp::END_THIS_MONTH)] = + scm_from_utf8_symbol("end-this-month"); + tmp[index_of(rdp::START_PREV_MONTH)] = + scm_from_utf8_symbol("start-prev-month"); + tmp[index_of(rdp::END_PREV_MONTH)] = + scm_from_utf8_symbol("end-prev-month"); + tmp[index_of(rdp::START_NEXT_MONTH)] = + scm_from_utf8_symbol("start-next-month"); + tmp[index_of(rdp::END_NEXT_MONTH)] = + scm_from_utf8_symbol("end-next-month"); + tmp[index_of(rdp::START_CURRENT_QUARTER)] = + scm_from_utf8_symbol("start-current-quarter"); + tmp[index_of(rdp::END_CURRENT_QUARTER)] = + scm_from_utf8_symbol("end-current-quarter"); + tmp[index_of(rdp::START_PREV_QUARTER)] = + scm_from_utf8_symbol("start-prev-quarter"); + tmp[index_of(rdp::END_PREV_QUARTER)] = + scm_from_utf8_symbol("end-prev-quarter"); + tmp[index_of(rdp::START_NEXT_QUARTER)] = + scm_from_utf8_symbol("start-next-quarter"); + tmp[index_of(rdp::END_NEXT_QUARTER)] = + scm_from_utf8_symbol("end-next-quarter"); + tmp[index_of(rdp::START_CAL_YEAR)] = + scm_from_utf8_symbol("start-cal-year"); + tmp[index_of(rdp::END_CAL_YEAR)] = + scm_from_utf8_symbol("end-cal-year"); + tmp[index_of(rdp::START_PREV_YEAR)] = + scm_from_utf8_symbol("start-prev-year"); + tmp[index_of(rdp::END_PREV_YEAR)] = + scm_from_utf8_symbol("end-prev-year"); + tmp[index_of(rdp::START_NEXT_YEAR)] = + scm_from_utf8_symbol("start-next-year"); + tmp[index_of(rdp::END_NEXT_YEAR)] = + scm_from_utf8_symbol("end-next-year"); + tmp[index_of(rdp::START_ACCOUNTING_PERIOD)] = + scm_from_utf8_symbol("start-accounting-period"); + tmp[index_of(rdp::END_ACCOUNTING_PERIOD)] = + scm_from_utf8_symbol("end-accounting-period"); + reldate_values = std::move(tmp); + } + inline static RelativeDatePeriod scm_relative_date_get_period(SCM date) { - static SCM reldate_values = SCM_BOOL_F; - - if (scm_is_false(reldate_values)) - reldate_values = scm_c_eval_string( - "'((absolute RelativeDatePeriod-ABSOLUTE)" - "(today RelativeDatePeriod-TODAY)" - "(one-week-ago RelativeDatePeriod-ONE-WEEK-AGO)" - "(one-week-ahead RelativeDatePeriod-ONE-WEEK-AHEAD)" - "(one-month-ago RelativeDatePeriod-ONE-MONTH-AGO)" - "(one-month-ahead RelativeDatePeriod-ONE-MONTH-AHEAD)" - "(three-months-ago RelativeDatePeriod-THREE-MONTHS-AGO)" - "(three-months-ahead RelativeDatePeriod-THREE-MONTHS-AHEAD)" - "(six-months-ago RelativeDatePeriod-SIX-MONTHS-AGO)" - "(six-months-ahead RelativeDatePeriod-SIX-MONTHS-AHEAD)" - "(one-year-ago RelativeDatePeriod-ONE-YEAR-AGO)" - "(one-year-ahead RelativeDatePeriod-ONE-YEAR-AHEAD)" - "(start-this-month RelativeDatePeriod-START-THIS-MONTH)" - "(end-this-month RelativeDatePeriod-END-THIS-MONTH)" - "(start-prev-month RelativeDatePeriod-START-PREV-MONTH)" - "(end-prev-month RelativeDatePeriod-END-PREV-MONTH)" - "(start-next-month RelativeDatePeriod-START-NEXT-MONTH)" - "(end-next-month RelativeDatePeriod-END-NEXT-MONTH)" - "(start-current-quarter RelativeDatePeriod-START-CURRENT-QUARTER)" - "(end-current-quarter RelativeDatePeriod-END-CURRENT-QUARTER)" - "(start-prev-quarter RelativeDatePeriod-START-PREV-QUARTER)" - "(end-prev-quarter RelativeDatePeriod-END-PREV-QUARTER)" - "(start-next-quarter RelativeDatePeriod-START-NEXT-QUARTER)" - "(end-next-quarter RelativeDatePeriod-END-NEXT-QUARTER)" - "(start-cal-year RelativeDatePeriod-START-CAL-YEAR)" - "(end-cal-year RelativeDatePeriod-END-CAL-YEAR)" - "(start-prev-year RelativeDatePeriod-START-PREV-YEAR)" - "(end-prev-year RelativeDatePeriod-END-PREV-YEAR)" - "(start-next-year RelativeDatePeriod-START-NEXT-YEAR)" - "(end-next-year RelativeDatePeriod-END-NEXT-YEAR)" - "(start-accounting-period RelativeDatePeriod-START-ACCOUNTING-PERIOD)" - "(end-accounting-period RelativeDatePeriod-END-ACCOUNTING-PERIOD))"); - - auto reldate_scm{scm_is_pair(date) ? scm_cdr(date) : date}; - auto reldate{scm_primitive_eval(scm_assq_ref(reldate_values, - reldate_scm))}; - return static_cast(scm_to_int(reldate)); + init_reldate_values(); + auto reldate_scm{scm_is_pair(date) ? scm_cdr(date) : date}; + SCM reldate_val{SCM_BOOL_F}; + if (scm_is_procedure(reldate_scm)) + reldate_val = scm_call_0(reldate_scm); + if (scm_is_number(reldate_scm)) + reldate_val = reldate_scm; + if (scm_is_number(reldate_val)) + { + auto reldate_index = scm_to_int(reldate_val); + assert(reldate_index >= static_cast(RelativeDatePeriod::ABSOLUTE) && reldate_index < static_cast(relative_date_periods - 1)); + return static_cast(reldate_index); + } + const char* reldate_str; + if (scm_is_symbol(reldate_scm)) + reldate_str = scm_to_utf8_string(scm_symbol_to_string(reldate_scm)); + else + reldate_str = scm_to_utf8_string(reldate_scm); + + auto date_iter = + std::find_if(reldate_values.begin(), reldate_values.end(), + [&reldate_scm](auto val)->bool { + return scm_is_eq(val, reldate_scm) == 1; + }); + if (date_iter == reldate_values.end()) + return RelativeDatePeriod::ABSOLUTE; + return static_cast(date_iter - reldate_values.begin() - 1); + } + inline static SCM scm_relative_date_from_period(RelativeDatePeriod period) + { + init_reldate_values(); + return reldate_values[static_cast(period) + 1]; } inline static bool scm_date_absolute(SCM date) { if (scm_is_pair(date)) { - auto car{scm_to_utf8_string(scm_symbol_to_string(scm_car(date)))}; - if (strcmp(car, "relative") == 0) - return false; + if (scm_is_symbol(scm_car(date))) + { + auto car{scm_to_utf8_string(scm_symbol_to_string(scm_car(date)))}; + auto cdr{scm_cdr(date)}; + if (strcmp(car, "relative") == 0) + return false; + if (strcmp(car, "absolute") == 0) + return true; + + assert(false); + } + else + { + auto cdr{scm_cdr(date)}; + if (scm_is_symbol(cdr)) + return false; + if (scm_is_number(cdr)) + return true; + + assert(false); + } } - return true; + return (!(scm_is_symbol(date) || scm_is_string(date))); } inline static time64 scm_absolute_date_to_time64(SCM date) @@ -808,16 +908,39 @@ wrap_unique_ptr(GncOptionDBPtr, GncOptionDB); return scm_cons(desig, scm_from_int(val)); } + static SCM + get_scm_value(const GncOptionDateValue& option) + { + if (option.get_period() == RelativeDatePeriod::ABSOLUTE) + return scm_cons(scm_from_utf8_symbol("absolute"), + scm_from_value(option.get_value())); + else + return scm_cons(scm_from_utf8_symbol("relative"), + scm_relative_date_from_period(option.get_period())); + } + + static SCM + get_scm_default_value(const GncOptionDateValue& option) + { + if (option.get_default_period() == RelativeDatePeriod::ABSOLUTE) + return scm_cons(scm_from_utf8_symbol("absolute"), + scm_from_value(option.get_default_value())); + else + return scm_cons(scm_from_utf8_symbol("relative"), + scm_relative_date_from_period(option.get_default_period())); + } + template -struct is_MultichoiceOrRange +struct is_MultichoiceDateOrRange { static constexpr bool value = is_same_decayed_v || - is_same_decayed_v>; + is_same_decayed_v> || + is_same_decayed_v; }; template -inline constexpr bool is_MultichoiceOrRange_v = is_MultichoiceOrRange::value; +inline constexpr bool is_MultichoiceDateOrRange_v = is_MultichoiceDateOrRange::value; template inline SCM return_scm_value(ValueType value) @@ -853,7 +976,7 @@ inline SCM return_scm_value(ValueType value) if (!$self) return SCM_BOOL_F; return std::visit([](const auto& option)->SCM { - if constexpr (is_MultichoiceOrRange_v) + if constexpr (is_MultichoiceDateOrRange_v) return get_scm_value(option); auto value{option.get_value()}; return return_scm_value(value); @@ -864,7 +987,7 @@ inline SCM return_scm_value(ValueType value) if (!$self) return SCM_BOOL_F; return std::visit([](const auto& option)->SCM { - if constexpr (is_MultichoiceOrRange_v) + if constexpr (is_MultichoiceDateOrRange_v) return get_scm_default_value(option); auto value{option.get_default_value()}; return return_scm_value(value); diff --git a/libgnucash/app-utils/test/test-gnc-optiondb.scm b/libgnucash/app-utils/test/test-gnc-optiondb.scm index ad88824638..30b5da1d03 100644 --- a/libgnucash/app-utils/test/test-gnc-optiondb.scm +++ b/libgnucash/app-utils/test/test-gnc-optiondb.scm @@ -202,9 +202,9 @@ "baz" "Phony Option" (RelativeDatePeriod-TODAY))) (a-time (gnc-dmy2time64 11 07 2019))) - (test-equal (current-time) (gnc-option-value option-db "foo" "bar")) + (test-equal '(relative . today) (gnc-option-value option-db "foo" "bar")) (gnc-set-option option-db "foo" "bar" a-time) - (test-equal a-time (gnc-option-value option-db "foo" "bar"))) + (test-equal `(absolute . ,a-time) (gnc-option-value option-db "foo" "bar"))) (test-end "test-gnc-test-date-option")) (define (test-gnc-make-date-set-option) @@ -212,7 +212,7 @@ (let* ((option-db (new-gnc-optiondb)) (date-opt (gnc-register-date-option-set option-db "foo" "bar" "baz" "Phony Option" - `(today + '(today start-this-month start-prev-month start-current-quarter @@ -221,7 +221,7 @@ start-cal-year start-prev-year start-accounting-period) #t))) - (test-equal (gnc-accounting-period-fiscal-start) + (test-equal '(relative . start-accounting-period) (gnc-option-value option-db "foo" "bar"))) (test-end "test-gnc-test-date-set-option"))