aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/exception.hpp7
-rw-r--r--host/lib/exception.cpp1
-rw-r--r--host/lib/include/uhdlib/utils/narrow.hpp99
-rw-r--r--host/tests/CMakeLists.txt1
-rw-r--r--host/tests/narrow_cast_test.cpp21
5 files changed, 129 insertions, 0 deletions
diff --git a/host/include/uhd/exception.hpp b/host/include/uhd/exception.hpp
index 5ae5d790e..a8cbb8134 100644
--- a/host/include/uhd/exception.hpp
+++ b/host/include/uhd/exception.hpp
@@ -80,6 +80,13 @@ namespace uhd{
virtual void dynamic_throw(void) const;
};
+ struct UHD_API narrowing_error : value_error{
+ narrowing_error(const std::string &what);
+ virtual unsigned code(void) const;
+ virtual narrowing_error *dynamic_clone(void) const;
+ virtual void dynamic_throw(void) const;
+ };
+
struct UHD_API runtime_error : exception{
runtime_error(const std::string &what);
virtual unsigned code(void) const;
diff --git a/host/lib/exception.cpp b/host/lib/exception.cpp
index 3d39d901d..1a1ddb0ad 100644
--- a/host/lib/exception.cpp
+++ b/host/lib/exception.cpp
@@ -26,6 +26,7 @@ make_exception_impl("IndexError", index_error, lookup_err
make_exception_impl("KeyError", key_error, lookup_error)
make_exception_impl("TypeError", type_error, exception)
make_exception_impl("ValueError", value_error, exception)
+make_exception_impl("NarrowingError", narrowing_error, value_error)
make_exception_impl("RuntimeError", runtime_error, exception)
make_exception_impl("NotImplementedError", not_implemented_error, runtime_error)
make_exception_impl("EnvironmentError", environment_error, exception)
diff --git a/host/lib/include/uhdlib/utils/narrow.hpp b/host/lib/include/uhdlib/utils/narrow.hpp
new file mode 100644
index 000000000..feb7112f6
--- /dev/null
+++ b/host/lib/include/uhdlib/utils/narrow.hpp
@@ -0,0 +1,99 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+// This narrowing code is inspired by the guidelines support library by
+// Microsoft: https://github.com/Microsoft/GSL/
+//
+// The C++ guidelines are published here:
+// https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md
+//
+// There are some minor details between this implementation and the Microsoft
+// implementation, but they are similar (the main difference is the exception
+// type thrown).
+// The original code was published under the following license:
+//
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
+//
+// This code is licensed under the MIT License (MIT).
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// [End of GSL license]
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef INCLUDED_UHDLIB_UTILS_NARROW_HPP
+#define INCLUDED_UHDLIB_UTILS_NARROW_HPP
+
+#include <uhd/exception.hpp>
+#include <utility>
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4127) // conditional expression is constant
+#endif // _MSC_VER
+
+namespace uhd {
+
+/*! Static typecast which expresses intent of narrowing
+ *
+ * Use this for any conversion that narrows, e.g.:
+ *
+ * \code{.cpp}
+ * uint16_t x = peek16();
+ * uint8_t y = narrow_cast<uint8_t>(x);
+ * \endcode
+ */
+template <class T, class U>
+inline constexpr T narrow_cast(U&& u) noexcept
+{
+ return static_cast<T>(std::forward<U>(u));
+}
+
+/*! Like narrow_cast, but will throw an exception on failure.
+ *
+ * Call this if you're not sure if the cast will work as expected (e.g. when
+ * narrowing user input).
+ *
+ * \throws uhd::narrowing_error on failure
+ */
+template <class T, class U>
+inline T narrow(U u)
+{
+ T t = narrow_cast<T>(u);
+ if (static_cast<U>(t) != u) {
+ throw narrowing_error("");
+ }
+ if (!std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value>::value
+ && ((t < T{}) != (u < U{}))) {
+ throw narrowing_error("");
+ }
+ return t;
+}
+
+} /* namespace uhd */
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif // _MSC_VER
+
+#endif /* INCLUDED_UHDLIB_UTILS_NARROW_HPP */
diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt
index 7fcf1652c..6f78f8d3e 100644
--- a/host/tests/CMakeLists.txt
+++ b/host/tests/CMakeLists.txt
@@ -27,6 +27,7 @@ SET(test_sources
gain_group_test.cpp
log_test.cpp
math_test.cpp
+ narrow_cast_test.cpp
property_test.cpp
ranges_test.cpp
sid_t_test.cpp
diff --git a/host/tests/narrow_cast_test.cpp b/host/tests/narrow_cast_test.cpp
new file mode 100644
index 000000000..2f784bfe3
--- /dev/null
+++ b/host/tests/narrow_cast_test.cpp
@@ -0,0 +1,21 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+#include <uhd/exception.hpp>
+#include <../lib/include/uhdlib/utils/narrow.hpp>
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+using namespace uhd;
+
+BOOST_AUTO_TEST_CASE(test_narrow){
+ uint16_t x = 5;
+ uint8_t y = narrow_cast<uint8_t>(x);
+ BOOST_CHECK_EQUAL(x, y);
+
+ BOOST_CHECK_THROW(narrow<uint8_t>(uint16_t(1<<10)), narrowing_error);
+ BOOST_CHECK_THROW(narrow<uint8_t>(int8_t(-1)), narrowing_error);
+}