1 // Copyright (c) 2011, Robert Escriva 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright 10 // notice, this list of conditions and the following disclaimer in the 11 // documentation and/or other materials provided with the distribution. 12 // * Neither the name of this project nor the names of its contributors may 13 // be used to endorse or promote products derived from this software 14 // without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 // POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef e_convert_h_ 29 #define e_convert_h_ 30 31 // C 32 #include <stdint.h> 33 #include <stdlib.h> 34 35 // STL 36 #include <stdexcept> 37 #include <string> 38 39 // POSIX 40 #include <errno.h> 41 42 namespace e 43 { 44 namespace convert 45 { 46 47 // These have the same gotchas inherent to stro*. I plan to someday extend them 48 // to safely convert integers, but until then they just ease usage of strto* 49 // without fixing the problem. 50 51 inline uint64_t 52 to_uint64_t(const std::string& s, int base = 0) 53 { 54 int olderrno = errno; 55 int newerrno; 56 char* endptr; 57 unsigned long long int ret; 58 59 errno = 0; 60 #ifdef _MSC_VER 61 ret = _strtoui64(s.c_str(), &endptr, base); 62 #else 63 ret = strtoull(s.c_str(), &endptr, base); 64 #endif 65 newerrno = errno; 66 errno = olderrno; 67 68 if (*endptr != '\0' || newerrno == EINVAL) 69 { 70 throw std::domain_error("The number is not valid for the given base."); 71 } 72 if (newerrno == ERANGE || static_cast<uint64_t>(ret) != ret) 73 { 74 throw std::out_of_range("The number does not fit in a uint64_t"); 75 } 76 77 return static_cast<uint64_t>(ret); 78 } 79 80 inline uint32_t 81 to_uint32_t(const std::string& s, int base = 0) 82 { 83 int olderrno = errno; 84 int newerrno; 85 char* endptr; 86 unsigned long int ret; 87 88 errno = 0; 89 ret = strtoul(s.c_str(), &endptr, base); 90 newerrno = errno; 91 errno = olderrno; 92 93 if (*endptr != '\0' || newerrno == EINVAL) 94 { 95 throw std::domain_error("The number is not valid for the given base."); 96 } 97 if (newerrno == ERANGE || static_cast<uint32_t>(ret) != ret) 98 { 99 throw std::out_of_range("The number does not fit in a uint32_t"); 100 } 101 102 return static_cast<uint32_t>(ret); 103 } 104 105 inline uint16_t 106 to_uint16_t(const std::string& s, int base = 0) 107 { 108 int olderrno = errno; 109 int newerrno; 110 char* endptr; 111 unsigned long int ret; 112 113 errno = 0; 114 ret = strtoul(s.c_str(), &endptr, base); 115 newerrno = errno; 116 errno = olderrno; 117 118 if (*endptr != '\0' || newerrno == EINVAL) 119 { 120 throw std::domain_error("The number is not valid for the given base."); 121 } 122 if (newerrno == ERANGE || static_cast<uint16_t>(ret) != ret) 123 { 124 throw std::out_of_range("The number does not fit in a uint16_t"); 125 } 126 127 return static_cast<uint16_t>(ret); 128 } 129 130 inline uint8_t 131 to_uint8_t(const std::string& s, int base = 0) 132 { 133 int olderrno = errno; 134 int newerrno; 135 char* endptr; 136 unsigned long int ret; 137 138 errno = 0; 139 ret = strtoul(s.c_str(), &endptr, base); 140 newerrno = errno; 141 errno = olderrno; 142 143 if (*endptr != '\0' || newerrno == EINVAL) 144 { 145 throw std::domain_error("The number is not valid for the given base."); 146 } 147 if (newerrno == ERANGE || (ret & 0xff) != ret) 148 { 149 throw std::out_of_range("The number does not fit in a uint8_t"); 150 } 151 152 return static_cast<uint8_t>(ret); 153 } 154 155 } // namespace convert 156 } // namespace e 157 158 #endif // e_convert_h_ 159