diff --git a/UnitTests/UnitTests.vcxproj b/UnitTests/UnitTests.vcxproj
index b6cd49e05..cdc137988 100644
--- a/UnitTests/UnitTests.vcxproj
+++ b/UnitTests/UnitTests.vcxproj
@@ -116,6 +116,7 @@
+
Create
diff --git a/UnitTests/UnitTests.vcxproj.filters b/UnitTests/UnitTests.vcxproj.filters
index 05a4e21ce..a1d5947e6 100644
--- a/UnitTests/UnitTests.vcxproj.filters
+++ b/UnitTests/UnitTests.vcxproj.filters
@@ -27,6 +27,9 @@
Source Files
+
+ Source Files
+
diff --git a/UnitTests/math.cpp b/UnitTests/math.cpp
new file mode 100644
index 000000000..9975c3dd6
--- /dev/null
+++ b/UnitTests/math.cpp
@@ -0,0 +1,42 @@
+/*
+ SPDX-License-Identifier: MIT
+ Copyright © 2023 Amebis
+*/
+
+#include "pch.h"
+
+using namespace std;
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace UnitTests
+{
+ TEST_CLASS(math)
+ {
+ public:
+ TEST_METHOD(mul)
+ {
+ Assert::AreEqual(10, stdex::mul(2, 5));
+ Assert::AreEqual(10, stdex::mul(5, 2));
+ Assert::AreEqual(0, stdex::mul(0, 10));
+ Assert::AreEqual(0, stdex::mul(10, 0));
+ Assert::AreEqual(0, stdex::mul(SIZE_MAX, 0));
+ Assert::AreEqual(0, stdex::mul(0, SIZE_MAX));
+ Assert::AreEqual(SIZE_MAX, stdex::mul(SIZE_MAX, 1));
+ Assert::AreEqual(SIZE_MAX, stdex::mul(1, SIZE_MAX));
+ Assert::ExpectException([] { stdex::mul(SIZE_MAX, 2); });
+ Assert::ExpectException([] { stdex::mul(2, SIZE_MAX); });
+ }
+
+ TEST_METHOD(add)
+ {
+ Assert::AreEqual(7, stdex::add(2, 5));
+ Assert::AreEqual(7, stdex::add(5, 2));
+ Assert::AreEqual(10, stdex::add(0, 10));
+ Assert::AreEqual(10, stdex::add(10, 0));
+ Assert::AreEqual(SIZE_MAX, stdex::add(SIZE_MAX, 0));
+ Assert::AreEqual(SIZE_MAX, stdex::add(0, SIZE_MAX));
+ Assert::ExpectException([] { stdex::add(SIZE_MAX, 1); });
+ Assert::ExpectException([] { stdex::add(1, SIZE_MAX); });
+ }
+ };
+}
diff --git a/UnitTests/pch.h b/UnitTests/pch.h
index 6016f700e..b7d7f5037 100644
--- a/UnitTests/pch.h
+++ b/UnitTests/pch.h
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/stdex/math.hpp b/include/stdex/math.hpp
new file mode 100644
index 000000000..73427a34d
--- /dev/null
+++ b/include/stdex/math.hpp
@@ -0,0 +1,49 @@
+/*
+ SPDX-License-Identifier: MIT
+ Copyright © 2023 Amebis
+*/
+
+#pragma once
+
+#include "sal.hpp"
+#include "system.hpp"
+#include
+
+namespace stdex
+{
+ inline size_t mul(size_t a, size_t b)
+ {
+#if _MSC_VER >= 1300
+ SIZE_T result;
+ if (SUCCEEDED(SIZETMult(a, b, &result)))
+ return result;
+#elif defined(_MSC_VER)
+ if (a == 0)
+ return 0;
+ if (b <= SIZE_MAX / a)
+ return a * b;
+#else
+ size_t result;
+ if (!__builtin_mul_overflow(a, b, &result))
+ return result;
+#endif
+ throw std::invalid_argument("multiply overflow");
+ }
+
+ inline size_t add(size_t a, size_t b)
+ {
+#if _MSC_VER >= 1300
+ SIZE_T result;
+ if (SUCCEEDED(SIZETAdd(a, b, &result)))
+ return result;
+#elif defined(_MSC_VER)
+ if (a <= SIZE_MAX - b)
+ return a + b;
+#else
+ size_t result;
+ if (!__builtin_add_overflow(a, b, &result))
+ return result;
+#endif
+ throw std::invalid_argument("add overflow");
+ }
+}
\ No newline at end of file