Giter VIP home page Giter VIP logo

strf's Introduction

Strf

Build Status codecov

A C++ text formatting and transcoding library.

Header-only by default, but can be used as a static library as well ( see details ).

Documentation

Requirements

From version 0.16 onwards, C++11 is no longer supported. The compiler must support C++14 or above.

Strf has been tested in the following compilers:

  • Clang 6.0
  • GCC 6.5.0
  • Visual Studio 2019 16
  • NVCC 11.8

Code samples

Basic examples

#include <strf/to_string.hpp>
#include <assert>

constexpr int x = 255;

void basic_samples()
{
    // Creating a std::string
    auto str = strf::to_string(x, " in hexadecimal is ", *strf::hex(x), '.');
    assert(str == "255 in hexadecimal is 0xff.");

    // Alternative syntax to enable i18n
    auto str_tr = strf::to_string.tr("{} in hexadecimal is {}.", x, *strf::hex(x));
    assert(str_tr == str);

    // Applying a facet
    auto to_string_mc = strf::to_string.with(strf::mixedcase);
    auto str_mc = to_string_mc(x, " in hexadecimal is ", *strf::hex(x), '.');
    assert(str_mc == "255 in hexadecimal is 0xFF.");

    // Achieving the same result, but in multiple steps:
    strf::string_maker str_maker;
    strf::to(str_maker) (x, " in hexadecimal is ");
    strf::to(str_maker).with(strf::mixedcase) (*strf::hex(x), '.');
    auto str_mc_2 = str_maker.finish();
    assert(str_mc_2 == str_mc);

    // Writing instead to char*
    char buff[200];
    strf::to(buff, sizeof(buff)) (x, " in hexadecimal is ", *strf::hex(x), '.');
    assert(str == buff);
}

Alignment formatting

#include <strf/to_string.hpp>
#include <assert>

void alignment_formatting()
{
    using namespace strf::format_functions;

    assert(strf::to_string(dec(123) > 8)  == "     123");
    assert(strf::to_string(dec(123) < 8)  == "123     ");
    assert(strf::to_string(dec(123) ^ 8)  == "  123   ");

    assert(strf::to_string(right(123, 8))        == "     123");
    assert(strf::to_string(right(123, 8,  '~'))  == "~~~~~123");
    assert(strf::to_string(left(123, 8,  '~'))   == "123~~~~~");
    assert(strf::to_string(center(123, 8,  '~')) == "~~123~~~");

    assert(strf::to_u8string(right(123, 8, U'')) == u8"‥‥‥‥‥123");
}

Note: Strf calculates string width the same way as specified to std::format in C++20, which takes into account grapheme clustering.

Single character argument

#include <strf/to_string.hpp>
#include <assert>

void single_character_argument()
{
    using namespace strf::format_functions; // strf::multi, strf::right

    assert(strf::to_string('a') == "a");
    assert(strf::to_string(multi('a', 5)) == "aaaaa");
    assert(strf::to_string(multi('a', 5) > 8) == "   aaaaa");
    assert(strf::to_string(right('a', 8, '.').multi(5)) == "...aaaaa");

    // char32_t is implicitly transcoded
    assert(strf::to_string(U'a') == "a");
    assert(strf::to_u8string(U'\u2022') == u8"");
    assert(strf::to_u8string(multi(U'\u2022', 5) > 8) == u8"   •••••");

    // strf::to_string(L'a') // doesn't compile: it must be char32_t or
                             // the same as the destination character type
}

Numeric Formatting

#include <strf/to_string.hpp>
#include <numbers> // C++20, defines std::numbers::pi
#include <assert>

void numeric_formatting()
{
    using namespace strf::format_functions;

    //  In printf  |       In Strf
    //-------------+-----------------------
    //         Integers
    //-------------+-----------------------
    //      'd'    |   .dec() or dec(value)
    //      'o'    |   .oct() or oct(value)
    //      'x'    |   .hex() or hex(value)
    //             |   .bin() or bin(value)
    //-------------+-----------------------
    //      Floating Points
    //-------------+-----------------------
    //      'x'    |   hex(value).p(6) or   hex(value, 6)
    //      'f'    | fixed(value).p(6) or fixed(value, 6)
    //    'e' 'E'  |   sci(value).p(6) or   sci(value, 6)
    //      'g'    |   gen(value).p(6) or   gen(value, 6)
    //-------------+-----------------------
    //   Integers and Floating Points
    //-------------+-----------------------
    //      '+'    |    .operator+()
    //      '#'    |    .operator*()
    //      ' '    |    .operator~()
    //  .precision |    .p(precision), or as the second argument of
    //             |                 hex(), fixed(), sci() or gen()
    //      '0'    |    .pad0(width) or pad0(value, width)

    assert(strf::to_string(  fmt(1.)) == "1");
    assert(strf::to_string( *fmt(1.)) == "1.");
    assert(strf::to_string( +fmt(1.)) == "+1");
    assert(strf::to_string(+*fmt(1.)) == "+1.");
    assert(strf::to_string( ~fmt(1.5)) == " 1.5");
    assert(strf::to_string( ~left(1.5, 8, '*')) == "*1.5****");

    assert(strf::to_string(sci(1.0))     == "1e+00");
    assert(strf::to_string(fixed(1e+10)) == "10000000000");

    //----------------------------------------------------------------
    // Strf prints enough digits for exact recovery on parsing
    // regardless of notation
    using std::numbers::pi;
    assert(strf::to_string(fixed(pi)) == "3.141592653589793");

    // , unless a precision is specified
    assert(strf::to_string(fixed(pi).p(4)) == "3.1416");
    assert(strf::to_string(fixed(pi, 4))   == "3.1416");
    assert(strf::to_string(gen(pi, 4))     == "3.142");

    // ---------------------------------------------------------------
    // pad0()
    assert(strf::to_string(+*pad0(1., 5))     == "+001.");
    assert(strf::to_string(+*pad0(1., 5) > 8) == "   +001.");

    // For nan and inf, pad0 sets the minimum alignment width:
    constexpr auto nan = std::numeric_limits<double>::quiet_NaN();
    assert(strf::to_string(pad0(nan, 8))              == "     nan");
    assert(strf::to_string(left(nan, 4, '*').pad0(8)) == "nan*****");
    assert(strf::to_string(left(nan, 8, '*').pad0(4)) == "nan*****");

    //----------------------------------------------------------------
    // The strf::lettercase facet
    constexpr auto to_string_upper = strf::to_string.with(strf::uppercase);
    constexpr auto to_string_lower = strf::to_string.with(strf::lowercase); // default
    constexpr auto to_string_mixed = strf::to_string.with(strf::mixedcase);

    assert(to_string_upper(*hex(0xaa), " ", sci(1.)) == "0XAA 1E+00");
    assert(to_string_lower(*hex(0xaa), " ", sci(1.)) == "0xaa 1e+00");
    assert(to_string_mixed(*hex(0xaa), " ", sci(1.)) == "0xAA 1e+00");
}

Numeric Punctuation

#include <strf/to_string.hpp>
#include <strf/locale.hpp> // strf::locale_numpunct

void numeric_punctuation()
{
    // German punctuation
    auto s = strf::to_string.with(strf::numpunct_de_DE) (!strf::fixed(1000000.5));
    assert(s == "1.000.000,5");

    // You have to use format function `strf::punct` or `.punct()`
    // or operator! to apply punctuation
    s = strf::to_string.with(strf::numpunct_de_DE)
        ( !strf::fixed(1000000.5), "  ", strf::fixed(1000000.5)
        , "  ", strf::punct(10000), "  ", 100000 );
    assert(s == "1.000.000,5  1000000.5  10.000  100000");

    // Use strf::locale_numpunct to get the
    // punctuation of current global locale
    try {
        const std::locale loc("en_US.UTF-8");
        const auto previous_loc = std::locale::global(loc);
        const auto loc_punct = strf::locale_numpunct(); // from <strf/locale.hpp>
        std::locale::global(previous_loc); // this does not affect loc_punt

        const auto result = strf::to_string.with(loc_punct) (*!strf::fixed(1000000.5));
        assert(result == "1,000,000.5");
    } catch (std::runtime_error&) {
        // locale not supported
    }

    // Manually specifing a punctuation
    constexpr auto my_fancy_punct = strf::numpunct<10>(3)
        .thousands_sep(U'')
        .decimal_point(U''); // U+2396
    auto s2 = strf::to_u8string.with(my_fancy_punct) (!strf::fixed(1000000.5));
    assert(s2 == u8"1•000•000⎖5");

    // With variable grouping
    constexpr auto my_fancy_punct_2 = strf::numpunct<10>(3, 2, 1)
        .thousands_sep(U'')
        .decimal_point(U'');
    auto s3 = strf::to_u8string.with(my_fancy_punct_2)
        (strf::punct(10000000.125));
    assert(s3 == u8"1•0•0•00•000⎖125");

    // Non-decimal bases
    constexpr auto my_hex_punct = strf::numpunct<16>(4).thousands_sep('\'');
    auto s4 = strf::to_string.with(my_hex_punct)(!strf::hex(0xFFFFFFF));
    assert(s4 == "fff'ffff");
}

Transcoding

#include <strf/to_string.hpp>

void transcoding()
{
    // Converting UTF-16 to UTF-8
    auto str_narrow = strf::to_string("He was born in ", strf::transcode(u"خنيفرة"), '.');
    assert(str_narrow == "He was born in \xd8\xae\xd9\x86\xd9\x8a\xd9\x81\xd8\xb1\xd8\xa9.");

    auto str_u8 = strf::to_u8string(u8"He was born in ", strf::transcode(u"خنيفرة"), u8'.');
    assert(str_u8 == u8"He was born in خنيفرة.");


    // Converting UTF-8 to UTF-16
    assert(strf::to_u16string(strf::transcode(str_narrow)) == u"He was born in خنيفرة.");
    assert(strf::to_u16string(strf::transcode(str_u8)) == u"He was born in خنيفرة.");


    // Converting UTF-16 to ISO-8859-6
    auto str_narrow_2 = strf::to_string.with(strf::iso_8859_6<char>)
        ( "He was born in ", strf::transcode(u"خنيفرة"), '.');
    assert(str_narrow_2 == "He was born in \xce\xe6\xea\xe1\xd1\xc9.");


    // Converting char8_t string to ISO-8859-6
    auto str_narrow_3 = strf::to_string.with(strf::iso_8859_6<char>)
        ( "He was born in ", strf::transcode(u8"خنيفرة"), '.');
    assert(str_narrow_3 == str_narrow_2);


    // Converting UTF-8 to ISO-8859-6
    // ( if the source character type is the same as the destination
    //   character type, the charset must be specified inside strf::transcode() )
    auto str_narrow_4 = strf::to_string.with(strf::iso_8859_6<char>)
        ( "He was born in "
        , strf::transcode( "\xd8\xae\xd9\x86\xd9\x8a\xd9\x81\xd8\xb1\xd8\xa9"
                         , strf::utf8<char> )
        , '.' );
    assert(str_narrow_4 == str_narrow_2);


    // Converting ISO-8859-6 to UTF-16
    auto str_u16 = strf::to_u16string
        ( u"He was born in "
        , strf::transcode("\xce\xe6\xea\xe1\xd1\xc9", strf::iso_8859_6<char>)
        , u'.' );
    assert(str_u16 == u"He was born in خنيفرة.");

    // or
    str_u16 = strf::to_u16string.with(strf::iso_8859_6<char>)
        ( u"He was born in "
        , strf::transcode("\xce\xe6\xea\xe1\xd1\xc9")
        , u'.' );
    assert(str_u16 == u"He was born in خنيفرة.");


    // Several transcodings in a single statemet
    auto str = strf::to_u8string( strf::transcode(u"aaa--")
                                , strf::transcode(U"bbb--")
                                , strf::transcode( "\x80\xA4"
                                                 , strf::windows_1252<char> ) );
    assert(str == u8"aaa--bbb--\u20AC\u00A4");
}

Joining arguments

#include <strf/to_string.hpp>

void joins()
{
    // strf::join makes a sequence of arguments to be treated as one
    const char* dirname = "/tmp";
    const char* filename = "tmp1234";
    auto s = strf::to_string.tr( "Could not open file {}"
                               , strf::join(dirname, '/', filename) );
    assert(s == "Could not open file /tmp/tmp1234");

    // join_left, join_center and join_right align several arguments as one
    const int value = 255;
    s = strf::to_string
        ( strf::join_center(40, U'.')
            ( value, " in hexadecimal is ", strf::hex(value) ) );

    assert(s == "........255 in hexadecimal is ff........");


    // You can also use operators < > ^ to a align a join
    auto j = strf::join(value, " in hexadecimal is ", strf::hex(value));
    s = strf::to_string(j ^ 40);
    assert(s == "        255 in hexadecimal is ff        ");
}

Ranges

#include <strf/to_string.hpp>

void ranges()
{
    int array[] = {10, 20, 30, 40};

    // Basic
    auto str = strf::to_string( "--[", strf::range(array), "]--");
    assert(str == "--[10203040]--");


    // With separator
    str = strf::to_string( "--[", strf::separated_range(array, " / "), "]--");
    assert(str == "--[10 / 20 / 30 / 40]--");


    // With separator and formatting
    str = strf::to_string( "--["
                         , *strf::fmt_separated_range(array, " / ").hex().p(4)
                         , "]--");
    assert(str == "--[0x000a / 0x0014 / 0x001e / 0x0028]--");


    // Transforming the elements
    auto func = [](int x){ return strf::join('<', strf::pad0(x, 4), '>'); };

    str = strf::to_string(strf::range(array, func));
    assert(str == "<0010><0020><0030><0040>");

    str = strf::to_string(strf::separated_range(array, " ", func));
    assert(str == "<0010> <0020> <0030> <0040>");
}

strf's People

Contributors

ckerr avatar robhz786 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

strf's Issues

Member names - consider not starting with an underscore

In C++, it is forbidden to use identifiers having two consecutive underscores, or beginning with an underscore and a capital letter. Your use of underscore+lowercase letter is valid, but it's customarily avoided and many recommend against it. I'd consider placing the extra underscore at the end, i.e. my_class::_foo becomes my_class::_foo::foo_.

Use `std::copy_n` where relevant

You have some place in the repository with this kind of code:

        auto digits_2 = digits + grp_size;
        std::copy(digits, digits_2, it);

(this is from detail/input_types/float.hpp)

This is artificial twisting. Just write:

        std::copy_n(digits, grp_size, it);

Of course, I'm going to use strf::detail::str_copy_n() (edit: actually, sometimes this isn't like str_copy_n, because the input and output iterators have a different type. But that doesn't matter in this repository for now.)

Compiler warning: pointless comparison of unsigned integer with zero

When compiling some code with strf, and using the -W switch, I'm getting:

/opt/strf/include/strf/detail/input_types/int.hpp(409): warning: pointless comparison of unsigned integer with zero
          detected during:
            instantiation of "void strf::detail::partial_fmt_int_printer<CharT, Base>::_init<IntT,HasPunct>(IntT, strf::int_format_data) [with CharT=char, Base=10, IntT=unsigned int, HasPunct=false]" 
(359): here
            instantiation of "strf::detail::partial_fmt_int_printer<CharT, Base>::partial_fmt_int_printer(const FPack &, Preview &, IntT, strf::int_format_data, strf::tag<IntT, IntTag>) [with CharT=char, Base=10, FPack=strf::facets_pack<>, Preview=strf::print_preview<false, false>, IntT=unsigned int, IntTag=unsigned int]" 
(586): here
            instantiation of "strf::detail::full_fmt_int_printer<CharT, Base>::full_fmt_int_printer(const FPack &, Preview &, strf::int_with_format<IntT, Base, true>) [with CharT=char, Base=10, FPack=strf::facets_pack<>, Preview=strf::print_preview<false, false>, IntT=unsigned int]" 
(781): here
            instantiation of "strf::detail::full_fmt_int_printer<CharT, Base> strf::make_printer<CharT,FPack,Preview,IntT,Base>(strf::rank<1UL>, const FPack &, Preview &, const strf::int_with_format<IntT, Base, true> &) [with CharT=char, FPack=strf::facets_pack<>, Preview=strf::print_preview<false, false>, IntT=unsigned int, Base=10]" 

The offending piece of code is:

_negative = value < 0;

Two templates for strf::range coincide

If I try to use:

strf::range<const char*>(some_const_char_ptr, another_const_char_ptr)

I get the error:

error: more than one instance of overloaded function "strf::range" matches the argument list:
            function template "auto strf::range(ForwardIt, ForwardIt)"
            function template "auto strf::range(const Range &, const CharT *)"
            argument types are: (util::constexpr_string::const_iterator, util::constexpr_string::const_iterator)

I guess somehow the second template parameter is inferred.

Right now I'm using

strf::range_p<const char *>{some_const_char_ptr, another_const_char_ptr}

as a workaround, but I shouldn't have to do that.

What could be done is the following:

- inline STRF_HD auto range(const Range& range, const CharT* sep)
+ inline STRF_HD auto range(const typename std::enable_if<not std::is_pointer<typename std::remove_cv<Range>::type>::value, Range &>::type range, const CharT* sep)

Determine how many leading chars in a string are valid?

Hey, thanks for writing strf!

The use case I'm working with is that, given a string, I'd like to find out how much of it is a valid sequence.

It looks like writing to a discard_destination and registering an invalid_seq_notifier would get halfway there, with a pass/fail for the entire string, but the invalid notifier callback has no args, e.g. a pointer to the invalid src_it, so I don't think getting the span of valid bytes is currently possible?

Need a bin() equivalent of hex(), oct() and dec()

It's important to be able to print the bit representation of values in memory; at the very least for integer-typed values.

The library should therefore have a strf::bin(), and int_format_fn should have a bin() member.

PS - It's true that this doesn't exist in the standard library, but it's only for historical reasons (see also this discussion).

unsigned char printing behavior different from std::cout

If you print an unsigned char using a cstr_writer, you'll get the number printed; if you stream that value to std::cout, you'll get the character with that ASCII value.

I get this in a CUDA kernel, but it's probably the same in host-side code.

Error (?) in the documentation, Section 6.5

In section 6.5 of the quick reference, it says:

template <typename Iterator, typename CharT>
/*...*/ range(const Iterator& begin, const Iterator& end);

but in fact, in the source we have:

template <typename ForwardIt>
inline STRF_HD auto range(ForwardIt begin, ForwardIt end)

i.e. not the same template params.

CUDA trouble again...

The current development branch does not build with CUDA 10.2; and definitely doesn't build with CUDA 11.3. In fact, even strf 0.12.2, which builds with CUDA 10.2, doesn't build 11.3.

... ah, well, it looks like strf now requires compilation in C++14 mode. I can see why you might want to require that, but cuda-kat is C++11. And the CUDA tests for strf using C++11 NVCC compilation. So, any chance of strf being made C++11-compatible again?

Missing STRF_HD signifiers in format_functions.hpp

There are still some STRF_HD signifiers missing from format_functions.hpp:

  • format_switcher::f (two variants),
  • alignment_format_fn::as_derived_ref()
  • alignment_format_fn::as_derived_rvalue_ref()

Triggered by the program in issue #20.

fmt() fails on the GPU

Consider the write_within_kernel unit test, and specifically, the kernel_using_cstr_to() kernel in which it's easy to demonstrate this issue. Its code is:

__global__ void kernel_using_cstr_to(char* buffer, std::size_t buffer_size)
{
	int global_thread_id = threadIdx.x + blockIdx.x * blockDim.x;
	auto printer = strf::to(buffer, buffer_size);
	printer ( "Hello", ' ', "world, from thread ", global_thread_id );
}

This makes extremely limited use of the capabilities of strf, and perhaps we were hasty in not testing more functionality. Specifically, even the following small addition is problematic:

	printer ( strf::fmt(threadIdx.x) );

This produces a bunch of warnings; and when running the thing, we get a launch failure. (edit: Need to establish exactly why.)

Re-list version 0.10.4

Hello @robhz786 :-)

My last release of cuda-kat requires v0.10.4 of strf, or later on the 0.10 line. But - 0.10.4 was removed (I think; it was released, right?)

Now, I'll update the code to be compatible with a newer version, but please keep 0.10.4 up on the versions page so that people can actually use my existing release.

Possible floating point presentation error on RISC-V

>>> [gameplay1] says: assertion k >= cache_holder<FloatFormat>::min_k && k <= cache_holder<FloatFormat>::max_k failed: "/home/gonzo/github/rvscript/programs/micro/ext/strf/include/strf/detail/dragonbox.hpp", line 2337, function: static constexpr typename strf::detail::jkj::dragonbox::detail::cache_holder<FloatFormat>::cache_entry_type strf::detail::jkj::dragonbox::detail::policy_impl::cache::full::get_cache(int) [with FloatFormat = strf::detail::jkj::dragonbox::ieee754_binary32; typename strf::detail::jkj::dragonbox
[0] 0x0000000000123e78 + 0x014: syscall(long)

I've spent some time on this and I cannot explain it. Every other formatting library can print floats, although I do realize that va_arg promotes to double. So, from what I remember printing 1.0f works, but everything else ends up as 8e-47 and so on.

I am willing and able to debug it further, but I was doing something else when the presentation issue .. presented itself. It's probably important to mention that I am running this in a custom RISC-V emulator, which means it is possible that I am emulating something wrongly. I haven't seen any wrong emulation happen in several months, so I am hoping that maybe this problem is related to something else?

The only significant change happening lately is changing from RISC-V GCC 9.x to 11.x.

Any ideas?

strf::left and strf::right add extra digit in device-side code

Consider the following program:

#include <stdio.h>
#include <strf.hpp>

__device__ __host__ void formatting_functions()
{
        char buffer[20];
        auto printer = strf::to(buffer, sizeof(buffer));
        printer ( strf::right(1, 2, '0') );
        printf("%*s\n", 10, buffer);
        printer ( strf::left(1, 2, '0') );
        printf("%*s\n", 10, buffer);
        printer ( strf::right(1, 4, '0') );
        printf("%*s\n", 10, buffer);
        printer ( strf::left(1, 4, '0') );
        printf("%*s\n", 10, buffer);
}

__global__ void ff_kernel()
{
        formatting_functions();
}

int main(void)
{
        int threads_per_block { 1 };
        int blocks_in_grid { 1 };
        printf("Device-side results:\n"); fflush(stdout);
        ff_kernel<<<threads_per_block, blocks_in_grid>>>();
        cudaDeviceReset();
        printf("Host-side results: \n"); fflush(stdout);
        formatting_functions();
}

and let's use the master branch.

When compiling this, we get warnings about calling a host-side from device-side functions; that's the first problem. But - it does build. And the output is:

Device-side results:
       001
       100
     00001
     10000
Host-side results: 
        01
        10
      0001
      1000

So, an extra fill digits. That's the bug.

Codecov issues?

Tom from Codecov here. I saw that you had commented out the call to upload coverage here and just wanted to make sure that there was nothing on our end that was broken.

"parameter pack was references but not expanded" in printers_tuple.hpp

When compiling printers_tuple.hpp with NVCC, I get the following errors:

detail/printers_tuple.hpp(50): error: parameter pack "I" was referenced but not expanded
detail/printers_tuple.hpp(50): error: parameter pack "T" was referenced but not expanded
detail/printers_tuple.hpp(50): error: parameter pack "args" was referenced but not expanded
detail/printers_tuple.hpp(50): error: expected a "{"
detail/printers_tuple.hpp(151): error: parameter pack "I" was referenced but not expanded
detail/printers_tuple.hpp(151): error: parameter pack "Printers" was referenced but not expanded
detail/printers_tuple.hpp(152): error: expected a "{"

And indeed, it does seem you're using unexpanded parameter packs. Bug?

Developer warning when building benchmarks

If you set the BUILD_BENCHMARKS CMake variable, you get a screen saying:

 CMake Warning (dev) at performance/CMakeLists.txt:3 (project):
   Policy CMP0048 is not set: project() command manages VERSION variables.
   Run "cmake --help-policy CMP0048" for policy details.  Use the cmake_policy
   command to set the policy and suppress this warning.

   The following variable(s) would be set to empty:

     PROJECT_VERSION
     PROJECT_VERSION_MAJOR
     PROJECT_VERSION_MINOR
     PROJECT_VERSION_PATCH
 This warning is for project developers.  Use -Wno-dev to suppress it.


 CMake Error at CMakeLists.txt:133 (add_subdirectory):
   The source directory

     /home/eyalroz/src/strf/externals/fmt

   does not contain a CMakeLists.txt file.

THis shouldn't happen...

Consider more renaming for clarity

If cv() is now convert_encoding(), it probably makes sense to rename sani() into sanitize()...

Also - doesn't cv_string now need to be converted_encoding_string ?

More renaming ideas:

  • underlying_outbuf::pos(), outbuf::pos() etc. - very confusing! Readers will tend to assume this method returns a numeric value. But - I don't have a great idea for an alternative name... at_current_pos()/at_current_position() ? Hmm.
  • outbuf -> output_buffer - these days, I think streambuf would not have made it past the language standard committee...

strf should warn you when using 0 as a fill character

I've just resolved this bug which was due to me saying:

fmt(my_number).fill(0)

when in fact I should have written

fmt(my_number).fill('0')

I wonder if it wouldn't be a good idea for strf to warn me somehow that I'm using the NUL character as a fill value.

Repository version not reflected anywhere

This repository has versioned releases - but the release version is not reflected anywhere: Neither in the code nor in the build mechanism.

We should apply common CMake practice for package versioning.

Add something equivalent to the printf flags '0' and ' '

This is my initial plan:

  • Create a new format function pad0 in int_format_fn and float_format_fn equivalent to the '0' format flag in print. For NaN and Inf floating-points, it has the same effect as the format function right.

    • It will be based on a new enum numeric_alignment{left, right, center, zeros}
  • Create a new format function space in int_format_fn and float_format_fn equivalent to the ' ' format flag in print

  • Remove int precision ( format function int_format_fn::p )

  • Remove text_alignment::split and alignment_formatter_fn::operator%

Wrong result when rounding up 9.999...

  • strf::sci(9.6e-5).p(0) is printed as ":e-05" — it should be "1e-04"
  • strf::sci(9.9996e-5).p(3) printed as "1.000e-05" — it should be "1.000e-04"
  • strf::sci(9.9996e+5).p(3) printed as "1.000e+05" — it should be "1.000e+06"

The same happens with strf::gen

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.