Skip to content

Commit

Permalink
num_get has early padding & base support
Browse files Browse the repository at this point in the history
  • Loading branch information
malachib committed Jun 17, 2024
1 parent 5c51865 commit 3aebb69
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 39 deletions.
41 changes: 31 additions & 10 deletions src/estd/internal/ios_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class ios_base
static CONSTEXPR fmtflags oct = 0x03;
#endif
static CONSTEXPR fmtflags basefield = dec | hex;
// Not supported yet
static CONSTEXPR fmtflags uppercase = 0x04;

// NOTE: "Has no effect on input"
// https://en.cppreference.com/w/cpp/io/manip/left
Expand All @@ -50,6 +52,9 @@ class ios_base

typedef uint8_t iostate;

// DEBT: Try making these enum if we can, primarily to auto deduce
// bit field size

static CONSTEXPR iostate goodbit = 0x00;
static CONSTEXPR iostate badbit = 0x01;
static CONSTEXPR iostate failbit = 0x02;
Expand All @@ -66,16 +71,26 @@ class ios_base
static CONSTEXPR seekdir cur = 0x02;

private:
struct
struct state
{
#if FEATURE_ESTD_AGGRESIVE_BITFIELD
fmtflags fmtfl_ : 8;
// DEBT: Experimental nodatabit doesn't fit here
iostate iostate_ : 4;
// Width applies to istream *and* ostream
unsigned width_ : 4;
#else
fmtflags fmtfl_;
iostate iostate_;
unsigned width_ : 16;
#endif

constexpr state() :
fmtfl_{dec},
iostate_{goodbit},
width_{0}
{}

} state_;

protected:
Expand All @@ -89,14 +104,21 @@ class ios_base
}

public:
// DEBT: Use initializer lists for compilers that have it
//ios_base() : fmtfl(dec), _iostate(goodbit) {}
ios_base()
ios_base() = default;

constexpr streamsize width() const
{
return state_.width_;
}

streamsize width(streamsize new_width)
{
state_.fmtfl_ = dec;
state_.iostate_ = goodbit;
streamsize old_width = width();
state_.width_ = new_width;
return old_width;
}


fmtflags setf(fmtflags flags)
{ fmtflags prior = state_.fmtfl_; state_.fmtfl_ |= flags; return prior; }

Expand Down Expand Up @@ -189,9 +211,6 @@ class basic_ostream_base

struct ostream_internal
{
// DEBT: Width applies to istream *and* ostream
unsigned width : 4;

// NOTE: Hitting compiler warning bug
// https://stackoverflow.com/questions/36005063/gcc-suppress-warning-too-small-to-hold-all-values-of
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51242#c31
Expand All @@ -202,13 +221,15 @@ class basic_ostream_base
//bool showbase : 1; // DEBT: Unused

ESTD_CPP_CONSTEXPR_RET ostream_internal() :
width(0), alignment(positioning_type::left),
alignment(positioning_type::left),
fillchar(0) // equivalent to space ' '
{
}

} ostream_;

#endif

};

}
Expand Down
7 changes: 7 additions & 0 deletions src/estd/internal/iosfwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,11 @@ template <class TStreambuf, class TBase>
detail::basic_istream<TStreambuf, TBase>&
ws(detail::basic_istream<TStreambuf, TBase>& __is);

// TODO: use specific 16/32/64 bit versions depending on architecture
typedef int streampos;
typedef int streamoff;
typedef int streamsize;



}
47 changes: 41 additions & 6 deletions src/estd/internal/locale/num_put.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace estd {
namespace internal {

//constexpr
inline unsigned get_base(const ios_base::fmtflags basefield)
inline unsigned get_base2(const ios_base::fmtflags basefield)
{
// DEBT: Consider a switch statement because we can, but might be slightly fragile
if(basefield == ios_base::hex)
Expand All @@ -31,14 +31,20 @@ inline unsigned get_base(const ios_base::fmtflags basefield)
// basefield mask is guaranteed to produce one of these 3 options
// DEBT: Ensure there's a unit test to that effect elsewhere
}
}

constexpr unsigned get_base(const ios_base::fmtflags basefield)
{
return basefield == ios_base::hex ? 16 :
basefield == ios_base::dec ? 10 :
8;
}

template <class TChar, class OutputIt, class TLocale = classic_locale_type>
template <class Char, class OutputIt, class Locale = classic_locale_type>
class num_put
{
public:
typedef TChar char_type;
typedef Char char_type;
typedef OutputIt iter_type;

private:
Expand All @@ -47,7 +53,11 @@ class num_put
{
// Hardcode to base 8 since that's the biggest version
// +1 for potential - sign
#if FEATURE_ESTD_OSTREAM_OCTAL
constexpr unsigned N = estd::numeric_limits<T>::template length<8>::value + 1;
#else
constexpr unsigned N = estd::numeric_limits<T>::template length<10>::value + 1;
#endif

const unsigned base = get_base(str.flags() & ios_base::basefield);

Expand All @@ -56,7 +66,32 @@ class num_put

to_chars_result result = to_chars_opt(buffer, buffer + N, value, base);

return copy(result.ptr, buffer + N, out);
unsigned width = str.width();
const unsigned result_width = buffer + N - result.ptr;

if(width > result_width)
{
width -= result_width;

const ios_base::fmtflags adj = str.flags() & ios_base::adjustfield;
if(adj == ios_base::left)
{
out = fill_n(out, width, fill);
return copy(result.ptr, buffer + N, out);
}
else if(adj == ios_base::right)
{
out = copy(result.ptr, buffer + N, out);
return fill_n(out, width, fill);
}
else
{
// DEBT: 'internal' flavor, needs work
return out;
}
}
else
return copy(result.ptr, buffer + N, out);
}

template <unsigned base, class T>
Expand All @@ -72,7 +107,7 @@ class num_put
static iter_type put(iter_type out, const ios_base& str, char_type fill,
bool value)
{
using np = numpunct<char_type, TLocale>;
using np = numpunct<char_type, Locale>;
// DEBT: We may prefer plain old const char* instead
layer2::const_string _v = value ? np::truename() : np::falsename();
const char* v = _v.data();
Expand All @@ -83,7 +118,7 @@ class num_put
template <class T>
// type filter not actually needed at the moment, but will probably come in handy when
// floats get involved
static typename enable_if<numeric_limits<T>::is_integer, iter_type>::type
static constexpr typename enable_if<numeric_limits<T>::is_integer, iter_type>::type
//static iter_type
put(iter_type out, const ios_base& str, char_type fill, T value)
{
Expand Down
18 changes: 2 additions & 16 deletions src/estd/internal/ostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class basic_ostream :
virtual
#endif
public Base,
internal::basic_ostream_base
public internal::basic_ostream_base
{
typedef Base base_type;

Expand Down Expand Up @@ -88,6 +88,7 @@ class basic_ostream :
#if FEATURE_ESTD_OSTREAM_SETW

public:
// DEBT: ASCII only
char_type fill() const
{
return 0x20 + ostream_.fillchar;
Expand Down Expand Up @@ -203,21 +204,6 @@ class basic_ostream :
ESTD_CPP_FORWARDING_CTOR(basic_ostream)
#endif

#if FEATURE_ESTD_OSTREAM_SETW
streamsize width() const
{
return ostream_.width;
}

streamsize width(streamsize new_width)
{
streamsize old_width = width();
ostream_.width = new_width;
return old_width;
}

#endif

};

} // detail
Expand Down
5 changes: 0 additions & 5 deletions src/estd/iosfwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ namespace estd {
template <class TState>
class fpos;

// TODO: use specific 16/32/64 bit versions depending on architecture
typedef int streampos;
typedef int streamoff;
typedef int streamsize;

template<class TStreambuf>
class istreambuf_iterator;

Expand Down
15 changes: 13 additions & 2 deletions test/catch/locale-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -383,11 +383,22 @@ TEST_CASE("locale")
{
// TODO: num_put can't quite do hex just yet

fmt.setf(ios_base::hex);
fmt.setf(ios_base::hex, ios_base::basefield);
char* last = n.put(data, fmt, ' ', 161);
*last = 0;

//REQUIRE(val == "A1");
// Uppercase not supported yet
REQUIRE(val == "a1");
}
SECTION("left padding")
{
fmt.width(5);
fmt.setf(ios_base::left);

char* last = n.put(data, fmt, '0', 161);
*last = 0;

REQUIRE(val == "00161");
}
}
SECTION("floating point")
Expand Down

0 comments on commit 3aebb69

Please sign in to comment.