1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * Copyright (c) 2018 Andrey Semashev
7  */
8 /*!
9  * \file   atomic/detail/integral_extend.hpp
10  *
11  * This header defines sign/zero extension utilities for Boost.Atomic. The tools assume two's complement signed integer representation.
12  */
13 
14 #ifndef BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_
15 #define BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_
16 
17 #include <boost/atomic/detail/config.hpp>
18 #include <boost/atomic/detail/bitwise_cast.hpp>
19 #include <boost/atomic/detail/type_traits/integral_constant.hpp>
20 #include <boost/atomic/detail/type_traits/is_signed.hpp>
21 #include <boost/atomic/detail/type_traits/make_signed.hpp>
22 #include <boost/atomic/detail/type_traits/make_unsigned.hpp>
23 
24 #ifdef BOOST_HAS_PRAGMA_ONCE
25 #pragma once
26 #endif
27 
28 namespace boost {
29 namespace atomics {
30 namespace detail {
31 
32 template< typename Output, typename Input >
zero_extend_impl(Input input,atomics::detail::true_type)33 BOOST_FORCEINLINE Output zero_extend_impl(Input input, atomics::detail::true_type) BOOST_NOEXCEPT
34 {
35     // Note: If we are casting with truncation or to the same-sized output, don't cause signed integer overflow by this chain of conversions
36     return atomics::detail::bitwise_cast< Output >(static_cast< typename atomics::detail::make_unsigned< Output >::type >(
37         static_cast< typename atomics::detail::make_unsigned< Input >::type >(input)));
38 }
39 
40 template< typename Output, typename Input >
zero_extend_impl(Input input,atomics::detail::false_type)41 BOOST_FORCEINLINE Output zero_extend_impl(Input input, atomics::detail::false_type) BOOST_NOEXCEPT
42 {
43     return static_cast< Output >(static_cast< typename atomics::detail::make_unsigned< Input >::type >(input));
44 }
45 
46 //! Zero-extends or truncates (wraps) input operand to fit in the output type
47 template< typename Output, typename Input >
zero_extend(Input input)48 BOOST_FORCEINLINE Output zero_extend(Input input) BOOST_NOEXCEPT
49 {
50     return atomics::detail::zero_extend_impl< Output >(input, atomics::detail::integral_constant< bool, atomics::detail::is_signed< Output >::value >());
51 }
52 
53 //! Truncates (wraps) input operand to fit in the output type
54 template< typename Output, typename Input >
integral_truncate(Input input)55 BOOST_FORCEINLINE Output integral_truncate(Input input) BOOST_NOEXCEPT
56 {
57     // zero_extend does the truncation
58     return atomics::detail::zero_extend< Output >(input);
59 }
60 
61 template< typename Output, typename Input >
sign_extend_impl(Input input,atomics::detail::true_type)62 BOOST_FORCEINLINE Output sign_extend_impl(Input input, atomics::detail::true_type) BOOST_NOEXCEPT
63 {
64     return atomics::detail::integral_truncate< Output >(input);
65 }
66 
67 template< typename Output, typename Input >
sign_extend_impl(Input input,atomics::detail::false_type)68 BOOST_FORCEINLINE Output sign_extend_impl(Input input, atomics::detail::false_type) BOOST_NOEXCEPT
69 {
70     return static_cast< Output >(atomics::detail::bitwise_cast< typename atomics::detail::make_signed< Input >::type >(input));
71 }
72 
73 //! Sign-extends or truncates (wraps) input operand to fit in the output type
74 template< typename Output, typename Input >
sign_extend(Input input)75 BOOST_FORCEINLINE Output sign_extend(Input input) BOOST_NOEXCEPT
76 {
77     return atomics::detail::sign_extend_impl< Output >(input, atomics::detail::integral_constant< bool, sizeof(Output) <= sizeof(Input) >());
78 }
79 
80 //! Sign-extends or truncates (wraps) input operand to fit in the output type
81 template< typename Output, typename Input >
integral_extend(Input input,atomics::detail::true_type)82 BOOST_FORCEINLINE Output integral_extend(Input input, atomics::detail::true_type) BOOST_NOEXCEPT
83 {
84     return atomics::detail::sign_extend< Output >(input);
85 }
86 
87 //! Zero-extends or truncates (wraps) input operand to fit in the output type
88 template< typename Output, typename Input >
integral_extend(Input input,atomics::detail::false_type)89 BOOST_FORCEINLINE Output integral_extend(Input input, atomics::detail::false_type) BOOST_NOEXCEPT
90 {
91     return atomics::detail::zero_extend< Output >(input);
92 }
93 
94 //! Sign- or zero-extends or truncates (wraps) input operand to fit in the output type
95 template< bool Signed, typename Output, typename Input >
integral_extend(Input input)96 BOOST_FORCEINLINE Output integral_extend(Input input) BOOST_NOEXCEPT
97 {
98     return atomics::detail::integral_extend< Output >(input, atomics::detail::integral_constant< bool, Signed >());
99 }
100 
101 } // namespace detail
102 } // namespace atomics
103 } // namespace boost
104 
105 #endif // BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_
106