C++ string Formatter Again Part-4

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite
1












Previously asked here.



The code is now available on GitHub.



Since the previous review I have added unit tests.



Since it is big it will come in a couple of parts.



Part 1 | Part 2 | Part 3 | Part 4



Part 4



Printing strings and integers did not work the same way on streams as they did in printf(). So I had to write some special handling code to deal with these types to get the unit tests to all work.



printToStream.h



#ifndef THORSANVIL_IOUTIL_PRINT_TO_STREAM_H
#define THORSANVIL_IOUTIL_PRINT_TO_STREAM_H

#include "FormatInfo.h"
#include "printIntToStream.h"
#include "printStringToStream.h"

#include <ostream>

namespace ThorsAnvil::IOUtil


template<typename T>
inline void printToStreamDefault(std::ostream& s, T const& arg, FormatInfo const&)

s << arg;


/* Template method for everything apart from integers */
template<typename T>
inline
typename std::enable_if<!std::is_integral<T>::value>::type
printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

// Just use the standard stream printing methods.
// Below we special case Int and string handling (floats work as expected).
printToStreamDefault(s, arg, info);


/*
* As a char is an integer we need to detect this case
* and call the standard printing functions for Type::Char
*
* But we can also print an integer using a char in which case we need to convert the char to an integer
* before we can print it. Below are helper functions to convert Char to Int when printing a char as an
* an integer.
*/
template<typename T>
struct CharIntConverter

using Integer = T;
;
template<>
struct CharIntConverter<char>

using Integer = int;
;
template<>
struct CharIntConverter<unsigned char>

using Integer = unsigned int;
;


template<typename T>
inline
typename std::enable_if<std::is_integral<T>::value>::type
printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

if (info.type == Type::Char)

printToStreamDefault(s, static_cast<char>(arg), info);

else

printIntToStream(s, static_cast<typename CharIntConverter<T>::Integer>(arg), info);



// C-String
inline void printToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

printStringToStream(s, arg, info);





#endif


PrintStringToStream.h



#ifndef THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H
#define THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H

#include "FormatInfo.h"
#include "printToStream.h"

namespace ThorsAnvil::IOUtil


inline void printStringToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

if (info.precision == -1)

s << arg;

else

s.width(0);
std::size_t padding = (info.precision >= info.width) ? 0 : (info.width - info.precision);
if (!info.leftJustify)

for (std::size_t loop = 0; loop < padding; ++loop)

s.put(' ');


for (std::size_t loop = 0; arg[loop] != '' && loop < info.precision; ++loop)

s.put(arg[loop]);

if (info.leftJustify)

for (std::size_t loop = 0; loop < padding; ++loop)

s.put(' ');








PrintIntToStream



#ifndef THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H
#define THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H

#include "FormatInfo.h"
#include "printToStream.h"

#include <ostream>
#include <cmath>

namespace ThorsAnvil::IOUtil


inline long long absm(long long arg) return std::abs(arg);
inline long absm(long arg) return std::abs(arg);
inline int absm(int arg) return std::abs(arg);
inline unsigned long long absm(unsigned long long arg) return arg;
inline unsigned long absm(unsigned long arg) return arg;
inline unsigned int absm(unsigned int arg) return arg;

template<typename T>
inline void printIntToStream(std::ostream& s, T arg, FormatInfo const& info)

static long double const logFor16 = std::log10(16.0L);
static long double const logFor10 = std::log10(10.0L);
static long double const logFor08 = std::log10(8.0L);

double const& logBase = s.flags() & std::ios_base::oct ? logFor08 : s.flags() & std::ios_base::hex ? logFor16 : logFor10;

if (info.width == 0 && info.precision == -1)

s << arg;

else
arg != 0)

s << absm(arg);

// Add spaces after number to make it fit in width.
if (info.leftJustify)

for (std::size_t loop = 0; loop < padding; ++loop)

s.put(' ');







#endif






share|improve this question



























    up vote
    3
    down vote

    favorite
    1












    Previously asked here.



    The code is now available on GitHub.



    Since the previous review I have added unit tests.



    Since it is big it will come in a couple of parts.



    Part 1 | Part 2 | Part 3 | Part 4



    Part 4



    Printing strings and integers did not work the same way on streams as they did in printf(). So I had to write some special handling code to deal with these types to get the unit tests to all work.



    printToStream.h



    #ifndef THORSANVIL_IOUTIL_PRINT_TO_STREAM_H
    #define THORSANVIL_IOUTIL_PRINT_TO_STREAM_H

    #include "FormatInfo.h"
    #include "printIntToStream.h"
    #include "printStringToStream.h"

    #include <ostream>

    namespace ThorsAnvil::IOUtil


    template<typename T>
    inline void printToStreamDefault(std::ostream& s, T const& arg, FormatInfo const&)

    s << arg;


    /* Template method for everything apart from integers */
    template<typename T>
    inline
    typename std::enable_if<!std::is_integral<T>::value>::type
    printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

    // Just use the standard stream printing methods.
    // Below we special case Int and string handling (floats work as expected).
    printToStreamDefault(s, arg, info);


    /*
    * As a char is an integer we need to detect this case
    * and call the standard printing functions for Type::Char
    *
    * But we can also print an integer using a char in which case we need to convert the char to an integer
    * before we can print it. Below are helper functions to convert Char to Int when printing a char as an
    * an integer.
    */
    template<typename T>
    struct CharIntConverter

    using Integer = T;
    ;
    template<>
    struct CharIntConverter<char>

    using Integer = int;
    ;
    template<>
    struct CharIntConverter<unsigned char>

    using Integer = unsigned int;
    ;


    template<typename T>
    inline
    typename std::enable_if<std::is_integral<T>::value>::type
    printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

    if (info.type == Type::Char)

    printToStreamDefault(s, static_cast<char>(arg), info);

    else

    printIntToStream(s, static_cast<typename CharIntConverter<T>::Integer>(arg), info);



    // C-String
    inline void printToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

    printStringToStream(s, arg, info);





    #endif


    PrintStringToStream.h



    #ifndef THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H
    #define THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H

    #include "FormatInfo.h"
    #include "printToStream.h"

    namespace ThorsAnvil::IOUtil


    inline void printStringToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

    if (info.precision == -1)

    s << arg;

    else

    s.width(0);
    std::size_t padding = (info.precision >= info.width) ? 0 : (info.width - info.precision);
    if (!info.leftJustify)

    for (std::size_t loop = 0; loop < padding; ++loop)

    s.put(' ');


    for (std::size_t loop = 0; arg[loop] != '' && loop < info.precision; ++loop)

    s.put(arg[loop]);

    if (info.leftJustify)

    for (std::size_t loop = 0; loop < padding; ++loop)

    s.put(' ');








    PrintIntToStream



    #ifndef THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H
    #define THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H

    #include "FormatInfo.h"
    #include "printToStream.h"

    #include <ostream>
    #include <cmath>

    namespace ThorsAnvil::IOUtil


    inline long long absm(long long arg) return std::abs(arg);
    inline long absm(long arg) return std::abs(arg);
    inline int absm(int arg) return std::abs(arg);
    inline unsigned long long absm(unsigned long long arg) return arg;
    inline unsigned long absm(unsigned long arg) return arg;
    inline unsigned int absm(unsigned int arg) return arg;

    template<typename T>
    inline void printIntToStream(std::ostream& s, T arg, FormatInfo const& info)

    static long double const logFor16 = std::log10(16.0L);
    static long double const logFor10 = std::log10(10.0L);
    static long double const logFor08 = std::log10(8.0L);

    double const& logBase = s.flags() & std::ios_base::oct ? logFor08 : s.flags() & std::ios_base::hex ? logFor16 : logFor10;

    if (info.width == 0 && info.precision == -1)

    s << arg;

    else
    arg != 0)

    s << absm(arg);

    // Add spaces after number to make it fit in width.
    if (info.leftJustify)

    for (std::size_t loop = 0; loop < padding; ++loop)

    s.put(' ');







    #endif






    share|improve this question























      up vote
      3
      down vote

      favorite
      1









      up vote
      3
      down vote

      favorite
      1






      1





      Previously asked here.



      The code is now available on GitHub.



      Since the previous review I have added unit tests.



      Since it is big it will come in a couple of parts.



      Part 1 | Part 2 | Part 3 | Part 4



      Part 4



      Printing strings and integers did not work the same way on streams as they did in printf(). So I had to write some special handling code to deal with these types to get the unit tests to all work.



      printToStream.h



      #ifndef THORSANVIL_IOUTIL_PRINT_TO_STREAM_H
      #define THORSANVIL_IOUTIL_PRINT_TO_STREAM_H

      #include "FormatInfo.h"
      #include "printIntToStream.h"
      #include "printStringToStream.h"

      #include <ostream>

      namespace ThorsAnvil::IOUtil


      template<typename T>
      inline void printToStreamDefault(std::ostream& s, T const& arg, FormatInfo const&)

      s << arg;


      /* Template method for everything apart from integers */
      template<typename T>
      inline
      typename std::enable_if<!std::is_integral<T>::value>::type
      printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

      // Just use the standard stream printing methods.
      // Below we special case Int and string handling (floats work as expected).
      printToStreamDefault(s, arg, info);


      /*
      * As a char is an integer we need to detect this case
      * and call the standard printing functions for Type::Char
      *
      * But we can also print an integer using a char in which case we need to convert the char to an integer
      * before we can print it. Below are helper functions to convert Char to Int when printing a char as an
      * an integer.
      */
      template<typename T>
      struct CharIntConverter

      using Integer = T;
      ;
      template<>
      struct CharIntConverter<char>

      using Integer = int;
      ;
      template<>
      struct CharIntConverter<unsigned char>

      using Integer = unsigned int;
      ;


      template<typename T>
      inline
      typename std::enable_if<std::is_integral<T>::value>::type
      printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

      if (info.type == Type::Char)

      printToStreamDefault(s, static_cast<char>(arg), info);

      else

      printIntToStream(s, static_cast<typename CharIntConverter<T>::Integer>(arg), info);



      // C-String
      inline void printToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

      printStringToStream(s, arg, info);





      #endif


      PrintStringToStream.h



      #ifndef THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H
      #define THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H

      #include "FormatInfo.h"
      #include "printToStream.h"

      namespace ThorsAnvil::IOUtil


      inline void printStringToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

      if (info.precision == -1)

      s << arg;

      else

      s.width(0);
      std::size_t padding = (info.precision >= info.width) ? 0 : (info.width - info.precision);
      if (!info.leftJustify)

      for (std::size_t loop = 0; loop < padding; ++loop)

      s.put(' ');


      for (std::size_t loop = 0; arg[loop] != '' && loop < info.precision; ++loop)

      s.put(arg[loop]);

      if (info.leftJustify)

      for (std::size_t loop = 0; loop < padding; ++loop)

      s.put(' ');








      PrintIntToStream



      #ifndef THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H
      #define THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H

      #include "FormatInfo.h"
      #include "printToStream.h"

      #include <ostream>
      #include <cmath>

      namespace ThorsAnvil::IOUtil


      inline long long absm(long long arg) return std::abs(arg);
      inline long absm(long arg) return std::abs(arg);
      inline int absm(int arg) return std::abs(arg);
      inline unsigned long long absm(unsigned long long arg) return arg;
      inline unsigned long absm(unsigned long arg) return arg;
      inline unsigned int absm(unsigned int arg) return arg;

      template<typename T>
      inline void printIntToStream(std::ostream& s, T arg, FormatInfo const& info)

      static long double const logFor16 = std::log10(16.0L);
      static long double const logFor10 = std::log10(10.0L);
      static long double const logFor08 = std::log10(8.0L);

      double const& logBase = s.flags() & std::ios_base::oct ? logFor08 : s.flags() & std::ios_base::hex ? logFor16 : logFor10;

      if (info.width == 0 && info.precision == -1)

      s << arg;

      else
      arg != 0)

      s << absm(arg);

      // Add spaces after number to make it fit in width.
      if (info.leftJustify)

      for (std::size_t loop = 0; loop < padding; ++loop)

      s.put(' ');







      #endif






      share|improve this question













      Previously asked here.



      The code is now available on GitHub.



      Since the previous review I have added unit tests.



      Since it is big it will come in a couple of parts.



      Part 1 | Part 2 | Part 3 | Part 4



      Part 4



      Printing strings and integers did not work the same way on streams as they did in printf(). So I had to write some special handling code to deal with these types to get the unit tests to all work.



      printToStream.h



      #ifndef THORSANVIL_IOUTIL_PRINT_TO_STREAM_H
      #define THORSANVIL_IOUTIL_PRINT_TO_STREAM_H

      #include "FormatInfo.h"
      #include "printIntToStream.h"
      #include "printStringToStream.h"

      #include <ostream>

      namespace ThorsAnvil::IOUtil


      template<typename T>
      inline void printToStreamDefault(std::ostream& s, T const& arg, FormatInfo const&)

      s << arg;


      /* Template method for everything apart from integers */
      template<typename T>
      inline
      typename std::enable_if<!std::is_integral<T>::value>::type
      printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

      // Just use the standard stream printing methods.
      // Below we special case Int and string handling (floats work as expected).
      printToStreamDefault(s, arg, info);


      /*
      * As a char is an integer we need to detect this case
      * and call the standard printing functions for Type::Char
      *
      * But we can also print an integer using a char in which case we need to convert the char to an integer
      * before we can print it. Below are helper functions to convert Char to Int when printing a char as an
      * an integer.
      */
      template<typename T>
      struct CharIntConverter

      using Integer = T;
      ;
      template<>
      struct CharIntConverter<char>

      using Integer = int;
      ;
      template<>
      struct CharIntConverter<unsigned char>

      using Integer = unsigned int;
      ;


      template<typename T>
      inline
      typename std::enable_if<std::is_integral<T>::value>::type
      printToStream(std::ostream& s, T const& arg, FormatInfo const& info)

      if (info.type == Type::Char)

      printToStreamDefault(s, static_cast<char>(arg), info);

      else

      printIntToStream(s, static_cast<typename CharIntConverter<T>::Integer>(arg), info);



      // C-String
      inline void printToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

      printStringToStream(s, arg, info);





      #endif


      PrintStringToStream.h



      #ifndef THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H
      #define THORSANVIL_IOUTIL_PRINT_STRING_TO_STREAM_H

      #include "FormatInfo.h"
      #include "printToStream.h"

      namespace ThorsAnvil::IOUtil


      inline void printStringToStream(std::ostream& s, char const* const& arg, FormatInfo const& info)

      if (info.precision == -1)

      s << arg;

      else

      s.width(0);
      std::size_t padding = (info.precision >= info.width) ? 0 : (info.width - info.precision);
      if (!info.leftJustify)

      for (std::size_t loop = 0; loop < padding; ++loop)

      s.put(' ');


      for (std::size_t loop = 0; arg[loop] != '' && loop < info.precision; ++loop)

      s.put(arg[loop]);

      if (info.leftJustify)

      for (std::size_t loop = 0; loop < padding; ++loop)

      s.put(' ');








      PrintIntToStream



      #ifndef THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H
      #define THORSANVIL_IOUTIL_PRINT_INT_TO_STREAM_H

      #include "FormatInfo.h"
      #include "printToStream.h"

      #include <ostream>
      #include <cmath>

      namespace ThorsAnvil::IOUtil


      inline long long absm(long long arg) return std::abs(arg);
      inline long absm(long arg) return std::abs(arg);
      inline int absm(int arg) return std::abs(arg);
      inline unsigned long long absm(unsigned long long arg) return arg;
      inline unsigned long absm(unsigned long arg) return arg;
      inline unsigned int absm(unsigned int arg) return arg;

      template<typename T>
      inline void printIntToStream(std::ostream& s, T arg, FormatInfo const& info)

      static long double const logFor16 = std::log10(16.0L);
      static long double const logFor10 = std::log10(10.0L);
      static long double const logFor08 = std::log10(8.0L);

      double const& logBase = s.flags() & std::ios_base::oct ? logFor08 : s.flags() & std::ios_base::hex ? logFor16 : logFor10;

      if (info.width == 0 && info.precision == -1)

      s << arg;

      else
      arg != 0)

      s << absm(arg);

      // Add spaces after number to make it fit in width.
      if (info.leftJustify)

      for (std::size_t loop = 0; loop < padding; ++loop)

      s.put(' ');







      #endif








      share|improve this question












      share|improve this question




      share|improve this question








      edited Mar 4 at 19:52









      Phrancis

      14.6k645137




      14.6k645137









      asked Mar 4 at 19:22









      Martin York

      70.9k481244




      70.9k481244

























          active

          oldest

          votes











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188812%2fc-string-formatter-again-part-4%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes










           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188812%2fc-string-formatter-again-part-4%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Python Lists

          Aion

          JavaScript Array Iteration Methods