gta base: add support for gcc's __int128 and __float128 types
authorMartin Lambers <marlam@marlam.de>
Sun, 12 Oct 2014 12:09:13 +0000 (14:09 +0200)
committerMartin Lambers <marlam@marlam.de>
Sun, 12 Oct 2014 20:12:20 +0000 (22:12 +0200)
gtatool/configure.ac
gtatool/src/base/str.cpp
gtatool/src/base/str.h

index cb3750a..e2b054d 100644 (file)
@@ -148,6 +148,11 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], [], [CPPFLAGS="$CPPFLAGS_bak"; LDFLAGS=
 dnl - str
 AM_ICONV([])
 AC_CHECK_FUNCS([nl_langinfo vasprintf wcswidth])
+AC_CHECK_TYPES([int128_t, uint128_t], [], [], [[#include <cstdint>]])
+AC_CHECK_TYPES([__int128, unsigned __int128])
+AC_CHECK_TYPES([__float128])
+AC_SEARCH_LIBS([strtoflt128], [quadmath])
+dnl TODO: define LONG_DOUBLE_IS_IEEE_754_QUAD on systems where this is true
 dnl - sys
 AC_CHECK_FUNCS([nanosleep sysconf sched_yield])
 dnl - tmr
index bf394eb..4db6035 100644 (file)
@@ -25,7 +25,6 @@
 #include <cerrno>
 #include <cstring>
 #include <limits>
-#include <sstream>
 #include <locale>
 #include <cwchar>
 #include <stdexcept>
 # include <iconv.h>
 #endif
 
+#ifdef HAVE___INT128
+# define INT128_MAX (__int128) (((unsigned __int128) 1 << 127) - 1)
+# define INT128_MIN (-INT128_MAX - 1)
+#endif
+#ifdef HAVE_UNSIGNED___INT128
+# define UINT128_MAX ((((unsigned __int128) 1 << 127) << 1) - 1)
+#endif
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+# include <quadmath.h>
+#endif
+
 #include "base/gettext.h"
 #define _(string) gettext(string)
 
@@ -72,20 +82,266 @@ static int vasprintf(char **strp, const char *format, va_list args)
 }
 #endif
 
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+__int128 strtoi128(const char* nptr, char** endptr, int base)
+{
+    // Adapted for __int128 from the following source:
+
+    /* $NetBSD: strtol.c,v 1.17 2005/11/29 03:12:00 christos Exp $     */
+
+    /*-
+     * Copyright (c) 1990, 1993
+     * The Regents of the University of California.  All rights reserved.
+     *
+     * Redistribution and use in source and binary forms, with or without
+     * modification, are permitted provided that the following conditions
+     * are met:
+     * 1. Redistributions of source code must retain the above copyright
+     *    notice, this list of conditions and the following disclaimer.
+     * 2. Redistributions in binary form must reproduce the above copyright
+     *    notice, this list of conditions and the following disclaimer in the
+     *    documentation and/or other materials provided with the distribution.
+     * 3. Neither the name of the University nor the names of its contributors
+     *    may be used to endorse or promote products derived from this software
+     *    without specific prior written permission.
+     *
+     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+     * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+     * SUCH DAMAGE.
+     */
+
+    /*
+     * Convert a string to a long integer.
+     *
+     * Ignores `locale' stuff.  Assumes that the upper and lower case
+     * alphabets and digits are each contiguous.
+     */
+
+    const char *s;
+    __int128 acc, cutoff;
+    int c;
+    int neg, any, cutlim;
+
+    /*
+     * Skip white space and pick up leading +/- sign if any.
+     * If base is 0, allow 0x for hex and 0 for octal, else
+     * assume decimal; if base is already 16, allow 0x.
+     */
+    s = nptr;
+    do {
+        c = (unsigned char) *s++;
+    } while (c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v');
+    if (c == '-') {
+        neg = 1;
+        c = *s++;
+    } else {
+        neg = 0;
+        if (c == '+')
+            c = *s++;
+    }
+    if ((base == 0 || base == 16) &&
+            c == '0' && (*s == 'x' || *s == 'X')) {
+        c = s[1];
+        s += 2;
+        base = 16;
+    }
+    if (base == 0)
+        base = c == '0' ? 8 : 10;
+
+    /*
+     * Compute the cutoff value between legal numbers and illegal
+     * numbers.  That is the largest legal value, divided by the
+     * base.  An input number that is greater than this value, if
+     * followed by a legal input character, is too big.  One that
+     * is equal to this value may be valid or not; the limit
+     * between valid and invalid numbers is then based on the last
+     * digit.  For instance, if the range for longs is
+     * [-2147483648..2147483647] and the input base is 10,
+     * cutoff will be set to 214748364 and cutlim to either
+     * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+     * a value > 214748364, or equal but the next digit is > 7 (or 8),
+     * the number is too big, and we will return a range error.
+     *
+     * Set any if any `digits' consumed; make it negative to indicate
+     * overflow.
+     */
+    cutoff = neg ? INT128_MIN : INT128_MAX;
+    cutlim = (int)(cutoff % base);
+    cutoff /= base;
+    if (neg) {
+        if (cutlim > 0) {
+            cutlim -= base;
+            cutoff += 1;
+        }
+        cutlim = -cutlim;
+    }
+    for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+        if (c >= '0' && c <= '9')
+            c -= '0';
+        else if (c >= 'a' && c <= 'a')
+            c -= 'a' - 10;
+        else if (c >= 'A' && c <= 'Z')
+            c -= 'A' - 10;
+        else
+            break;
+        if (c >= base)
+            break;
+        if (any < 0)
+            continue;
+        if (neg) {
+            if (acc < cutoff || (acc == cutoff && c > cutlim)) {
+                any = -1;
+                acc = INT128_MIN;
+                errno = ERANGE;
+            } else {
+                any = 1;
+                acc *= base;
+                acc -= c;
+            }
+        } else {
+            if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+                any = -1;
+                acc = INT128_MAX;
+                errno = ERANGE;
+            } else {
+                any = 1;
+                acc *= base;
+                acc += c;
+            }
+        }
+    }
+    if (endptr != 0)
+        *endptr = const_cast<char*>(any ? s - 1 : nptr);
+    return (acc);
+}
+#endif
+
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+unsigned __int128 strtoui128(const char* nptr, char** endptr, int base)
+{
+    // Adapted for __int128 from the following source:
+
+    /* $NetBSD: strtoul.c,v 1.17 2005/11/29 03:12:00 christos Exp $    */
+
+    /*
+     * Copyright (c) 1990, 1993
+     * The Regents of the University of California.  All rights reserved.
+     *
+     * Redistribution and use in source and binary forms, with or without
+     * modification, are permitted provided that the following conditions
+     * are met:
+     * 1. Redistributions of source code must retain the above copyright
+     *    notice, this list of conditions and the following disclaimer.
+     * 2. Redistributions in binary form must reproduce the above copyright
+     *    notice, this list of conditions and the following disclaimer in the
+     *    documentation and/or other materials provided with the distribution.
+     * 3. Neither the name of the University nor the names of its contributors
+     *    may be used to endorse or promote products derived from this software
+     *    without specific prior written permission.
+     *
+     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+     * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+     * SUCH DAMAGE.
+     */
+
+    /*
+     * Convert a string to an unsigned long integer.
+     *
+     * Ignores `locale' stuff.  Assumes that the upper and lower case
+     * alphabets and digits are each contiguous.
+     */
+
+    const char *s;
+    unsigned __int128 acc, cutoff;
+    int c;
+    int neg, any, cutlim;
+
+    /*
+     * See strtol for comments as to the logic used.
+     */
+    s = nptr;
+    do {
+        c = (unsigned char) *s++;
+    } while (c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v');
+    if (c == '-') {
+        neg = 1;
+        c = *s++;
+    } else {
+        neg = 0;
+        if (c == '+')
+            c = *s++;
+    }
+    if ((base == 0 || base == 16) &&
+            c == '0' && (*s == 'x' || *s == 'X')) {
+        c = s[1];
+        s += 2;
+        base = 16;
+    }
+    if (base == 0)
+        base = c == '0' ? 8 : 10;
+
+    cutoff = UINT128_MAX / base;
+    cutlim = (int)(UINT128_MAX % base);
+    for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+        if (c >= base)
+            break;
+        if (c >= '0' && c <= '9')
+            c -= '0';
+        else if (c >= 'a' && c <= 'a')
+            c -= 'a' - 10;
+        else if (c >= 'A' && c <= 'Z')
+            c -= 'A' - 10;
+        else
+            break;
+        if (any < 0)
+            continue;
+        if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+            any = -1;
+            acc = UINT128_MAX;
+            errno = ERANGE;
+        } else {
+            any = 1;
+            acc *= (unsigned long)base;
+            acc += c;
+        }
+    }
+    if (neg && any > 0)
+        acc = -acc;
+    if (endptr != 0)
+        *endptr = const_cast<char*>(any ? s - 1 : nptr);
+    return (acc);
+}
+#endif
+
 /* Convert an unsigned integer to a string.
  * We hide this function so that it cannot be called with invalid arguments. */
 template<typename T>
 static inline std::string uint_to_str(T x)
 {
-    std::string s;
-    do
-    {
-        // this assumes an ASCII-compatible character set
-        s.insert(0, 1, '0' + x % 10);
+    size_t size = sizeof(T) * 8 / 3 + 1;
+    char buf[size];
+    int i = size;
+    do {
+        buf[--i] = '0' + x % 10; // this assumes an ASCII-compatible character set
         x /= 10;
-    }
-    while (x != 0);
-    return s;
+    } while (x != 0);
+    return std::string(buf + i, size - i);
 }
 
 /* Convert a signed integer to a string.
@@ -93,34 +349,111 @@ static inline std::string uint_to_str(T x)
 template<typename T>
 static inline std::string int_to_str(T x)
 {
-    std::string s;
-    bool negative = (x < 0);
-    do
-    {
-        // this assumes an ASCII-compatible character set
-        s.insert(0, 1, (negative ? ('0' - x % 10) : ('0' + x % 10)));
-        x /= 10;
-    }
-    while (x != 0);
-    if (negative)
-    {
-        s.insert(0, 1, '-');
+    size_t size = sizeof(T) * 8 / 3 + 1 + 1 /* sign */;
+    char buf[size];
+    int i = size;
+    if (x < 0) {
+        do {
+            buf[--i] = '0' - x % 10; // this assumes an ASCII-compatible character set
+            x /= 10;
+        } while (x != 0);
+        buf[--i] = '-';
+    } else {
+        do {
+            buf[--i] = '0' + x % 10; // this assumes an ASCII-compatible character set
+            x /= 10;
+        } while (x != 0);
     }
-    return s;
+    return std::string(buf + i, size - i);
 }
 
-/* Convert a floating point number (float, double, long double) to a string.
+/* Convert a floating point representation to a string.
  * We hide this function so that it cannot be called with invalid arguments. */
+template<typename T> static int float_startbufsize() { return 1 << 30; /* will never be called */ }
+template<> int float_startbufsize<float>() { return 32; }
+template<> int float_startbufsize<double>() { return 64; }
+template<> int float_startbufsize<long double>() { return 128; }
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+template<> int float_startbufsize<__float128>() { return 128; }
+#endif
+template<typename T> static int float_snprintf(char* str, size_t size, T x) { return -1; /* will never be called */ }
+template<> int float_snprintf<float>(char* str, size_t size, float x) { return snprintf(str, size, "%.9g", x); }
+template<> int float_snprintf<double>(char* str, size_t size, double x) { return snprintf(str, size, "%.17g", x); }
+template<> int float_snprintf<long double>(char* str, size_t size, long double x) { return snprintf(str, size, "%.36Lg", x); }
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+template<> int float_snprintf<__float128>(char* str, size_t size, __float128 x) { return quadmath_snprintf(str, size, "%.36Qg", x); }
+#endif
 template<typename T>
 static inline std::string float_to_str(T x)
 {
-    std::ostringstream os;
-    os.imbue(std::locale::classic());
-    os.precision(std::numeric_limits<T>::digits10 + 1);
-    os << x;
-    return os.str();
+    const int startsize = float_startbufsize<T>();
+    char buf[startsize];
+    int length = float_snprintf(buf, startsize, x);
+    if (length < startsize) {
+        return std::string(buf, length);
+    } else {
+        std::vector<char> buf2(length + 1);
+        length = float_snprintf<T>(&buf2[0], length + 1, x);
+        return std::string(&buf2[0], length);
+    }
 }
 
+/* Read a number from a string.
+ * We hide this function so that it cannot be called with invalid arguments. */
+template<typename T> static T str_to_small_int(const char* nptr, char** endptr, int base)
+{
+    long x = std::strtol(nptr, endptr, base);
+    if (std::numeric_limits<T>::is_signed && x < std::numeric_limits<T>::min()) {
+        x = std::numeric_limits<T>::min();
+        errno = ERANGE;
+    } else if (x > std::numeric_limits<T>::max()) {
+        x = std::numeric_limits<T>::max();
+        errno = ERANGE;
+    }
+    return x;
+}
+template<typename T> static T strtox(const char* nptr, char** endptr, int base) { return 0; /* will never be called */ }
+template<> signed char strtox<signed char>(const char* nptr, char** endptr, int base) { return str_to_small_int<signed char>(nptr, endptr, base); }
+template<> unsigned char strtox<unsigned char>(const char* nptr, char** endptr, int base) { return str_to_small_int<unsigned char>(nptr, endptr, base); }
+template<> short strtox<short>(const char* nptr, char** endptr, int base) { return str_to_small_int<short>(nptr, endptr, base); }
+template<> unsigned short strtox<unsigned short>(const char* nptr, char** endptr, int base) { return str_to_small_int<unsigned short>(nptr, endptr, base); }
+template<> int strtox<int>(const char* nptr, char** endptr, int base) { return str_to_small_int<int>(nptr, endptr, base); }
+template<> unsigned int strtox<unsigned int>(const char* nptr, char** endptr, int base) { return str_to_small_int<unsigned int>(nptr, endptr, base); }
+template<> long strtox<long>(const char* nptr, char** endptr, int base) { return std::strtol(nptr, endptr, base); }
+template<> unsigned long strtox<unsigned long>(const char* nptr, char** endptr, int base) { return std::strtoul(nptr, endptr, base); }
+template<> long long strtox<long long>(const char* nptr, char** endptr, int base) { return std::strtoll(nptr, endptr, base); }
+template<> unsigned long long strtox<unsigned long long>(const char* nptr, char** endptr, int base) { return std::strtoull(nptr, endptr, base); }
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+template<> __int128 strtox<__int128>(const char* nptr, char** endptr, int base) { return strtoi128(nptr, endptr, base); }
+#endif
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+template<> unsigned __int128 strtox<unsigned __int128>(const char* nptr, char** endptr, int base) { return strtoui128(nptr, endptr, base); }
+#endif
+template<> float strtox<float>(const char* nptr, char** endptr, int /* base */) { return std::strtof(nptr, endptr); }
+template<> double strtox<double>(const char* nptr, char** endptr, int /* base */) { return std::strtod(nptr, endptr); }
+template<> long double strtox<long double>(const char* nptr, char** endptr, int /* base */) { return std::strtold(nptr, endptr); }
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+template<> __float128 strtox<__float128>(const char* nptr, char** endptr, int /* base */) { return strtoflt128(nptr, endptr); }
+#endif
+template<typename T>
+static inline T str_to(const std::string& s, const char* t)
+{
+    T r;
+    const char* str = s.c_str();
+    char* p;
+    int errnobak = errno;
+    errno = 0;
+    char* localebak = setlocale(LC_NUMERIC, NULL);
+    setlocale(LC_NUMERIC, "");
+    r = strtox<T>(str, &p, 0);
+    setlocale(LC_NUMERIC, localebak);
+    if (p == str || errno == ERANGE || *p != '\0') {
+        errno = errnobak;
+        throw std::invalid_argument(str::asprintf(_("Cannot convert string to %s."), t));
+    }
+    errno = errnobak;
+    return r;
+}
 
 namespace str
 {
@@ -191,7 +524,7 @@ namespace str
 
     std::string from(bool x)
     {
-        return std::string(x ? "0" : "1");
+        return std::string(1, x ? '1' : '0');
     }
 
     std::string from(signed char x)
@@ -244,6 +577,20 @@ namespace str
         return uint_to_str(x);
     }
 
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+    std::string from(__int128 x)
+    {
+        return int_to_str(x);
+    }
+#endif
+
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+    std::string from(unsigned __int128 x)
+    {
+        return uint_to_str(x);
+    }
+#endif
+
     std::string from(float x)
     {
         return float_to_str(x);
@@ -259,35 +606,90 @@ namespace str
         return float_to_str(x);
     }
 
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+    std::string from(__float128 x)
+    {
+        return float_to_str(x);
+    }
+#endif
+
     /* Convert a string to one of the basic data types */
 
-    template<typename T>
-    static inline T _to(const std::string &s, const char *name)
+    template<> bool to<bool>(const std::string &s)
     {
-        std::istringstream is(s);
-        T v;
-        is >> v;
-        if (is.fail() || !is.eof())
-        {
-            throw std::invalid_argument(str::asprintf(_("Cannot convert string to %s."), name));
-        }
-        return v;
-    }
-
-    template<> bool to<bool>(const std::string &s) { return _to<bool>(s, "bool"); }
-    template<> signed char to<signed char>(const std::string &s) { return _to<signed char>(s, "signed char"); }
-    template<> unsigned char to<unsigned char>(const std::string &s) { return _to<unsigned char>(s, "unsigned char"); }
-    template<> short to<short>(const std::string &s) { return _to<short>(s, "short"); }
-    template<> unsigned short to<unsigned short>(const std::string &s) { return _to<unsigned short>(s, "unsigned short"); }
-    template<> int to<int>(const std::string &s) { return _to<int>(s, "int"); }
-    template<> unsigned int to<unsigned int>(const std::string &s) { return _to<unsigned int>(s, "unsigned int"); }
-    template<> long to<long>(const std::string &s) { return _to<long>(s, "long"); }
-    template<> unsigned long to<unsigned long>(const std::string &s) { return _to<unsigned long>(s, "unsigned long"); }
-    template<> long long to<long long>(const std::string &s) { return _to<long long>(s, "long long"); }
-    template<> unsigned long long to<unsigned long long>(const std::string &s) { return _to<unsigned long long>(s, "unsigned long long"); }
-    template<> float to<float>(const std::string &s) { return _to<float>(s, "float"); }
-    template<> double to<double>(const std::string &s) { return _to<double>(s, "double"); }
-    template<> long double to<long double>(const std::string &s) { return _to<long double>(s, "long double"); }
+        long r = str_to<long>(s, "bool");
+        return r ? true : false;
+    }
+    template<> signed char to<signed char>(const std::string &s)
+    {
+        return str_to<signed char>(s, "signed char");
+    }
+    template<> unsigned char to<unsigned char>(const std::string &s)
+    {
+        return str_to<unsigned char>(s, "unsigned char");
+    }
+    template<> short to<short>(const std::string &s)
+    {
+        return str_to<short>(s, "short");
+    }
+    template<> unsigned short to<unsigned short>(const std::string &s)
+    {
+        return str_to<unsigned short>(s, "unsigned short");
+    }
+    template<> int to<int>(const std::string &s)
+    {
+        return str_to<int>(s, "int");
+    }
+    template<> unsigned int to<unsigned int>(const std::string &s)
+    {
+        return str_to<unsigned int>(s, "unsigned int");
+    }
+    template<> long to<long>(const std::string &s)
+    {
+        return str_to<long>(s, "long");
+    }
+    template<> unsigned long to<unsigned long>(const std::string &s)
+    {
+        return str_to<unsigned long>(s, "unsigned long");
+    }
+    template<> long long to<long long>(const std::string &s)
+    {
+        return str_to<long long>(s, "long long");
+    }
+    template<> unsigned long long to<unsigned long long>(const std::string &s)
+    {
+        return str_to<unsigned long long>(s, "unsigned long long");
+    }
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+    template<> __int128 to<__int128>(const std::string &s)
+    {
+        return str_to<__int128>(s, "int128");
+    }
+#endif
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+    template<> unsigned __int128 to<unsigned __int128>(const std::string &s)
+    {
+        return str_to<unsigned __int128>(s, "unsigned int128");
+    }
+#endif
+    template<> float to<float>(const std::string &s)
+    {
+        return str_to<float>(s, "float");
+    }
+    template<> double to<double>(const std::string &s)
+    {
+        return str_to<double>(s, "double");
+    }
+    template<> long double to<long double>(const std::string &s)
+    {
+        return str_to<long double>(s, "long double");
+    }
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+    template<> __float128 to<__float128>(const std::string &s)
+    {
+        return str_to<__float128>(s, "float128");
+    }
+#endif
 
     template<typename T>
     static inline bool _to(const std::string& s, T* x)
@@ -314,9 +716,18 @@ namespace str
     template<> bool to(const std::string& s, unsigned long* x) { return _to(s, x); }
     template<> bool to(const std::string& s, long long* x) { return _to(s, x); }
     template<> bool to(const std::string& s, unsigned long long* x) { return _to(s, x); }
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+    template<> bool to(const std::string& s, __int128* x) { return _to(s, x); }
+#endif
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+    template<> bool to(const std::string& s, unsigned __int128* x) { return _to(s, x); }
+#endif
     template<> bool to(const std::string& s, float* x) { return _to(s, x); }
     template<> bool to(const std::string& s, double* x) { return _to(s, x); }
     template<> bool to(const std::string& s, long double* x) { return _to(s, x); }
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+    template<> bool to(const std::string& s, __float128* x) { return _to(s, x); }
+#endif
 
     /* Create std::strings printf-like */
 
index 5aab26f..ff7a5ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2010, 2011, 2012, 2013
+ * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014
  * Martin Lambers <marlam@marlam.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,8 @@
 #ifndef STR_H
 #define STR_H
 
+#include "config.h"
+
 #include <string>
 #include <vector>
 #include <cstdarg>
@@ -59,9 +61,18 @@ namespace str
     std::string from(unsigned long x);
     std::string from(long long x);
     std::string from(unsigned long long x);
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+    std::string from(__int128 x);
+#endif
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+    std::string from(unsigned __int128 x);
+#endif
     std::string from(float x);
     std::string from(double x);
     std::string from(long double x);
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+    std::string from(__float128 x);
+#endif
 
     /* Convert a string to one of the basic data types */
     template<typename T> T to(const std::string &s);
@@ -76,9 +87,18 @@ namespace str
     template<> unsigned long to<unsigned long>(const std::string &s);
     template<> long long to<long long>(const std::string &s);
     template<> unsigned long long to<unsigned long long>(const std::string &s);
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+    template<> __int128 to<__int128>(const std::string &s);
+#endif
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+    template<> unsigned __int128 to<unsigned __int128>(const std::string &s);
+#endif
     template<> float to<float>(const std::string &s);
     template<> double to<double>(const std::string &s);
     template<> long double to<long double>(const std::string &s);
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+    template<> __float128 to<__float128>(const std::string &s);
+#endif
     template<typename T> bool to(const std::string& s, T* x);
     template<> bool to(const std::string& s, bool* x);
     template<> bool to(const std::string& s, signed char* x);
@@ -91,9 +111,18 @@ namespace str
     template<> bool to(const std::string& s, unsigned long* x);
     template<> bool to(const std::string& s, long long* x);
     template<> bool to(const std::string& s, unsigned long long* x);
+#if !defined(HAVE_INT128_T) && defined(HAVE___INT128)
+    template<> bool to(const std::string& s, __int128* x);
+#endif
+#if !defined(HAVE_UINT128_T) && defined(HAVE_UNSIGNED___INT128)
+    template<> bool to(const std::string& s, unsigned __int128* x);
+#endif
     template<> bool to(const std::string& s, float* x);
     template<> bool to(const std::string& s, double* x);
     template<> bool to(const std::string& s, long double* x);
+#if !defined(LONG_DOUBLE_IS_IEEE_754_QUAD) && defined(HAVE___FLOAT128)
+    template<> bool to(const std::string& s, __float128* x);
+#endif
 
     /* Create std::strings printf-like */
     std::string vasprintf(const char *format, va_list args) STR_AFP(1, 0);