strings::format string view support

This commit is contained in:
2018-09-04 05:18:59 +07:00
parent 2ce653eacc
commit 5b95a68ffe
8 changed files with 74 additions and 25 deletions

View File

@@ -7,6 +7,7 @@
#pragma once #pragma once
#include "_base.hpp" #include "_base.hpp"
#include "configs.hpp" #include "configs.hpp"
#include "macros.hpp" #include "macros.hpp"
#include "stdex.hpp" #include "stdex.hpp"

View File

@@ -398,6 +398,10 @@ namespace e2d { namespace stdex
size_type size_ = 0; size_type size_ = 0;
}; };
template < typename Char, typename Traits >
const typename basic_string_view<Char, Traits>::size_type
basic_string_view<Char, Traits>::npos;
template < typename Char, typename Traits > template < typename Char, typename Traits >
bool operator<( bool operator<(
basic_string_view<Char, Traits> l, basic_string_view<Char, Traits> l,

View File

@@ -17,4 +17,5 @@
#include "streams.hpp" #include "streams.hpp"
#include "strfmts.hpp" #include "strfmts.hpp"
#include "strings.hpp" #include "strings.hpp"
#include "strings.inl"
#include "time.hpp" #include "time.hpp"

View File

@@ -353,6 +353,13 @@ namespace e2d { namespace strings
} }
}; };
template <>
class format_arg<str_view> : public format_arg<str> {
public:
explicit format_arg(str_view sv)
: format_arg<str>(sv) {}
};
// //
// wstr // wstr
// //
@@ -372,6 +379,13 @@ namespace e2d { namespace strings
} }
}; };
template <>
class format_arg<wstr_view> : public format_arg<wstr> {
public:
explicit format_arg(wstr_view sv)
: format_arg<wstr>(sv) {}
};
// //
// str16 // str16
// //
@@ -391,6 +405,13 @@ namespace e2d { namespace strings
} }
}; };
template <>
class format_arg<str16_view> : public format_arg<str16> {
public:
explicit format_arg(str16_view sv)
: format_arg<str16>(sv) {}
};
// //
// str32 // str32
// //
@@ -410,6 +431,13 @@ namespace e2d { namespace strings
} }
}; };
template <>
class format_arg<str32_view> : public format_arg<str32> {
public:
explicit format_arg(str32_view sv)
: format_arg<str32>(sv) {}
};
// //
// color // color
// //

View File

@@ -46,10 +46,10 @@ namespace e2d
template < typename... Args > template < typename... Args >
std::size_t format( std::size_t format(
char* dst, std::size_t size, char* dst, std::size_t size,
const char* fmt, Args&&... args); str_view fmt, Args&&... args);
template < typename... Args > template < typename... Args >
str rformat(const char* fmt, Args&&... args); str rformat(str_view fmt, Args&&... args);
bool wildcard_match(str_view string, str_view pattern); bool wildcard_match(str_view string, str_view pattern);
} }

View File

@@ -238,8 +238,10 @@ namespace e2d { namespace strings
template < typename Tuple > template < typename Tuple >
std::enable_if_t<std::tuple_size<Tuple>::value <= 10, std::size_t> std::enable_if_t<std::tuple_size<Tuple>::value <= 10, std::size_t>
format_impl(char* dst, std::size_t size, const char* format, const Tuple& targs) { format_impl(char* dst, std::size_t size, str_view fmt, const Tuple& targs) {
if ( !format ) { const char* format_i = fmt.cbegin();
const char* const format_e = fmt.cend();
if ( !format_i ) {
throw bad_format(); throw bad_format();
} }
if ( !dst != !size ) { if ( !dst != !size ) {
@@ -248,20 +250,19 @@ namespace e2d { namespace strings
std::size_t result = 0; std::size_t result = 0;
const char* const b_dst = dst; const char* const b_dst = dst;
const char* const e_dst = b_dst ? b_dst + size : nullptr; const char* const e_dst = b_dst ? b_dst + size : nullptr;
while ( *format ) { while ( format_i != format_e ) {
if ( dst && dst == e_dst - 1 ) { if ( dst && dst == e_dst - 1 ) {
*dst = '\0'; *dst = '\0';
throw bad_format_buffer(); throw bad_format_buffer();
} }
if ( *format != '%' ) { if ( *format_i != '%' ) {
if ( dst ) { if ( dst ) {
*dst++ = *format; *dst++ = *format_i;
} }
++result; ++result;
++format; ++format_i;
} else { } else {
const char n_param = *(++format); if ( ++format_i == format_e ) {
if ( !n_param ) {
// "hello%" // "hello%"
if ( dst ) { if ( dst ) {
*dst = '\0'; *dst = '\0';
@@ -273,7 +274,7 @@ namespace e2d { namespace strings
? math::numeric_cast<std::size_t>(e_dst - dst) ? math::numeric_cast<std::size_t>(e_dst - dst)
: 0; : 0;
E2D_ASSERT(!dst || dst_tail_size); E2D_ASSERT(!dst || dst_tail_size);
switch ( n_param ) { switch ( *format_i ) {
case '0' : case '0' :
write_arg_r = write_arg_n<0>(dst, dst_tail_size, targs); write_arg_r = write_arg_n<0>(dst, dst_tail_size, targs);
break; break;
@@ -337,7 +338,7 @@ namespace e2d { namespace strings
dst += write_bytes; dst += write_bytes;
} }
result += write_bytes; result += write_bytes;
++format; ++format_i;
} }
} }
if ( dst ) { if ( dst ) {
@@ -353,7 +354,7 @@ namespace e2d { namespace strings
template < typename... Args > template < typename... Args >
std::size_t format( std::size_t format(
char* dst, std::size_t size, char* dst, std::size_t size,
const char* fmt, Args&&... args) str_view fmt, Args&&... args)
{ {
return impl::format_impl( return impl::format_impl(
dst, size, fmt, dst, size, fmt,
@@ -361,7 +362,7 @@ namespace e2d { namespace strings
} }
template < typename... Args > template < typename... Args >
str rformat(const char* fmt, Args&&... args) { str rformat(str_view fmt, Args&&... args) {
auto targs = std::make_tuple( auto targs = std::make_tuple(
impl::wrap_arg(std::forward<Args>(args))...); impl::wrap_arg(std::forward<Args>(args))...);
const std::size_t expected_format_size = impl::format_impl( const std::size_t expected_format_size = impl::format_impl(

View File

@@ -68,7 +68,7 @@ namespace
dst.assign(img_size, img_format, std::move(img_buffer)); dst.assign(img_size, img_format, std::move(img_buffer));
return true; return true;
} }
} catch (std::exception&) { } catch (...) {
// nothing // nothing
} }
return false; return false;

View File

@@ -7,6 +7,16 @@
#include "_utils.hpp" #include "_utils.hpp"
using namespace e2d; using namespace e2d;
namespace
{
const char* null_utf8 = nullptr;
const wchar_t* null_wide = nullptr;
const char16_t* null_utf16 = nullptr;
const char32_t* null_utf32 = nullptr;
str_view null_view = {null_utf8, 0};
}
TEST_CASE("strings") { TEST_CASE("strings") {
{ {
REQUIRE(make_utf8("hello") == "hello"); REQUIRE(make_utf8("hello") == "hello");
@@ -30,11 +40,6 @@ TEST_CASE("strings") {
REQUIRE(make_utf32(U"hello") == U"hello"); REQUIRE(make_utf32(U"hello") == U"hello");
} }
{ {
const char* null_utf8 = nullptr;
const wchar_t* null_wide = nullptr;
const char16_t* null_utf16 = nullptr;
const char32_t* null_utf32 = nullptr;
REQUIRE(make_utf8(str_view(null_utf8, 0)) == make_utf8(u"")); REQUIRE(make_utf8(str_view(null_utf8, 0)) == make_utf8(u""));
REQUIRE(make_utf8(wstr_view(null_wide, 0)) == make_utf8(L"")); REQUIRE(make_utf8(wstr_view(null_wide, 0)) == make_utf8(L""));
REQUIRE(make_utf8(str16_view(null_utf16, 0)) == make_utf8(u"")); REQUIRE(make_utf8(str16_view(null_utf16, 0)) == make_utf8(u""));
@@ -95,8 +100,6 @@ TEST_CASE("strings") {
REQUIRE(wildcard_match("", "*") == true); REQUIRE(wildcard_match("", "*") == true);
REQUIRE(wildcard_match("", "?") == false); REQUIRE(wildcard_match("", "?") == false);
const char* null_utf8 = nullptr;
str_view null_view = {null_utf8, 0};
REQUIRE(wildcard_match(null_view, null_view) == true); REQUIRE(wildcard_match(null_view, null_view) == true);
REQUIRE(wildcard_match("a", null_view) == false); REQUIRE(wildcard_match("a", null_view) == false);
REQUIRE(wildcard_match(null_view, "*") == true); REQUIRE(wildcard_match(null_view, "*") == true);
@@ -214,7 +217,6 @@ TEST_CASE("strings") {
} }
{ {
char buf[6]; char buf[6];
REQUIRE_THROWS_AS(strings::format(buf, sizeof(buf), nullptr), strings::bad_format);
REQUIRE_THROWS_AS(strings::format(buf, 0, "hello"), strings::bad_format_buffer); REQUIRE_THROWS_AS(strings::format(buf, 0, "hello"), strings::bad_format_buffer);
REQUIRE_THROWS_AS(strings::format(nullptr, sizeof(buf), "hello"), strings::bad_format_buffer); REQUIRE_THROWS_AS(strings::format(nullptr, sizeof(buf), "hello"), strings::bad_format_buffer);
REQUIRE_THROWS_AS(strings::format(buf, sizeof(buf), "helloE"), strings::bad_format_buffer); REQUIRE_THROWS_AS(strings::format(buf, sizeof(buf), "helloE"), strings::bad_format_buffer);
@@ -235,8 +237,6 @@ TEST_CASE("strings") {
REQUIRE_THROWS_AS(strings::format(buf, sizeof(buf), "%z%hell"), strings::bad_format); REQUIRE_THROWS_AS(strings::format(buf, sizeof(buf), "%z%hell"), strings::bad_format);
} }
{ {
REQUIRE_THROWS_AS(strings::rformat(nullptr), strings::bad_format);
REQUIRE_THROWS_AS(strings::rformat("%"), strings::bad_format); REQUIRE_THROWS_AS(strings::rformat("%"), strings::bad_format);
REQUIRE_THROWS_AS(strings::rformat("%hell"), strings::bad_format); REQUIRE_THROWS_AS(strings::rformat("%hell"), strings::bad_format);
REQUIRE_THROWS_AS(strings::rformat("he%ll"), strings::bad_format); REQUIRE_THROWS_AS(strings::rformat("he%ll"), strings::bad_format);
@@ -250,6 +250,20 @@ TEST_CASE("strings") {
REQUIRE_THROWS_AS(strings::rformat("hell%y%"), strings::bad_format); REQUIRE_THROWS_AS(strings::rformat("hell%y%"), strings::bad_format);
REQUIRE_THROWS_AS(strings::rformat("%z%hell"), strings::bad_format); REQUIRE_THROWS_AS(strings::rformat("%z%hell"), strings::bad_format);
} }
{
REQUIRE(strings::rformat(str_view("%0"), 42) == "42");
REQUIRE(strings::rformat(str_view("%0%1",2), 42) == "42");
auto s1 = make_utf8("hello");
auto s2 = make_wide("hello");
auto s3 = make_utf16("hello");
auto s4 = make_utf32("hello");
REQUIRE(strings::rformat(str_view("%0"), str_view(s1)) == "hello");
REQUIRE(strings::rformat(str_view("%0"), wstr_view(s2)) == "hello");
REQUIRE(strings::rformat(str_view("%0"), str16_view(s3)) == "hello");
REQUIRE(strings::rformat(str_view("%0"), str32_view(s4)) == "hello");
}
{ {
char buf[1]; char buf[1];