1 /*************************************************************************** 2 * Copyright (C) 2008-2021 by Andrzej Rybczak * 3 * andrzej@rybczak.net * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 * * 10 * This program is distributed in the hope that it will be useful, * 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 * GNU General Public License for more details. * 14 * * 15 * You should have received a copy of the GNU General Public License * 16 * along with this program; if not, write to the * 17 * Free Software Foundation, Inc., * 18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * 19 ***************************************************************************/ 20 21 #ifndef NCMPCPP_UTILITY_CONVERSION_H 22 #define NCMPCPP_UTILITY_CONVERSION_H 23 24 #include <boost/format.hpp> 25 #include <boost/lexical_cast.hpp> 26 #include <boost/type_traits/is_unsigned.hpp> 27 28 #include "config.h" 29 #include "gcc.h" 30 31 struct ConversionError 32 { ConversionErrorConversionError33 ConversionError(std::string source) : m_source_value(source) { } 34 valueConversionError35 const std::string &value() { return m_source_value; } 36 37 private: 38 std::string m_target_type; 39 std::string m_source_value; 40 }; 41 42 struct OutOfBounds : std::exception 43 { errorMessageOutOfBounds44 const std::string &errorMessage() { return m_error_message; } 45 46 template <typename Type> raiseOutOfBounds47 GNUC_NORETURN static void raise(const Type &value, const Type &lbound, const Type &ubound) 48 { 49 throw OutOfBounds((boost::format( 50 "value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str()); 51 } 52 53 template <typename Type> raiseLowerOutOfBounds54 GNUC_NORETURN static void raiseLower(const Type &value, const Type &lbound) 55 { 56 throw OutOfBounds((boost::format( 57 "value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str()); 58 } 59 60 template <typename Type> raiseUpperOutOfBounds61 GNUC_NORETURN static void raiseUpper(const Type &value, const Type &ubound) 62 { 63 throw OutOfBounds((boost::format( 64 "value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str()); 65 } 66 whatOutOfBounds67 virtual const char *what() const noexcept override { return m_error_message.c_str(); } 68 69 private: OutOfBoundsOutOfBounds70 OutOfBounds(std::string msg) : m_error_message(msg) { } 71 72 std::string m_error_message; 73 }; 74 75 template <typename TargetT, bool isUnsigned> 76 struct unsigned_checker 77 { applyunsigned_checker78 static void apply(const std::string &) { } 79 }; 80 template <typename TargetT> 81 struct unsigned_checker<TargetT, true> 82 { 83 static void apply(const std::string &s) 84 { 85 if (s[0] == '-') 86 throw ConversionError(s); 87 } 88 }; 89 90 template <typename TargetT> 91 TargetT fromString(const std::string &source) 92 { 93 unsigned_checker<TargetT, boost::is_unsigned<TargetT>::value>::apply(source); 94 try 95 { 96 return boost::lexical_cast<TargetT>(source); 97 } 98 catch (boost::bad_lexical_cast &) 99 { 100 throw ConversionError(source); 101 } 102 } 103 104 template <typename Type> 105 void boundsCheck(const Type &value, const Type &lbound, const Type &ubound) 106 { 107 if (value < lbound || value > ubound) 108 OutOfBounds::raise(value, lbound, ubound); 109 } 110 111 template <typename Type> 112 void lowerBoundCheck(const Type &value, const Type &lbound) 113 { 114 if (value < lbound) 115 OutOfBounds::raiseLower(value, lbound); 116 } 117 118 template <typename Type> 119 void upperBoundCheck(const Type &value, const Type &ubound) 120 { 121 if (value > ubound) 122 OutOfBounds::raiseUpper(value, ubound); 123 } 124 125 #endif // NCMPCPP_UTILITY_CONVERSION_H 126