mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-03 14:20:27 +00:00
math(): Add INCREMENT and DECREMENT modes
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
math
|
||||
----
|
||||
|
||||
Evaluate a mathematical expression.
|
||||
Perform mathematical operations.
|
||||
|
||||
Expression Evaluation
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
@@ -37,3 +40,16 @@ For example
|
||||
|
||||
math(EXPR value "100 * 0xA" OUTPUT_FORMAT DECIMAL) # value is set to "1000"
|
||||
math(EXPR value "100 * 0xA" OUTPUT_FORMAT HEXADECIMAL) # value is set to "0x3e8"
|
||||
|
||||
Increment/Decrement
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
math(INCREMENT <variable>)
|
||||
math(DECREMENT <variable>)
|
||||
|
||||
.. versionadded:: 4.5
|
||||
|
||||
Take the value of ``<variable>``, increment/decrement it, and store the result back
|
||||
in ``<variable>``. The variable must be defined and be a valid base-10 integer.
|
||||
|
||||
4
Help/release/dev/math-increment-decrement.rst
Normal file
4
Help/release/dev/math-increment-decrement.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
math-increment-decrement
|
||||
------------------------
|
||||
|
||||
* The :command:`math` command gained new ``INCREMENT`` and ``DECREMENT`` modes.
|
||||
@@ -3,6 +3,11 @@
|
||||
#include "cmMathCommand.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <cm/string_view>
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include <cm3p/kwiml/int.h>
|
||||
|
||||
@@ -10,10 +15,16 @@
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmExprParserHelper.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
namespace {
|
||||
bool HandleExprCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status);
|
||||
bool HandleIncDecCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status, int amount,
|
||||
long long overflowFrom, long long overflowTo,
|
||||
cm::string_view verbing);
|
||||
}
|
||||
|
||||
bool cmMathCommand(std::vector<std::string> const& args,
|
||||
@@ -27,6 +38,16 @@ bool cmMathCommand(std::vector<std::string> const& args,
|
||||
if (subCommand == "EXPR") {
|
||||
return HandleExprCommand(args, status);
|
||||
}
|
||||
if (subCommand == "INCREMENT") {
|
||||
return HandleIncDecCommand(
|
||||
args, status, 1, std::numeric_limits<long long>::max(),
|
||||
std::numeric_limits<long long>::min(), "incrementing"_s);
|
||||
}
|
||||
if (subCommand == "DECREMENT") {
|
||||
return HandleIncDecCommand(
|
||||
args, status, -1, std::numeric_limits<long long>::min(),
|
||||
std::numeric_limits<long long>::max(), "decrementing"_s);
|
||||
}
|
||||
std::string e = "does not recognize sub-command " + subCommand;
|
||||
status.SetError(e);
|
||||
return false;
|
||||
@@ -117,4 +138,50 @@ bool HandleExprCommand(std::vector<std::string> const& args,
|
||||
status.GetMakefile().AddDefinition(outputVariable, buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleIncDecCommand(std::vector<std::string> const& args,
|
||||
cmExecutionStatus& status, int amount,
|
||||
long long overflowFrom, long long overflowTo,
|
||||
cm::string_view verbing)
|
||||
{
|
||||
std::string const messageHint = cmStrCat("sub-command ", args[0], " ");
|
||||
if (args.size() != 2) {
|
||||
status.SetError(cmStrCat(messageHint, "wrong number of arguments"));
|
||||
return false;
|
||||
}
|
||||
auto value = status.GetMakefile().GetDefinition(args[1]);
|
||||
if (!value) {
|
||||
status.SetError(
|
||||
cmStrCat(messageHint, "variable \"", args[1], "\" is not defined"));
|
||||
return false;
|
||||
}
|
||||
if (value->empty()) {
|
||||
status.SetError(
|
||||
cmStrCat(messageHint, "value \"\" is not a valid integer"));
|
||||
return false;
|
||||
}
|
||||
std::size_t pos = 0;
|
||||
long long intValue = 0;
|
||||
try {
|
||||
intValue = std::stoll(*value, &pos, 10);
|
||||
} catch (std::invalid_argument&) {
|
||||
// Do nothing, leave pos as is, which will trigger the error
|
||||
}
|
||||
if (pos != value->length()) {
|
||||
status.SetError(
|
||||
cmStrCat(messageHint, "value \"", *value, "\" is not a valid integer"));
|
||||
return false;
|
||||
}
|
||||
auto newValue = intValue + amount;
|
||||
if (intValue == overflowFrom) {
|
||||
status.GetMakefile().IssueDiagnostic(
|
||||
cmDiagnosticCategory::CMD_AUTHOR,
|
||||
cmStrCat("signed integer overflow while ", verbing, ":\n ", intValue,
|
||||
"\n"));
|
||||
// Overflow is undefined behavior in C++, so define it manually
|
||||
newValue = overflowTo;
|
||||
}
|
||||
status.GetMakefile().AddDefinition(args[1], std::to_string(newValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
1
Tests/RunCMake/math/MATH-DECREMENT-Empty-result.txt
Normal file
1
Tests/RunCMake/math/MATH-DECREMENT-Empty-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-DECREMENT-Empty-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-DECREMENT-Empty-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-DECREMENT-Empty\.cmake:[0-9]+ \(math\):
|
||||
math sub-command DECREMENT value "" is not a valid integer
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-DECREMENT-Empty.cmake
Normal file
2
Tests/RunCMake/math/MATH-DECREMENT-Empty.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value "")
|
||||
math(DECREMENT value)
|
||||
1
Tests/RunCMake/math/MATH-DECREMENT-Extra-result.txt
Normal file
1
Tests/RunCMake/math/MATH-DECREMENT-Extra-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-DECREMENT-Extra-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-DECREMENT-Extra-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-DECREMENT-Extra\.cmake:[0-9]+ \(math\):
|
||||
math sub-command DECREMENT value "0a" is not a valid integer
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-DECREMENT-Extra.cmake
Normal file
2
Tests/RunCMake/math/MATH-DECREMENT-Extra.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value 0a)
|
||||
math(DECREMENT value)
|
||||
1
Tests/RunCMake/math/MATH-DECREMENT-Invalid-result.txt
Normal file
1
Tests/RunCMake/math/MATH-DECREMENT-Invalid-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-DECREMENT-Invalid-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-DECREMENT-Invalid-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-DECREMENT-Invalid\.cmake:[0-9]+ \(math\):
|
||||
math sub-command DECREMENT value "notanint" is not a valid integer
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-DECREMENT-Invalid.cmake
Normal file
2
Tests/RunCMake/math/MATH-DECREMENT-Invalid.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value notanint)
|
||||
math(DECREMENT value)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-DECREMENT-NotEnoughArgs\.cmake:[0-9]+ \(math\):
|
||||
math sub-command DECREMENT wrong number of arguments
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
1
Tests/RunCMake/math/MATH-DECREMENT-NotEnoughArgs.cmake
Normal file
1
Tests/RunCMake/math/MATH-DECREMENT-NotEnoughArgs.cmake
Normal file
@@ -0,0 +1 @@
|
||||
math(DECREMENT)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-DECREMENT-TooManyArgs\.cmake:[0-9]+ \(math\):
|
||||
math sub-command DECREMENT wrong number of arguments
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
1
Tests/RunCMake/math/MATH-DECREMENT-TooManyArgs.cmake
Normal file
1
Tests/RunCMake/math/MATH-DECREMENT-TooManyArgs.cmake
Normal file
@@ -0,0 +1 @@
|
||||
math(DECREMENT value 1)
|
||||
1
Tests/RunCMake/math/MATH-DECREMENT-Undefined-result.txt
Normal file
1
Tests/RunCMake/math/MATH-DECREMENT-Undefined-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-DECREMENT-Undefined-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-DECREMENT-Undefined-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-DECREMENT-Undefined\.cmake:[0-9]+ \(math\):
|
||||
math sub-command DECREMENT variable "value" is not defined
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-DECREMENT-Undefined.cmake
Normal file
2
Tests/RunCMake/math/MATH-DECREMENT-Undefined.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value)
|
||||
math(DECREMENT value)
|
||||
1
Tests/RunCMake/math/MATH-INCREMENT-Empty-result.txt
Normal file
1
Tests/RunCMake/math/MATH-INCREMENT-Empty-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-INCREMENT-Empty-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-INCREMENT-Empty-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-INCREMENT-Empty\.cmake:[0-9]+ \(math\):
|
||||
math sub-command INCREMENT value "" is not a valid integer
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-INCREMENT-Empty.cmake
Normal file
2
Tests/RunCMake/math/MATH-INCREMENT-Empty.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value "")
|
||||
math(INCREMENT value)
|
||||
1
Tests/RunCMake/math/MATH-INCREMENT-Extra-result.txt
Normal file
1
Tests/RunCMake/math/MATH-INCREMENT-Extra-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-INCREMENT-Extra-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-INCREMENT-Extra-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-INCREMENT-Extra\.cmake:[0-9]+ \(math\):
|
||||
math sub-command INCREMENT value "0a" is not a valid integer
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-INCREMENT-Extra.cmake
Normal file
2
Tests/RunCMake/math/MATH-INCREMENT-Extra.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value 0a)
|
||||
math(INCREMENT value)
|
||||
1
Tests/RunCMake/math/MATH-INCREMENT-Invalid-result.txt
Normal file
1
Tests/RunCMake/math/MATH-INCREMENT-Invalid-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-INCREMENT-Invalid-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-INCREMENT-Invalid-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-INCREMENT-Invalid\.cmake:[0-9]+ \(math\):
|
||||
math sub-command INCREMENT value "notanint" is not a valid integer
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-INCREMENT-Invalid.cmake
Normal file
2
Tests/RunCMake/math/MATH-INCREMENT-Invalid.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value notanint)
|
||||
math(INCREMENT value)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-INCREMENT-NotEnoughArgs\.cmake:[0-9]+ \(math\):
|
||||
math sub-command INCREMENT wrong number of arguments
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
1
Tests/RunCMake/math/MATH-INCREMENT-NotEnoughArgs.cmake
Normal file
1
Tests/RunCMake/math/MATH-INCREMENT-NotEnoughArgs.cmake
Normal file
@@ -0,0 +1 @@
|
||||
math(INCREMENT)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-INCREMENT-TooManyArgs\.cmake:[0-9]+ \(math\):
|
||||
math sub-command INCREMENT wrong number of arguments
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
1
Tests/RunCMake/math/MATH-INCREMENT-TooManyArgs.cmake
Normal file
1
Tests/RunCMake/math/MATH-INCREMENT-TooManyArgs.cmake
Normal file
@@ -0,0 +1 @@
|
||||
math(INCREMENT value 1)
|
||||
1
Tests/RunCMake/math/MATH-INCREMENT-Undefined-result.txt
Normal file
1
Tests/RunCMake/math/MATH-INCREMENT-Undefined-result.txt
Normal file
@@ -0,0 +1 @@
|
||||
1
|
||||
4
Tests/RunCMake/math/MATH-INCREMENT-Undefined-stderr.txt
Normal file
4
Tests/RunCMake/math/MATH-INCREMENT-Undefined-stderr.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
^CMake Error at MATH-INCREMENT-Undefined\.cmake:[0-9]+ \(math\):
|
||||
math sub-command INCREMENT variable "value" is not defined
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
2
Tests/RunCMake/math/MATH-INCREMENT-Undefined.cmake
Normal file
2
Tests/RunCMake/math/MATH-INCREMENT-Undefined.cmake
Normal file
@@ -0,0 +1,2 @@
|
||||
set(value)
|
||||
math(INCREMENT value)
|
||||
@@ -10,3 +10,21 @@ math_test("100 * 10" 1000)
|
||||
math_test("100 * 10" 1000 OUTPUT_FORMAT DECIMAL)
|
||||
math_test("100 * 0xA" 1000 OUTPUT_FORMAT DECIMAL)
|
||||
math_test("100 * 0xA" 0x3e8 OUTPUT_FORMAT HEXADECIMAL)
|
||||
|
||||
function(inc_dec_test command initial_value expected)
|
||||
set(value "${initial_value}")
|
||||
math("${command}" value)
|
||||
if(NOT value STREQUAL "${expected}")
|
||||
message(FATAL_ERROR "wrong ${command} result: ${value} != ${expected}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
inc_dec_test(INCREMENT 0 1)
|
||||
inc_dec_test(INCREMENT 4 5)
|
||||
inc_dec_test(INCREMENT -04 -3)
|
||||
inc_dec_test(INCREMENT -9223372036854775808 -9223372036854775807)
|
||||
|
||||
inc_dec_test(DECREMENT 0 -1)
|
||||
inc_dec_test(DECREMENT 4 3)
|
||||
inc_dec_test(DECREMENT -04 -5)
|
||||
inc_dec_test(DECREMENT 9223372036854775807 9223372036854775806)
|
||||
|
||||
@@ -68,4 +68,26 @@ CMake Warning \(author\) at [^
|
||||
|
||||
-9223372036854775808
|
||||
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.
|
||||
|
||||
CMake Warning \(author\) at [^
|
||||
]+/Tests/RunCMake/math/Overflow\.cmake:[0-9]+ \(math\):
|
||||
signed integer overflow while incrementing:
|
||||
|
||||
9223372036854775807
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
[^
|
||||
]+/Tests/RunCMake/math/Overflow\.cmake:[0-9]+ \(inc_dec\)
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.
|
||||
|
||||
CMake Warning \(author\) at [^
|
||||
]+/Tests/RunCMake/math/Overflow\.cmake:[0-9]+ \(math\):
|
||||
signed integer overflow while decrementing:
|
||||
|
||||
-9223372036854775808
|
||||
|
||||
Call Stack \(most recent call first\):
|
||||
[^
|
||||
]+/Tests/RunCMake/math/Overflow\.cmake:[0-9]+ \(inc_dec\)
|
||||
This warning is for project developers\. Use -Wno-author to suppress it\.$
|
||||
|
||||
@@ -7,4 +7,6 @@
|
||||
-- 0x7FFFFFFFFFFFFFFF \+ 1: -9223372036854775808
|
||||
-- -0x7FFFFFFFFFFFFFFF - 2: 9223372036854775807
|
||||
-- 0x7FFFFFFFFFFFFFFF \* 2: -2
|
||||
-- -~0x7FFFFFFFFFFFFFFF: -9223372036854775808$
|
||||
-- -~0x7FFFFFFFFFFFFFFF: -9223372036854775808
|
||||
-- INCREMENT 9223372036854775807: -9223372036854775808
|
||||
-- DECREMENT -9223372036854775808: 9223372036854775807$
|
||||
|
||||
@@ -13,3 +13,12 @@ foreach(expr IN ITEMS
|
||||
math(EXPR result "${expr}")
|
||||
message(STATUS "${expr}: ${result}")
|
||||
endforeach()
|
||||
|
||||
function(inc_dec command value)
|
||||
set(new_value "${value}")
|
||||
math("${command}" new_value)
|
||||
message(STATUS "${command} ${value}: ${new_value}")
|
||||
endfunction()
|
||||
|
||||
inc_dec(INCREMENT 9223372036854775807)
|
||||
inc_dec(DECREMENT -9223372036854775808)
|
||||
|
||||
@@ -10,6 +10,18 @@ run_cmake(MATH-DivideByZero)
|
||||
run_cmake(MATH-ModByZero)
|
||||
run_cmake(MATH-DivideMinByMinusOne)
|
||||
run_cmake(MATH-ModMinByMinusOne)
|
||||
run_cmake(MATH-INCREMENT-NotEnoughArgs)
|
||||
run_cmake(MATH-INCREMENT-TooManyArgs)
|
||||
run_cmake(MATH-INCREMENT-Undefined)
|
||||
run_cmake(MATH-INCREMENT-Empty)
|
||||
run_cmake(MATH-INCREMENT-Invalid)
|
||||
run_cmake(MATH-INCREMENT-Extra)
|
||||
run_cmake(MATH-DECREMENT-NotEnoughArgs)
|
||||
run_cmake(MATH-DECREMENT-TooManyArgs)
|
||||
run_cmake(MATH-DECREMENT-Undefined)
|
||||
run_cmake(MATH-DECREMENT-Empty)
|
||||
run_cmake(MATH-DECREMENT-Invalid)
|
||||
run_cmake(MATH-DECREMENT-Extra)
|
||||
|
||||
if(CMake_TEST_MATH_OVERFLOW)
|
||||
run_cmake_script(Overflow)
|
||||
|
||||
Reference in New Issue
Block a user