From 9590949fa752d823ac32624dd92f3be2d3f3f5d6 Mon Sep 17 00:00:00 2001 From: chros Date: Mon, 6 Mar 2017 13:06:59 +0000 Subject: [PATCH 1/7] Add support for basic arithmetic operators (See #14) --- src/command_ui.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/command_ui.cc b/src/command_ui.cc index 69ee2f54..a40a4100 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -519,6 +519,56 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back())); } +int64_t +apply_math_basic(const std::function op, const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count."); + + int64_t val = 0; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + if (itr->is_value()) { + val = itr == args.begin() ? itr->as_value() : op(val, itr->as_value()); + } else if (itr->is_string()) { + val = itr == args.begin() ? rpc::convert_to_value(itr->as_string()) : op(val, rpc::convert_to_value(itr->as_string())); + } else if (itr->is_list()) { + val = itr == args.begin() ? apply_math_basic(op, itr->as_list()) : op(val, apply_math_basic(op, itr->as_list())); + } else { + throw torrent::input_error("Wrong type supplied to apply_math_basic."); + } + + } + + return val; +} + +int64_t +apply_arith_basic(const std::function op, const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count."); + + int64_t val = 0; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + if (itr->is_value()) { + val = itr == args.begin() ? itr->as_value() : (op(val, itr->as_value()) ? val : itr->as_value()); + } else if (itr->is_string()) { + int64_t cval = rpc::convert_to_value(itr->as_string()); + val = itr == args.begin() ? cval : (op(val, cval) ? val : cval); + } else if (itr->is_list()) { + int64_t fval = apply_arith_basic(op, itr->as_list()); + val = itr == args.begin() ? fval : (op(val, fval) ? val : fval); + } else { + throw torrent::input_error("Wrong type supplied to apply_arith_basic."); + } + + } + + return val; +} + void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); @@ -585,6 +635,15 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2)); CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); + CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, std::plus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.subtract", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.multiply", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); + CMD2_ANY_LIST("math.divide", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); + CMD2_ANY_LIST("math.modulo", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); + + CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); + CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); + CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); } From 3002c95b2c4122890f8a4e4ec7ef933ab68cf3c3 Mon Sep 17 00:00:00 2001 From: chros Date: Mon, 6 Mar 2017 19:41:49 +0000 Subject: [PATCH 2/7] Rename couple of arithmetic commands (See #14) --- src/command_ui.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index a40a4100..54a121d7 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -636,10 +636,10 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, std::plus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.subtract", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.multiply", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); - CMD2_ANY_LIST("math.divide", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); - CMD2_ANY_LIST("math.modulo", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); + CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); From 8b6a1ad07967f3c664e8323d7c6c391f1bb3f666 Mon Sep 17 00:00:00 2001 From: chros Date: Tue, 7 Mar 2017 12:57:31 +0000 Subject: [PATCH 3/7] Add count and average commands (See #14) --- src/command_ui.cc | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index 54a121d7..bbb07a4d 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -569,6 +569,44 @@ apply_arith_basic(const std::function op, const torren return val; } +int64_t +apply_arith_count(const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count in apply_arith_count."); + + int64_t val = 0; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + switch (itr->type()) { + case torrent::Object::TYPE_VALUE: + case torrent::Object::TYPE_STRING: + val++; + break; + case torrent::Object::TYPE_LIST: + val += apply_arith_count(itr->as_list()); + break; + default: + throw torrent::input_error("Wrong type supplied to apply_arith_count."); + } + + } + + return val; +} + +int64_t +apply_arith_other(const char* op, const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count in apply_arith_other."); + + if (op == "average") + return (int64_t)(apply_math_basic(std::plus(), args) / apply_arith_count(args)); + else + throw torrent::input_error("Wrong operation supplied to apply_arith_other."); + +} + void initialize_command_ui() { CMD2_VAR_STRING("keys.layout", "qwerty"); @@ -640,9 +678,10 @@ initialize_command_ui() { CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); + CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2)); + CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); From 6cb176ada3d411cdb8a9ffb3b9ed956c436f9810 Mon Sep 17 00:00:00 2001 From: chros Date: Tue, 7 Mar 2017 13:12:18 +0000 Subject: [PATCH 4/7] Add more info to throw message in math commands (See #14) --- src/command_ui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index bbb07a4d..a558de64 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -522,7 +522,7 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { int64_t apply_math_basic(const std::function op, const torrent::Object::list_type& args) { if (args.size() == 0) - throw torrent::input_error("Wrong argument count."); + throw torrent::input_error("Wrong argument count in apply_math_basic."); int64_t val = 0; @@ -546,7 +546,7 @@ apply_math_basic(const std::function op, const torrent int64_t apply_arith_basic(const std::function op, const torrent::Object::list_type& args) { if (args.size() == 0) - throw torrent::input_error("Wrong argument count."); + throw torrent::input_error("Wrong argument count in apply_arith_basic."); int64_t val = 0; From 13676f06e5398b83f05e13d9f60288f1c0eba1ef Mon Sep 17 00:00:00 2001 From: chros Date: Sat, 11 Mar 2017 11:40:08 +0000 Subject: [PATCH 5/7] Add median command (See #14) --- rak/algorithm.h | 20 ++++++++++++++++++++ src/command_ui.cc | 36 +++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/rak/algorithm.h b/rak/algorithm.h index ad8e7158..98613820 100644 --- a/rak/algorithm.h +++ b/rak/algorithm.h @@ -176,6 +176,26 @@ inline int popcount_wrapper(T t) { #endif } +// Get the median of an unordered set of numbers of arbitrary +// type by modifing the underlying dataset +template +T median(_InputIter __first, _InputIter __last) { + T __med; + + unsigned int __size = __last - __first; + unsigned int __middle = __size / 2; + _InputIter __target1 = __first + __middle; + std::nth_element(__first, __target1, __last); + __med = *__target1; + + if (__size % 2 == 0) { + _InputIter __target2 = std::max_element(__first, __target1); + __med = (__med + *__target2) / 2.0; + } + + return __med; +} + } #endif diff --git a/src/command_ui.cc b/src/command_ui.cc index a558de64..d0646bd1 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -519,6 +520,31 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { return (int64_t)(start_time != 0 && rak::timer::current_seconds() - start_time > rpc::convert_to_value(args.back())); } +inline std::vector +as_vector(const torrent::Object::list_type& args) { + if (args.size() == 0) + throw torrent::input_error("Wrong argument count in as_list."); + + std::vector result; + + for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { + + if (itr->is_value()) { + result.push_back(itr->as_value()); + } else if (itr->is_string()) { + result.push_back(rpc::convert_to_value(itr->as_string())); + } else if (itr->is_list()) { + std::vector subResult = as_vector(itr->as_list()); + result.insert(result.end(), subResult.begin(), subResult.end()); + } else { + throw torrent::input_error("Wrong type supplied to as_list."); + } + + } + + return result; +} + int64_t apply_math_basic(const std::function op, const torrent::Object::list_type& args) { if (args.size() == 0) @@ -600,11 +626,14 @@ apply_arith_other(const char* op, const torrent::Object::list_type& args) { if (args.size() == 0) throw torrent::input_error("Wrong argument count in apply_arith_other."); - if (op == "average") + if (op == "average") { return (int64_t)(apply_math_basic(std::plus(), args) / apply_arith_count(args)); - else + } else if (op == "median") { + std::vector result = as_vector(args); + return (int64_t)rak::median(result.begin(), result.end()); + } else { throw torrent::input_error("Wrong operation supplied to apply_arith_other."); - + } } void @@ -682,6 +711,7 @@ initialize_command_ui() { CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2)); CMD2_ANY_LIST("math.avg", std::bind(&apply_arith_other, "average", std::placeholders::_2)); + CMD2_ANY_LIST("math.med", std::bind(&apply_arith_other, "median", std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.less", std::bind(&apply_elapsed_less, std::placeholders::_2)); CMD2_ANY_LIST ("elapsed.greater", std::bind(&apply_elapsed_greater, std::placeholders::_2)); From 6c11a1dbb065adc179e280dbf77b0b65eedc6b9c Mon Sep 17 00:00:00 2001 From: chros Date: Sat, 3 Mar 2018 09:08:28 +0000 Subject: [PATCH 6/7] Fix error message in as_vector method (See #14) --- src/command_ui.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index d0646bd1..5cd1e4af 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -523,7 +523,7 @@ apply_elapsed_greater(const torrent::Object::list_type& args) { inline std::vector as_vector(const torrent::Object::list_type& args) { if (args.size() == 0) - throw torrent::input_error("Wrong argument count in as_list."); + throw torrent::input_error("Wrong argument count in as_vector."); std::vector result; @@ -537,7 +537,7 @@ as_vector(const torrent::Object::list_type& args) { std::vector subResult = as_vector(itr->as_list()); result.insert(result.end(), subResult.begin(), subResult.end()); } else { - throw torrent::input_error("Wrong type supplied to as_list."); + throw torrent::input_error("Wrong type supplied to as_vector."); } } From 6dc87e499ac4292d98c258b61dd140bb17de9c3e Mon Sep 17 00:00:00 2001 From: chros Date: Fri, 1 Jun 2018 11:51:42 +0100 Subject: [PATCH 7/7] Fix bugs in 'math.*' commands (See #14) --- src/command_ui.cc | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/command_ui.cc b/src/command_ui.cc index 5cd1e4af..c98f9427 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -546,24 +546,30 @@ as_vector(const torrent::Object::list_type& args) { } int64_t -apply_math_basic(const std::function op, const torrent::Object::list_type& args) { - if (args.size() == 0) - throw torrent::input_error("Wrong argument count in apply_math_basic."); +apply_math_basic(const char* name, const std::function op, const torrent::Object::list_type& args) { + int64_t val = 0, rhs = 0; + bool divides = !strcmp(name, "math.div") || !strcmp(name, "math.mod"); - int64_t val = 0; + if (args.size() == 0) + throw torrent::input_error(std::string(name) + ": No arguments provided!"); for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { if (itr->is_value()) { - val = itr == args.begin() ? itr->as_value() : op(val, itr->as_value()); + rhs = itr->as_value(); } else if (itr->is_string()) { - val = itr == args.begin() ? rpc::convert_to_value(itr->as_string()) : op(val, rpc::convert_to_value(itr->as_string())); + rhs = rpc::convert_to_value(itr->as_string()); } else if (itr->is_list()) { - val = itr == args.begin() ? apply_math_basic(op, itr->as_list()) : op(val, apply_math_basic(op, itr->as_list())); + rhs = apply_math_basic(name, op, itr->as_list()); } else { - throw torrent::input_error("Wrong type supplied to apply_math_basic."); + throw torrent::input_error(std::string(name) + ": Wrong argument type"); } + if (divides && !rhs && itr != args.begin()) + throw torrent::input_error(std::string(name) + ": Division by zero!"); + + val = itr == args.begin() ? rhs : op(val, rhs); + } return val; @@ -626,9 +632,9 @@ apply_arith_other(const char* op, const torrent::Object::list_type& args) { if (args.size() == 0) throw torrent::input_error("Wrong argument count in apply_arith_other."); - if (op == "average") { - return (int64_t)(apply_math_basic(std::plus(), args) / apply_arith_count(args)); - } else if (op == "median") { + if (strcmp(op, "average") == 0) { + return (int64_t)(apply_math_basic(op, std::plus(), args) / apply_arith_count(args)); + } else if (strcmp(op, "median") == 0) { std::vector result = as_vector(args); return (int64_t)rak::median(result.begin(), result.end()); } else { @@ -702,11 +708,11 @@ initialize_command_ui() { CMD2_ANY_VALUE("convert.xb", std::bind(&apply_to_xb, std::placeholders::_2)); CMD2_ANY_VALUE("convert.throttle", std::bind(&apply_to_throttle, std::placeholders::_2)); - CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, std::plus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, std::minus(), std::placeholders::_2)); - CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, std::multiplies(), std::placeholders::_2)); - CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, std::divides(), std::placeholders::_2)); - CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, std::modulus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.add", std::bind(&apply_math_basic, "math.add", std::plus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.sub", std::bind(&apply_math_basic, "math.sub", std::minus(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mul", std::bind(&apply_math_basic, "math.mul", std::multiplies(), std::placeholders::_2)); + CMD2_ANY_LIST("math.div", std::bind(&apply_math_basic, "math.div", std::divides(), std::placeholders::_2)); + CMD2_ANY_LIST("math.mod", std::bind(&apply_math_basic, "math.mod", std::modulus(), std::placeholders::_2)); CMD2_ANY_LIST("math.min", std::bind(&apply_arith_basic, std::less(), std::placeholders::_2)); CMD2_ANY_LIST("math.max", std::bind(&apply_arith_basic, std::greater(), std::placeholders::_2)); CMD2_ANY_LIST("math.cnt", std::bind(&apply_arith_count, std::placeholders::_2));