Synesis Software STLSoft - ... Robust, Lightweight, Cross-platform, Template Software ...

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 SourceForge.net Logo