- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages
- Examples

# fastformat/inserters/real.hpp

Go to the documentation of this file.

    00001 /* /////////////////////////////////////////////////////////////////////////
    00002  * File:        fastformat/inserters/real.hpp
    00003  *
    00004  * Purpose:     Inserter functions for floating-point types
    00005  *
    00006  * Created:     1st March 2009
    00007  * Updated:     7th March 2010
    00008  *
    00009  * Home:        http://www.fastformat.org/
    00010  *
    00011  * Copyright (c) 2009-2010, Matthew Wilson and Synesis Software
    00012  * All rights reserved.
    00013  *
    00014  * Redistribution and use in source and binary forms, with or without
    00015  * modification, are permitted provided that the following conditions are
    00016  * met:
    00017  *
    00018  * - Redistributions of source code must retain the above copyright notice,
    00019  *   this list of conditions and the following disclaimer.
    00020  * - Redistributions in binary form must reproduce the above copyright
    00021  *   notice, this list of conditions and the following disclaimer in the
    00022  *   documentation and/or other materials provided with the distribution.
    00023  * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
    00024  *   names of any contributors may be used to endorse or promote products
    00025  *   derived from this software without specific prior written permission.
    00026  *
    00027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
    00028  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    00029  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    00030  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    00031  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    00032  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    00033  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    00034  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
    00035  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    00036  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00037  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00038  *
    00039  * ////////////////////////////////////////////////////////////////////// */
    00040
    00041
    00047 #ifndef FASTFORMAT_INCL_FASTFORMAT_INSERTERS_HPP_REAL
    00048 #define FASTFORMAT_INCL_FASTFORMAT_INSERTERS_HPP_REAL
    00049
    00050 /* /////////////////////////////////////////////////////////////////////////
    00051  * Version information
    00052  */
    00053
    00054 #ifndef FASTFORMAT_DOCUMENTATION_SKIP_SECTION
    00055 # define FASTFORMAT_VER_FASTFORMAT_INSERTERS_HPP_REAL_MAJOR     1
    00056 # define FASTFORMAT_VER_FASTFORMAT_INSERTERS_HPP_REAL_MINOR     1
    00057 # define FASTFORMAT_VER_FASTFORMAT_INSERTERS_HPP_REAL_REVISION  4
    00058 # define FASTFORMAT_VER_FASTFORMAT_INSERTERS_HPP_REAL_EDIT      5
    00059 #endif /* !FASTFORMAT_DOCUMENTATION_SKIP_SECTION */
    00060
    00061 /* /////////////////////////////////////////////////////////////////////////
    00062  * Includes
    00063  */
    00064
    00065 #include <fastformat/fastformat.h>
    00066 #include <fastformat/quality/contract.h>
    00067 #include <fastformat/util/string/snprintf.h>
    00068
    00069 #include <stlsoft/conversion/integer_to_string.hpp>
    00070 #include <stlsoft/string/shim_string.hpp>
    00071 #include <stlsoft/util/limit_traits.h>
    00072
    00073 #include <stdlib.h> /* for abs() */
    00074
    00075 /* /////////////////////////////////////////////////////////////////////////
    00076  * Namespace
    00077  */
    00078
    00079 #if !defined(FASTFORMAT_NO_NAMESPACE)
    00080 namespace fastformat
    00081 {
    00082 namespace inserters
    00083 {
    00084 #endif /* !FASTFORMAT_NO_NAMESPACE */
    00085
    00086 /* /////////////////////////////////////////////////////////////////////////
    00087  * Implementation
    00088  */
    00089
    00090 #ifndef FASTFORMAT_DOCUMENTATION_SKIP_SECTION
    00091 namespace real_impl
    00092 {
    00093
    00094 inline int default_width_sentinel_()
    00095 {
    00096     return stlsoft::limit_traits<int>::minimum();
    00097 }
    00098
    00099 inline int default_precision_sentinel_()
    00100 {
    00101     return -1;
    00102 }
    00103
    00104 inline stlsoft::basic_shim_string<ff_char_t, 64> real_helper_2(
    00105     double const&       value
    00106 ,   ff_char_t const*    fmt
    00107 )
    00108 {
    00109     typedef stlsoft::basic_shim_string<ff_char_t, 64>   result_t;
    00110
    00111     enum { maxRepeats = 4 };
    00112
    00113 #if _STLSOFT_VER < 0x010a0000 && \
    00114     defined(_STLSOFT_1_10_VER) && \
    00115     _STLSOFT_1_10_VER < 0x010a0109
    00116
    00117     /* Using STLSoft 1.10.1 alpha 1 - alpha 8 */
    00118
    00119 # error This class cannot work with STLSoft 1.10 versions between 1.10.1 alpha 1 and 1.10.1 alpha 9. Please download the latest version of STLSoft 1.10 alpha
    00120
    00121 #elif _STLSOFT_VER >= 0x010a0000 || \
    00122       defined(_STLSOFT_1_10_VER)
    00123
    00124     /* Using STLSoft 1.10+ version of basic_shim_string */
    00125
    00126     // We use the public interface of the shim string.
    00127
    00128     result_t result(64);
    00129
    00130 # ifndef STLSOFT_CF_THROW_BAD_ALLOC
    00131     if(!result.empty())
    00132 # endif /* !STLSOFT_CF_THROW_BAD_ALLOC */
    00133     {
    00134         // Unlike integral types, the string representation of floating
    00135         // point values do not have a known maximum length, so we must be
    00136         // flexible.
    00137         //
    00138         // However, some implementations of snprintf() return -1 instead of
    00139         // the length that would be required, so we cannot assume -1
    00140         // indicates error. To handle this, we double the size of the buffer
    00141         // up to four times, at which point we admit defeat.
    00142
    00143         { for(int i = 0;; )
    00144         {
    00145             int n = fastformat_util_snprintf(result.data(), result.size() - 1, fmt, value);
    00146
    00147             if(n > int(result.size()))
    00148             {
    00149                 // An implementation that does it correctly, so just resize
    00150                 // to the desired size and go again
    00151
    00152                 // This'll only return false when exception-handling is
    00153                 // suppressed, but the code is correct without pre-processor
    00154                 // logic in either case, so leave as is
    00155                 if(!result.resize(n))
    00156                 {
    00157                     result.truncate(0);
    00158                     break;
    00159                 }
    00160             }
    00161             else if(n < 0)
    00162             {
    00163                 if(maxRepeats == ++i)
    00164                 {
    00165                     result.truncate(0);
    00166                     break;
    00167                 }
    00168                 else
    00169                 {
    00170                     // This'll only return false when exception-handling is
    00171                     // suppressed, but the code is correct without pre-processor
    00172                     // logic in either case, so leave as is
    00173                     if(!result.resize(1u + result.size() * 2))
    00174                     {
    00175                         result.truncate(0);
    00176                         break;
    00177                     }
    00178                 }
    00179             }
    00180             else
    00181             {
    00182                 // It's worked!
    00183                 //
    00184                 // We must nul-terminate, and resize, so that the shim string's
    00185                 // length is evaluated correctly
    00186                 result.truncate(size_t(n));
    00187
    00188                 break;
    00189             }
    00190         }}
    00191     }
    00192
    00193     return result;
    00194
    00195 #else /* ? STLSoft 1.x */
    00196
    00197     /* Using STLSoft 1.9+ version of basic_shim_string */
    00198
    00199     // We have to use the internal buffer, which means that we are
    00200     // relying on the internal workings of shim string, which is ugly.
    00201     // With 1.10, we don't need to do this.
    00202
    00203     result_t                result(64);
    00204     result_t::buffer_type&  buffer = result.get_buffer();
    00205
    00206 # ifndef STLSOFT_CF_THROW_BAD_ALLOC
    00207     if(!buffer.empty())
    00208 # endif /* !STLSOFT_CF_THROW_BAD_ALLOC */
    00209     {
    00210         // Unlike integral types, the string representation of floating
    00211         // point values do not have a known maximum length, so we must be
    00212         // flexible.
    00213         //
    00214         // However, some implementations of snprintf() return -1 instead of
    00215         // the length that would be required, so we cannot assume -1
    00216         // indicates error. To handle this, we double the size of the buffer
    00217         // up to four times, at which point we admit defeat.
    00218
    00219         { for(int i = 0;; )
    00220         {
    00221             int n = fastformat_util_snprintf(&buffer[0], buffer.size() - 1, fmt, value);
    00222
    00223             if(n > int(buffer.size() - 1))
    00224             {
    00225                 // An implementation that does it correctly, so just resize
    00226                 // to the desired size and go again
    00227
    00228                 // This'll only return false when exception-handling is
    00229                 // suppressed, but the code is correct without pre-processor
    00230                 // logic in either case, so leave as is
    00231                 if(!buffer.resize(size_t(n) + 1u))
    00232                 {
    00233                     buffer.resize(1u);
    00234                     break;
    00235                 }
    00236             }
    00237             else if(n < 0)
    00238             {
    00239                 if(maxRepeats == ++i)
    00240                 {
    00241                     break;
    00242                 }
    00243                 else
    00244                 {
    00245                     // This'll only return false when exception-handling is
    00246                     // suppressed, but the code is correct without pre-processor
    00247                     // logic in either case, so leave as is
    00248                     if(!buffer.resize(1u + buffer.size() * 2))
    00249                     {
    00250                         buffer.resize(1u);
    00251                         break;
    00252                     }
    00253                 }
    00254             }
    00255             else
    00256             {
    00257                 // It's worked!
    00258                 //
    00259                 // We must nul-terminate, and resize, so that the shim string's
    00260                 // length is evaluated correctly
    00261                 buffer[size_t(n)] = '\0';
    00262
    00263                 buffer.resize(size_t(n) + 1u);
    00264
    00265                 break;
    00266             }
    00267         }}
    00268     }
    00269
    00270     return result;
    00271 #endif /* STLSoft 1.x */
    00272 }
    00273
    00274 inline stlsoft::basic_shim_string<ff_char_t, 64> real_helper_4(
    00275     double const&       value
    00276 ,   int                 minimumWidth
    00277 ,   int                 precision
    00278 ,   ff_char_t const*    specifier
    00279 )
    00280 {
    00281     ff_char_t   type    =   'f';
    00282     ff_char_t   fmt_[]  =   FASTFORMAT_LITERAL_STRING("%-01234567890123456789.01234567890123456789f");
    00283     ff_char_t*  fmt     =   fmt_;
    00284
    00285     if(NULL != specifier)
    00286     {
    00287         type = *specifier;
    00288     }
    00289
    00290     if( default_width_sentinel_() == minimumWidth &&
    00291         precision < 0)
    00292     {
    00293         fmt[1] = type;
    00294         fmt[2] = '\0';
    00295     }
    00296     else
    00297     {
    00298         if(default_width_sentinel_() == minimumWidth)
    00299         {
    00300             minimumWidth = 0;
    00301         }
    00302         if(precision < 0)
    00303         {
    00304             precision = 0;
    00305         }
    00306
    00307         // Performance tests show a substantial advantage in using
    00308         // integer_to_string() over fastformat_util_snprintf()
    00309
    00310 #if 0
    00311
    00312         int n = fastformat_util_snprintf(&fmt[0], STLSOFT_NUM_ELEMENTS(fmt_) - 1, FASTFORMAT_LITERAL_STRING("%%%d.%d%c"), minimumWidth, precision, type);
    00313
    00314         FASTFORMAT_CONTRACT_ENFORCE_ASSUMPTION((n > 0) && (n < int(STLSOFT_NUM_ELEMENTS(fmt_)) - 1));
    00315
    00316         fmt[n] = '\0';
    00317
    00318 #else /* ? 0 */
    00319
    00320         const size_t    fmtDim  =   STLSOFT_NUM_ELEMENTS(fmt_) - 1;
    00321         ff_char_t*      end     =   &fmt[fmtDim];
    00322         size_t          n1;
    00323         size_t          n2;
    00324
    00325         stlsoft::integer_to_string(end - 21, 21, precision, n1);
    00326         *--end = type;
    00327         end -= n1;
    00328         stlsoft::integer_to_string(end - 21, 21, minimumWidth, n2);
    00329         *--end = '.';
    00330         end -= n2;
    00331         *--end = '%';
    00332         fmt = end;
    00333
    00334 #endif /* 0 */
    00335     }
    00336
    00337     return real_helper_2(value, fmt);
    00338 }
    00339
    00340 } /* namespace real_impl */
    00341 #endif /* !FASTFORMAT_DOCUMENTATION_SKIP_SECTION */
    00342
    00343 /* /////////////////////////////////////////////////////////////////////////
    00344  * Inserter functions
    00345  */
    00346
    00353 inline stlsoft::basic_shim_string<ff_char_t, 64> real(
    00354     double const&   value
    00355 )
    00356 {
    00357     return real_impl::real_helper_4(value, real_impl::default_width_sentinel_(), real_impl::default_precision_sentinel_(), NULL);
    00358 }
    00359
    00372 inline stlsoft::basic_shim_string<ff_char_t, 64> real(
    00373     double const&   value
    00374 ,   int             minimumWidth
    00375 ,   int             decimalPlaces
    00376 )
    00377 {
    00378     FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_APPL_LAYER(abs(minimumWidth) < 512, "maximum value for width exceeded");
    00379     FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_APPL_LAYER(abs(minimumWidth) < 1 || decimalPlaces <= abs(minimumWidth), "decimal places must not exceed width");
    00380
    00381     return real_impl::real_helper_4(value, minimumWidth, decimalPlaces, NULL);
    00382 }
    00383
    00398 inline stlsoft::basic_shim_string<ff_char_t, 64> real(
    00399     double const&   value
    00400 ,   int             minimumWidth
    00401 ,   int             decimalPlaces
    00402 ,   ff_char_t       type
    00403 )
    00404 {
    00405     FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_APPL_LAYER(abs(minimumWidth) < 512, "maximum value for width exceeded");
    00406     FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_APPL_LAYER(abs(minimumWidth) < 1 || decimalPlaces <= abs(minimumWidth), "decimal places must not exceed width");
    00407     FASTFORMAT_CONTRACT_ENFORCE_PRECONDITION_PARAMS_APPL_LAYER(('f' == type) || ('e' == type) || ('E' == type) || ('g' == type) || ('G' == type), "type parameter must be one of 'f', 'e', 'E', 'g' or 'G'");
    00408
    00409     return real_impl::real_helper_4(value, minimumWidth, decimalPlaces, &type);
    00410 }
    00411
    00412 /* /////////////////////////////////////////////////////////////////////////
    00413  * Namespace
    00414  */
    00415
    00416 #if !defined(FASTFORMAT_NO_NAMESPACE)
    00417 } // namespace inserters
    00418 using ::fastformat::inserters::real;
    00419 } // namespace fastformat
    00420 #endif /* !FASTFORMAT_NO_NAMESPACE */
    00421
    00422 /* /////////////////////////////////////////////////////////////////////////
    00423  * Inclusion
    00424  */
    00425
    00426 #ifdef STLSOFT_PPF_pragma_once_SUPPORT
    00427 # pragma once
    00428 #endif /* STLSOFT_PPF_pragma_once_SUPPORT */
    00429
    00430 /* ////////////////////////////////////////////////////////////////////// */
    00431
    00432 #endif /* !FASTFORMAT_INCL_FASTFORMAT_INSERTERS_HPP_REAL */
    00433
    00434 /* ///////////////////////////// end of file //////////////////////////// */

FastFormat Library documentation © Matthew Wilson, 2006-2009 |