/*
 * baseout.cpp: handle all forms of output which ultimately come down
 * to representing a number in ordinary positional notation, with or
 * without a scientific-notation exponent, and with all kinds of
 * top-level formatting (e.g. as a decimal string or an IEEE bit
 * pattern).
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <string>
#include <map>
#include <utility>
#include <sstream>
using std::string;
using std::map;
using std::pair;
using std::ostringstream;

#include "spigot.h"
#include "error.h"
#include "funcs.h"
#include "cr.h"
#include "rmode.h"
#include "baseout.h"

/* ----------------------------------------------------------------------
 * Low-level utility stuff.
 */

char digitchar(int d, char a = 'a')
{
    return (d >= 10 ? a-10 : '0') + d;
}

/*
 * Small helper class to handle intervals of integers, with rigorous
 * attention paid to open/closed endpoints.
 */
class Interval {
  public:
    bigint lo, hi;
    bool lo_open, hi_open;
    bool lo_inf, hi_inf;

    Interval();
    Interval(bigint alo, bigint ahi, bool alo_open, bool ahi_open);
    Interval intersect(const Interval &b) const;
    bool empty() const;
    void translate(bigint origin);
    void scale(bigint scale);
    void remove_lower_bound();
    bool has_lower_bound() const;
};

Interval::Interval()
    : lo(0), hi(0), lo_open(true), hi_open(true),
      lo_inf(false), hi_inf(false)
{
}

Interval::Interval(bigint alo, bigint ahi, bool alo_open, bool ahi_open)
    : lo(alo), hi(ahi), lo_open(alo_open), hi_open(ahi_open),
      lo_inf(false), hi_inf(false)
{
}

Interval Interval::intersect(const Interval &b) const
{
    Interval ret;
    int s;

    s = (lo_inf ?
         (b.lo_inf ? 0 : -1) :
         (b.lo_inf ? +1 : bigint_sign(lo - b.lo)));
    if (s > 0) {
        ret.lo = lo;
        ret.lo_open = lo_open;
        ret.lo_inf = lo_inf;
    } else if (s < 0) {
        ret.lo = b.lo;
        ret.lo_open = b.lo_open;
        ret.lo_inf = b.lo_inf;
    } else {
        ret.lo = b.lo;
        ret.lo_open = lo_open || b.lo_open;
        ret.lo_inf = b.lo_inf;
    }

    s = (hi_inf ?
         (b.hi_inf ? 0 : +1) :
         (b.hi_inf ? -1 : bigint_sign(hi - b.hi)));
    if (s < 0) {
        ret.hi = hi;
        ret.hi_open = hi_open;
        ret.hi_inf = hi_inf;
    } else if (s > 0) {
        ret.hi = b.hi;
        ret.hi_open = b.hi_open;
        ret.hi_inf = b.hi_inf;
    } else {
        ret.hi = b.hi;
        ret.hi_open = hi_open || b.hi_open;
        ret.hi_inf = b.hi_inf;
    }

    return ret;
}

bool Interval::empty() const
{
    return !lo_inf && !hi_inf &&
        (lo > hi || (lo == hi && (lo_open || hi_open)));
}

void Interval::translate(bigint origin)
{
    lo += origin;
    hi += origin;
}

void Interval::scale(bigint scale)
{
    lo *= scale;
    hi *= scale;
}

void Interval::remove_lower_bound()
{
    lo_inf = true;
}

bool Interval::has_lower_bound() const
{
    return !lo_inf;
}

static int floor_log(bigint i, int base, bool *exact)
{
    /*
     * Helper function for deciding on exponents. Returns the integer
     * part (literally, floor) part of the log of i to the base base,
     * which must be 2 or 10. Input must be positive.
     */

    /*
     * We start by finding a rational approximation to 1/log2(base).
     * Since we have spigot available to compute these for us, that's
     * how we do it!
     */
    bigint lognum, logdenom;
    if ((base & (base-1)) == 0) {
        // Special case: base is a power of 2, so its log is an
        // integer.
        lognum = 1;
        logdenom = 0;
        for (int b = base; b > 1; b >>= 1)
            ++logdenom;
    } else {
        // Memoise the approximate logarithm we get, so we can reuse
        // it if called on again to generate output in the same base.
        typedef map<int,pair<bigint,bigint>> our_map_t;
        static our_map_t log2s;
        our_map_t::iterator it = log2s.find(base);

        if (it != log2s.end()) {
            lognum = it->second.first;
            logdenom = it->second.second;
        } else {
            ConvergentsGenerator convs(
                spigot_reciprocal(spigot_log2(spigot_integer(base))));
            while (1) {
                /*
                 * We need to err on the low side, which means taking
                 * only every other convergent. (They oscillate
                 * between erring high and low, starting with the
                 * integer part which is always low.)
                 */
                convs.get_convergent(&lognum, &logdenom);
                if (logdenom > 200)
                    break;
                convs.get_convergent(&lognum, &logdenom);
            }
            log2s[base] = pair<bigint,bigint>(lognum, logdenom);
        }
    }

    assert(i > 0);

    int ret = bigint_approxlog2(i) * lognum / logdenom;
    bigint power = bigint_power(base, ret);
    *exact = (i % power == 0);
    bigint residual = i / power;
    while (residual >= base) {
        if (residual % (unsigned)base != 0)
            *exact = false;
        residual /= base;
        ret++;
    }
    return ret;
}

static RoundingMode signedify(RoundingMode rmode, int sign)
{
    if (sign < 0) {
        return (rmode == ROUND_UP ? ROUND_TOWARD_ZERO :
                rmode == ROUND_DOWN ? ROUND_AWAY_FROM_ZERO :
                rmode == ROUND_TO_NEAREST_UP ?
                ROUND_TO_NEAREST_TOWARD_ZERO :
                rmode == ROUND_TO_NEAREST_DOWN ?
                ROUND_TO_NEAREST_AWAY_FROM_ZERO :
                rmode);
    } else {
        return (rmode == ROUND_UP ? ROUND_AWAY_FROM_ZERO :
                rmode == ROUND_DOWN ? ROUND_TOWARD_ZERO :
                rmode == ROUND_TO_NEAREST_UP ?
                ROUND_TO_NEAREST_AWAY_FROM_ZERO :
                rmode == ROUND_TO_NEAREST_DOWN ?
                ROUND_TO_NEAREST_TOWARD_ZERO :
                rmode);
    }
}

static bool is_directed(RoundingMode rmode)
{
    return (rmode == ROUND_UP ||
            rmode == ROUND_TOWARD_ZERO ||
            rmode == ROUND_DOWN ||
            rmode == ROUND_AWAY_FROM_ZERO);
}

/* ----------------------------------------------------------------------
 * Abstract base class for formatters.
 */

/*
 * 'Formatter' is an abstract base class for things which accept a
 * stream of data in the form (sign, exponent, digit, digit, ...) and
 * turn it into a string.
 *
 * Formatters provide information on the base they want to use (for
 * exponent and digit), and whether they have a digit limit. They
 * receive digits _after_ rounding, so they can concentrate entirely
 * on gluing them into strings.
 */
class Formatter {
    string text;

  protected:
    void write(char c);
    void write(string s);

  public:
    virtual ~Formatter() = default;

    string current_text() const;
    void consume_text(size_t nchars);

    /*
     * Return the desired number bases for exponent / integer part
     * (ebase), and fractional digits (dbase). Both bases must be at
     * least 2, but are otherwise independently configurable.
     *
     * The semantics will be that the exponent will be returned as the
     * largest power of ebase less than or equal to the number, and
     * the first digit returned will be the integer part of the
     * quantity (number * ebase^-exponent). In other words, the first
     * digit can range from 1 to ebase-1; subsequent digits range from
     * 0 to dbase-1.
     *
     * (So if you implement printf("%a") by setting ebase=2 and
     * dbase=16, that gives you output in which the leading digit is
     * always 1. Of course if you wanted the version with the exponent
     * always a multiple of 4 and all leading digits possible, you
     * could do that just as easily by using ebase=16 and quadrupling
     * the received exponent.)
     */
    virtual unsigned ebase() = 0;
    virtual unsigned dbase() = 0;

    /*
     * Indicate whether this formatter has a lower limit on the
     * exponent it can accept. Some will take any exponent; others
     * find it easier to cap the exponent below, so as not to have to
     * faff around with inventing lots of leading zeroes.
     */
    virtual bool has_min_exp() = 0;
    virtual int min_exp() = 0;

    /*
     * Called by the generator to provide the sign and exponent, then
     * the digits. sign_exp() is called once, then digit() repeatedly,
     * and done() once we've finished outputting digits (if we ever
     * do). The argument to done() indicates whether we've stopped
     * outputting digits because the representation in the target base
     * turned out to be exact (in which case we pass 'true') or just
     * because we reached the digit limit ('false').
     */
    virtual void sign_exp(int s, int e) = 0;
    virtual void digit(unsigned d) = 0;
    virtual void done(bool exact) = 0;

    /*
     * Called by the generator in place of sign_exp() and digit(), if
     * an exact zero needs to be formatted.
     *
     * In case it makes a difference, the formatter should respond to
     * this by preparing enough text to use as tentative output
     * representing a potential zero, and to the subsequent done() by
     * appending the rest of the text to make a full and complete
     * output (e.g. a trailing exponent).
     */
    virtual void exact_zero() = 0;

    /*
     * Indicate whether this formatter has a finite number of digits
     * remaining to output. Some can keep going for ever; others
     * impose a limit, at which rounding takes place.
     */
    virtual bool has_digit_limit() = 0;
    virtual unsigned digits_left() = 0;

    /*
     * Indicates whether this formatter has prematurely decided on its
     * entire output. This can happen in the case of IEEE overflow.
     * Default behaviour is to return false (on the basis that _most_
     * subclasses won't need this feature).
     */
    virtual bool complete();

    /*
     * Tweaks which permit the formatter to scale up the first digit,
     * or to round at a partial digit position. Both default to
     * returning 1 (meaning 'don't do either of these unusual things').
     */
    virtual bigint first_digit_scale();
    virtual bigint round_digit_scale();

    /*
     * Formatters constantly have to be copied, because in situations
     * where the input number is taking a while to decide which side
     * of a digit boundary it's on, we run multiple formatters in
     * parallel for the various possibilities.
     */
    virtual unique_ptr<Formatter> copy() = 0;
};

/*
 * CRTP class intermediate between Formatter and its ultimate derived
 * classes, which automatically fills in the copy() method. It has to
 * be CRTPishly templated on the derived class type, so that it knows
 * what to construct a new instance of.
 */
template<typename T>
class FormatterImpl : public Formatter {
    virtual unique_ptr<Formatter> copy() override;
};

template<typename T>
unique_ptr<Formatter> FormatterImpl<T>::copy()
{
    return make_unique<T>(*static_cast<T *>(this));
}

void Formatter::write(char c)
{
    text.push_back(c);
}

void Formatter::write(string s)
{
    text += s;
}

string Formatter::current_text() const
{
    return text;
}

void Formatter::consume_text(size_t nchars)
{
    text.erase(0, nchars);
}

bool Formatter::complete()
{
    return false;
}

bigint Formatter::first_digit_scale()
{
    return 1;
}

bigint Formatter::round_digit_scale()
{
    return 1;
}

/* ----------------------------------------------------------------------
 * The main core of base output.
 */

/*
 * BaseOutputGenerator is the place where the top-level work happens.
 * At one end, this retrieves data from an input spigot by being a
 * subclass of Generator; at the other end, it maintains a number of
 * currently active Formatters with partially constructed strings, and
 * outputs digits whenever they all agree on what comes next. In
 * between, it does sign and exponent finding, and rounding.
 */
class BaseOutputGenerator : public OutputGenerator {
    unique_ptr<Formatter> mainfmt;
    struct CurrFmt {
        /*
         * This structure defines a currently active formatter, and
         * all the things BaseOutputGenerator needs to know to
         * remember how and when to pass it further digits.
         */
        unique_ptr<Formatter> fmt;

        /*
         * The first digit has an unusual range of possibilities, so
         * remember if this is it or not. Also, the range of
         * possibilities depends on whether we're outputting the
         * formatter's minimum exponent (because that's when a leading
         * zero digit is permitted).
         */
        bool at_first_digit, at_min_exp;

        /* How to convert the spigot's current scale to output digits:
         * you compute (value-base)/(2*halfscale). */
        bigint base;
        bigint halfscale;

        /*
         * Record the running parity of the number so far, for RTE/RTO.
         *
         * In an even (digit) base, 'round to even/odd' can be
         * regarded as simply rounding to whichever answer has an even
         * or odd _last digit_. But if the base is odd, that doesn't
         * make sense - e.g. what if you're in base 7, and stuck
         * between outputting a digit 6 or rounding up to 0? _Both_
         * are even, so round-to-even has two choices that it still
         * can't decide between, and round-to-odd has none.
         *
         * The answer is to stop thinking about the last digit, and
         * start thinking about the whole number. Rounding to even/odd
         * should properly be seen as rounding so that the _entire
         * number output_ is an even or odd multiple of the last place
         * value. (In particular, if you're rounding to the nearest
         * _integer_, you want to break ties by picking the even or
         * odd _integer_ out of the options.)
         *
         * In an even base, of course, the two notions are the same.
         * But in an odd base, it means we have to track the parity of
         * the whole number so far, which handily is easy because the
         * parity of a number in an odd base is equal to the parity of
         * the sum of the digits, or the parity of the number of odd
         * digits, or other equivalent formulations including the
         * parity of the XOR of the digits.
         *
         * 'parity' does this tracking, as we step along the number.
         * Only its low bit is meaningful.
         */
        unsigned parity;

        /*
         * 'done' is true if this formatter has output its rounding
         * digit and hence finished. In that situation, 'base' always
         * points at the rounding boundary separating us from the
         * other formatter, and the other two booleans here indicate
         * which side of that boundary this formatter expects to be
         * on, and whether an exact tie counts as valid.
         */
        bool done;
        bool round_down;        // if true, we expect to be < base
        bool round_open;        // if false, = counts as the right side

        /*
         * Remember what exponent this formatter started off with, and
         * whether either end of its interval is an exponent boundary,
         * so that we can recognise the case later on when a rounding
         * decision is being made between two numbers of different
         * exponents.
         */
        int exponent;
        bool just_below_exponent_boundary, just_above_exponent_boundary;

        int digits_since_done;
    } currfmts[2], newfmts[2];
    int n_currfmts;
    unsigned ebase, dbase;
    bool has_min_exp;
    int min_exp;
    RoundingMode rmode;
    bool exponent_finding_phase;
    bool done;
    int crState;                 // for coroutine-structured progress()
    int sign, exponent;
    int scale;
    bool force_refine;
    void dump_formatters(const char *prefix);
  private:
    int compute_exponent(int sign, int eadj, const bigint &i,
                         bool add_epsilon, bool maximum);
    void progress();
    virtual bool get_definite_output(string &out) override;
    virtual bool get_tentative_output(string &out, int *digits) override;
  public:
    BaseOutputGenerator(Spigot acore, unique_ptr<Formatter> fmt,
                        RoundingMode armode);
};

MAKE_CLASS_GREETER(BaseOutputGenerator);

BaseOutputGenerator::BaseOutputGenerator(Spigot acore,
                                         unique_ptr<Formatter> fmt,
                                         RoundingMode armode)
    : OutputGenerator(move(acore)),
      mainfmt(move(fmt)),
      n_currfmts(0),
      rmode(armode),
      exponent_finding_phase(true),
      done(false),
      crState(-1)
{
    dgreet(core->dbg_id());
}

void BaseOutputGenerator::dump_formatters(const char *prefix)
{
    if (!debugging)
        return;

    for (int i = 0; i < n_currfmts; ++i) {
        auto &fmt = currfmts[i];

        if (fmt.done) {
            dprint(prefix, ": formatter ", i, ": done base=", fmt.base,
                   ", rdown=", fmt.round_down, " ropen=", fmt.round_open,
                   " \"", fmt.fmt->current_text(), "\"");
        } else {
            dprint(prefix, ": formatter ", i,
                   ": base=", fmt.base, " scale=2*", fmt.halfscale,
                   " parity=", currfmts[i].parity & 1,
                   " \"", fmt.fmt->current_text(), "\" "
                   "(", fmt.fmt->digits_left(), " digits)");
        }
    }
}

int BaseOutputGenerator::compute_exponent(int sign, int eadj, const bigint &i,
                                          bool add_epsilon, bool maximum)
{
    assert(i >= 0);
    bool exact;
    int e = floor_log(i, ebase, &exact);

    if (exact) {
        /*
         * If the number is an _exact_ power of ebase, then there is
         * only one possible exponent for it, irrespective of rounding.
         */
        if (!add_epsilon)
            return e;

        /*
         * If the number is epsilon less than an exact power of ebase,
         * then we should consider its exponent to be one lower.
         */
        if (maximum)
            e--;
    }

    bool special_case = false;
    RoundingMode real_rmode = signedify(rmode, sign);
    if (ebase == 2 && is_directed(real_rmode)) {
        unique_ptr<Formatter> fmt = mainfmt->copy();
        if (!(fmt->has_min_exp() && eadj + e < fmt->min_exp())) {
            fmt->sign_exp(sign, eadj + e);
            special_case = (fmt->has_digit_limit() && fmt->digits_left() == 1);
        }
    }
    if (special_case) {
        return real_rmode == ROUND_TOWARD_ZERO ? e : e+1;
    }

    if (maximum) {
        bigint threshold = bigint_power(ebase, e+1);
        if (dbase > 2) {
            threshold = fdiv(threshold * (dbase-1), dbase);
        } else {
            threshold = fdiv(threshold * 3, 4);
        }
        if (i >= threshold) {
            e++;
        }
    }

    return e;
}

void BaseOutputGenerator::progress() {
    bigint lo, hi;

    crBegin;

    ebase = mainfmt->ebase();
    dbase = mainfmt->dbase();
    has_min_exp = mainfmt->has_min_exp();
    min_exp = mainfmt->min_exp();

    dprint("ebase=", ebase, " dbase=", dbase);
    if (has_min_exp)
        dprint("min_exp=", min_exp);
    else
        dprint("no min_exp");

    /*
     * Start by determining the sign and exponent, which we do by
     * iterating the input spigot until the two ends of its interval
     * have the same sign and differ by at most a factor of ebase.
     *
     * While we do this, we arrange for a formatter to be active and
     * contain an exact representation of zero, so that that can be
     * used as tentative output if the exponent search drags on.
     */
    n_currfmts = 1;
    currfmts[0].fmt = mainfmt->copy();
    currfmts[0].fmt->exact_zero();
    currfmts[0].fmt->done(true);

    exponent = 0;
    force_refine = false;
    while (1) {
        bool lo_open, hi_open;
        iterate_to_bounds(&lo, &hi, &lo_open, &hi_open, 0, nullptr, force_refine);

        dprint("exponent-finding: got (", lo, ",", hi, ")");

        if (hi > 0 && (lo > 0 || (lo == 0 && lo_open))) {
            /*
             * The number is definitely positive. Do we know its
             * exponent well enough?
             */
            int e_max = compute_exponent(+1, exponent, hi, hi_open, true);
            if (has_min_exp && e_max + exponent <= min_exp) {
                /*
                 * If we're running in a mode that imposes a lower
                 * limit on the output exponent, and the _largest_
                 * exponent the number might have is that lower-bound
                 * value, then we know we must output the lower-bound
                 * value without having to check anything else.
                 */
                sign = +1;
                scale = min_exp - exponent;
                dprint("positive, scale=", scale, " (min exp)");
                break;
            }
            if (lo > 0) {
                int e_min = compute_exponent(+1, exponent, lo, lo_open, false);
                if (e_max - e_min <= 1) {
                    /*
                     * Otherwise, if we've narrowed the range to the
                     * point where the range of possible output
                     * exponents contains at most two values, then
                     * that's enough to terminate this loop. (We may
                     * have to get all the way to the rounding stage
                     * before finding out _which_ output exponent we
                     * use, if the number is very close to an integer
                     * power of ebase.)
                     */
                    sign = +1;
                    scale = e_max;
                    dprint("positive, scale=", scale);
                    break;
                };
            }
        } else if (lo < 0 && (hi < 0 || (hi == 0 && hi_open))) {
            /*
             * Same cases as the previous branch, but for a number
             * that's definitely _negative_ rather than positive.
             */
            int e_max = compute_exponent(-1, exponent, -lo, lo_open, true);
            if (has_min_exp && e_max + exponent <= min_exp) {
                sign = -1;
                scale = min_exp - exponent;
                dprint("negative, scale=", scale, " (min exp)");
                break;
            }
            if (hi < 0) {
                int e_min = compute_exponent(
                    -1, exponent, -hi, hi_open, false);
                if (e_max - e_min <= 1) {
                    sign = -1;
                    scale = e_max;
                    dprint("negative, scale=", scale);
                    break;
                };
            }
        } else if (hi == 0 && lo == 0) {
            /*
             * The number is exactly zero, so the temporary formatter
             * we set up for that possibility has in fact got the
             * right answer already, so just leave it there and finish.
             */
            dprint("exact zero");
            exponent_finding_phase = false;
            done = true;
            crReturnV;
            assert(!"Called again after completing an exact zero");
        }

        /*
         * If we haven't exited the loop in any of the above cases,
         * then we don't yet have enough information. We need to
         * narrow the interval further.
         */

        if (hi - lo <= 2) {
            /*
             * If the interval has narrowed as far as we can
             * reasonably expect it to at this scale of magnification,
             * and we _still_ haven't exited the loop via any of the
             * above cases, then the exponent is probably too small to
             * see at this resolution (or else the number is
             * _non-obviously_ zero). Premultiply a matrix that zooms
             * in, remember that we've done so, and keep trying.
             */
            Matrix matrix = { ebase, 0, 0, 1 };
            dprint("premultiplying exponent-finding zoom ", matrix);
            core->premultiply(matrix);
            exponent--;
            dprint("zoomed in, decremented exponent to ", exponent);
            force_refine = false;
        } else {
            /*
             * Otherwise, we need more information from the source
             * spigot.
             */
            force_refine = true;
        }

        /*
         * Return from the coroutine every time we go round this loop,
         * so that we're conveniently interruptible.
         */
        crReturnV;
    }

    dprint("exponent found: exponent=", exponent, " scale=", scale,
           " sign=", sign);
    if (has_min_exp && exponent + scale < min_exp) {
        scale = min_exp - exponent;
        dprint("adjusted for min exp ", min_exp, ": exponent=", exponent,
               " scale=", scale, " sign=", sign);
    }

    /*
     * Do sign-dependent processing, now we know the sign: translate
     * signed roundings (towards +inf or -inf) into sign-independent
     * ones (towards or away from zero), and premultiply a negation
     * matrix if the number is negative.
     */
    if (sign < 0) {
        static const Matrix matrix = { -1, 0, 0, 1 };
        dprint("premultiplying negation ", matrix);
        core->premultiply(matrix);
    }
    rmode = signedify(rmode, sign);

    /*
     * Discard our temporary zero formatter.
     */
    currfmts[0].fmt = nullptr;
    exponent_finding_phase = false;

    /*
     * Find the overall exponent, by combining the log of the
     * integer-part interval we got back with the number of times
     * we've already zoomed in.
     */
    exponent += (int)scale;
    dprint("final exponent=", exponent);

    /*
     * If the integer part was large, start by zooming back out. Also
     * zoom if we need to scale up the first digit.
     */
    {
        Matrix matrix = {
            mainfmt->first_digit_scale(), 0,
            0, bigint_power(ebase, scale),
        };
        if (matrix[0] != matrix[3]) {
            dprint("premultiplying initial zoom ", matrix);
            core->premultiply(matrix);
        }
    }

    /*
     * We've now zoomed the spigot so that ebase^exponent in the scale
     * of the output number is represented by 1 here. But we're going
     * to worry about the exponent one below that, so we must zoom in
     * by ebase again; also we zoom in by an extra factor of 2 so that
     * we can get intervals at half-digit granularity.
     */
    {
        Matrix matrix = { ebase*2, 0, 0, 1 };
        dprint("premultiplying pre-main-loop zoom ", matrix);
        core->premultiply(matrix);
    }

    /*
     * Now we know the number's sign, and we've got its exponent to
     * within a range of two possibilities. Begin our main loop by
     * initialising one formatter to each of the exponent choices.
     *
     * Our formatters are in sorted order always, from smallest to
     * largest.
     */
    n_currfmts = 0;

    if (!has_min_exp || exponent > min_exp) { // omit this exponent if too low
        currfmts[n_currfmts].fmt = mainfmt->copy();
        currfmts[n_currfmts].done = false;
        currfmts[n_currfmts].fmt->sign_exp(sign, exponent - 1);
        currfmts[n_currfmts].base = 0;
        currfmts[n_currfmts].halfscale = 1;
        currfmts[n_currfmts].parity = 0;
        currfmts[n_currfmts].at_first_digit = true;
        currfmts[n_currfmts].at_min_exp = (has_min_exp &&
                                           exponent-1 == min_exp);
        currfmts[n_currfmts].exponent = exponent - 1;
        currfmts[n_currfmts].just_below_exponent_boundary = true;
        currfmts[n_currfmts].just_above_exponent_boundary = false;
        currfmts[n_currfmts].digits_since_done = 0;
        n_currfmts++;
    }

    currfmts[n_currfmts].fmt = mainfmt->copy();
    currfmts[n_currfmts].done = false;
    currfmts[n_currfmts].fmt->sign_exp(sign, exponent);
    currfmts[n_currfmts].base = 0;
    currfmts[n_currfmts].halfscale = ebase;
    currfmts[n_currfmts].parity = 0;
    currfmts[n_currfmts].at_first_digit = true;
    currfmts[n_currfmts].at_min_exp = (has_min_exp &&
                                       exponent == min_exp);
    currfmts[n_currfmts].exponent = exponent;
    currfmts[n_currfmts].just_below_exponent_boundary = false;
    currfmts[n_currfmts].just_above_exponent_boundary = (n_currfmts > 0);
    currfmts[n_currfmts].digits_since_done = 0;
    n_currfmts++;

    while (1) {
        dump_formatters("digit loop");

        /*
         * Fetch enough data to narrow down to the next digit
         * position, no matter which formatter's scale we're working
         * at.
         */
        bool lo_open, hi_open;
        force_refine = false;

        {
            assert(n_currfmts > 0);
            bigint min_halfscale = currfmts[0].halfscale;
            if (n_currfmts > 1 && min_halfscale > currfmts[1].halfscale)
                min_halfscale = currfmts[1].halfscale;

            while (1) {
                iterate_to_bounds(&lo, &hi, &lo_open, &hi_open, 0, nullptr,
                                  force_refine);
                /*
                 * We make the termination condition of this loop as
                 * carefully loose as possible, to get the maximum
                 * output in cases where limited data is available
                 * (e.g. FileReaders).
                 *
                 * We need our interval to overlap at most two
                 * possible digits' catchment areas. For this, it has
                 * to be contained in either a closed interval between
                 * two exact digit boundaries (which are at least
                 * 2*min_halfscale apart), or a closed interval
                 * between two points exactly midway between digit
                 * boundaries. That will get us what we want
                 * regardless of the rounding mode.
                 *
                 * Also, we don't want it to be the full width of one
                 * of those intervals _and_ be closed at both ends.
                 * (Because that raises the possibility that we might
                 * manage to overlap three digit catchment intervals,
                 * in the case where each endpoint of the width-2
                 * closed interval would round-to-even outwards.)
                 */
                bigint tmp_lo = fdiv(lo, min_halfscale);
                bool tmp_lo_open = lo_open || (tmp_lo * min_halfscale != lo);
                bigint tmp_hi = fdiv(hi + min_halfscale-1, min_halfscale);
                bool tmp_hi_open = hi_open || (tmp_hi * min_halfscale != hi);

                int s = bigint_sign(tmp_hi - tmp_lo - 2);
                if (s < 0 || (s == 0 && (tmp_lo_open || tmp_hi_open)))
                    break;
                force_refine = true;
            }
        }

        dprint("digit loop: got ",
               lo_open?"(":"[", lo, ",", hi, hi_open?")":"]");

        /*
         * Iterate over all active formatters, and see what each one
         * makes of this new piece of data.
         */
        int n_newfmts;
        n_newfmts = 0;
        for (int i = 0; i < n_currfmts; ++i) {
            CurrFmt &cfmt = currfmts[i];

            if (cfmt.done) {
                /*
                 * This formatter is a static entry in the list
                 * representing a successfully rounded output. Check
                 * whether the number has been shown to be on the
                 * wrong side of the rounding boundary; if so, discard
                 * this formatter, and otherwise, just propagate it
                 * into the newfmts list without change.
                 */
                int sign;
                bool open;

                bigint base;
                if (i > 0 && cfmt.just_above_exponent_boundary) {
                    base = currfmts[i-1].base;
                } else {
                    base = cfmt.base;
                }

                if (cfmt.round_down) {
                    sign = bigint_sign(lo - base);
                    open = lo_open;
                } else {
                    sign = bigint_sign(base - hi);
                    open = hi_open;
                }
                dprint("check done formatter ", i, ", sign=", sign);
                if (sign < 0 || (sign == 0 && !cfmt.round_open && !open)) {
                    cfmt.digits_since_done++;
                    newfmts[n_newfmts++] = move(cfmt);
                }
                continue;
            }

            bool rounding = (cfmt.fmt->has_digit_limit() &&
                             cfmt.fmt->digits_left() == 1);

            bigint this_scale = cfmt.halfscale;
            bigint digit_scale = 1;
            if (rounding) {
                digit_scale = cfmt.fmt->round_digit_scale();
                this_scale *= digit_scale;
                dprint("rounding this digit with scale ", digit_scale);
            } else {
                dprint("not rounding this digit");
            }

            bigint this_lo = fdiv(lo - cfmt.base, this_scale);
            bool this_lo_open = lo_open || (this_lo * this_scale != lo - cfmt.base);
            bigint this_hi = fdiv(hi - cfmt.base + this_scale-1,
                                  this_scale);
            bool this_hi_open = hi_open || (this_hi * this_scale != hi - cfmt.base);

            /*
             * If there's any possibility of this number being rounded
             * up to slightly more than its current value at a later
             * digit position, then we must presume that it could
             * round up to the high end of our current interval, i.e.
             * we must treat the interval as closed at the top end for
             * the purposes of this formatter.
             *
             * Rounding up is a possibility if we're not in
             * round-toward-zero mode, and have a nonzero digit limit
             * which we haven't yet reached.
             */
            if (rmode != ROUND_TOWARD_ZERO &&
                cfmt.fmt->has_digit_limit() &&
                cfmt.fmt->digits_left() > 1)
                this_hi_open = false;

            Interval curr_int(this_lo, this_hi, this_lo_open, this_hi_open);
            dprint("formatter ", i, ": scaled interval ",
                   this_lo_open?"(":"[", this_lo, ",",
                   this_hi, this_hi_open?")":"]");

            /*
             * If the interval we're now sitting on is _exactly_ zero,
             * then we've output all the digits of a terminating base
             * representation, and we should notify the formatter.
             */
            if (this_lo == 0 && this_hi == 0) {
                dprint("formatter ", i, ": marking as exact");
                cfmt.done = true;
                cfmt.digits_since_done = 0;
                cfmt.round_open = false;
                cfmt.round_down = true;
                cfmt.fmt->done(true);
                newfmts[n_newfmts++] = move(cfmt);
                continue;
            }

            /*
             * Enumerate the possible next digits that might go to
             * this formatter, based on the number's interval.
             */
            bigint dmin = this_lo / 2U, dmax = (this_hi + 1) / 2U;
            bool potentially_still_above_exponent_boundary = false;
            bool potentially_still_below_exponent_boundary = false;

            unsigned this_dbase;

            if (cfmt.at_first_digit) {
                bigint first_digit_scale =
                    cfmt.fmt->first_digit_scale() / digit_scale;
                bigint first_digit_min = (cfmt.at_min_exp ? 0_bi :
                                          first_digit_scale);
                bigint first_digit_max = ebase * first_digit_scale;
                if (dmax >= first_digit_max)
                    dmax = first_digit_max - 1;
                if (dmin < first_digit_min)
                    dmin = first_digit_min;
                if (cfmt.just_above_exponent_boundary &&
                    !cfmt.at_min_exp && dmin == first_digit_scale)
                    potentially_still_above_exponent_boundary = true;
                if (cfmt.just_below_exponent_boundary &&
                    dmax == first_digit_max - 1)
                    potentially_still_below_exponent_boundary = true;
                this_dbase = ebase * first_digit_scale;
            } else {
                bigint scaled_dbase = bigint(dbase) / digit_scale;
                if (dmax >= scaled_dbase)
                    dmax = scaled_dbase - 1;
                if (dmin < 0)
                    dmin = 0;
                if (cfmt.just_above_exponent_boundary &&
                    !cfmt.at_min_exp && dmin == 0)
                    potentially_still_above_exponent_boundary = true;
                if (cfmt.just_below_exponent_boundary &&
                    dmax == scaled_dbase - 1)
                    potentially_still_below_exponent_boundary = true;
                this_dbase = dbase;
            }

            dprint("formatter ", i, ": digit range [", dmin, ",", dmax, "]");

            for (bigint d = dmin; d <= dmax; ++d) {
                assert(d >= 0);
                assert(d < bigint(this_dbase));
                /*
                 * Determine the catchment interval for this digit.
                 * Usually this is just [d,d+1), unless we're at the
                 * rounding point right now, in which case the shape
                 * of the catchment interval varies a lot depending on
                 * rounding mode.
                 */
                Interval catchment;
                if (!rounding || rmode == ROUND_TOWARD_ZERO) {
                    catchment = { d*2, d*2+2, false, true };
                } else if (rmode == ROUND_AWAY_FROM_ZERO) {
                    catchment = { d*2-2, d*2, true, false };
                } else {
                    bool cmin_open, cmax_open;
                    switch (rmode) {
                      case ROUND_TO_NEAREST_EVEN:
                        /*
                         * If the number is the last digit of an even
                         * multiple of this place value, its catchment
                         * interval is closed at both ends, otherwise
                         * it's open at both ends.
                         */
                        cmin_open = cmax_open =
                            (((unsigned)d ^ cfmt.parity) & 1) != 0;
                        break;
                      case ROUND_TO_NEAREST_ODD:
                        /*
                         * Exact reverse of ROUND_TO_NEAREST_EVEN, of
                         * course.
                         */
                        cmin_open = cmax_open =
                            (((unsigned)d ^ cfmt.parity) & 1) == 0;
                        break;
                      case ROUND_TO_NEAREST_TOWARD_ZERO:
                        cmin_open = true;
                        cmax_open = false;
                        break;
                      default /*case ROUND_TO_NEAREST_AWAY_FROM_ZERO */ :
                        cmin_open = false;
                        cmax_open = true;
                        break;
                    }
                    catchment = { d*2-1, d*2+1, cmin_open, cmax_open };
                }

                /*
                 * If this formatter is just above an exponent
                 * boundary, and there's one recorded just below it
                 * which is just below the same boundary, then we
                 * discard the lower bound on this catchment area,
                 * because only the next formatter down can correctly
                 * compute the rounding boundary between exponents.
                 */
                if (potentially_still_above_exponent_boundary && d == dmin &&
                    n_newfmts > 0 &&
                    newfmts[n_newfmts-1].just_below_exponent_boundary)
                    catchment.remove_lower_bound();

                if (rounding) {
                    if (catchment.has_lower_bound()) {
                        dprint("catchment interval for digit ", d, ": ",
                               catchment.lo_open?"(":"[",
                               catchment.lo, ",",
                               catchment.hi,
                               catchment.hi_open?")":"]");
                    } else {
                        dprint("catchment interval for digit ", d, ": (-inf,",
                               catchment.hi,
                               catchment.hi_open?")":"]");
                    }
                }

                /*
                 * Intersect, and if the resulting interval is
                 * non-empty, create a new formatter for the next
                 * digit which has the right parameters.
                 */
                Interval out = curr_int.intersect(catchment);
                if (!out.empty()) {
                    /*
                     * Special case: there's one situation in which we
                     * might find ourselves attempting to produce a
                     * third formatter, which is if we've just crossed
                     * an exponent boundary and the lower-exponent
                     * formatter had two possibilities already.
                     *
                     * In that situation, we discard the current
                     * option: it's only included due to unwillingness
                     * to trust the lower bound of a formatter just
                     * above an exponent boundary, and the fact that
                     * the next formatter down is still considering a
                     * digit lower than 9 (or more generally dmax) is
                     * enough to show that we can't really be in this
                     * exponent's catchment area.
                     */
                    if (n_newfmts == 2 &&
                        potentially_still_above_exponent_boundary &&
                        d == dmin &&
                        newfmts[n_newfmts-1].exponent != cfmt.exponent) {
                        dprint("formatter ", i, ": would output digit ", d,
                               ", but deferring to lower exponent");
                        continue;
                    }

                    dprint("formatter ", i, ": output digit ", d);

                    assert(n_newfmts < 2);

                    CurrFmt &newfmt = newfmts[n_newfmts];
                    n_newfmts++;

                    newfmt.fmt = cfmt.fmt->copy();
                    newfmt.fmt->digit(d * digit_scale);
                    newfmt.at_first_digit = false;
                    newfmt.exponent = cfmt.exponent;
                    newfmt.just_above_exponent_boundary =
                        potentially_still_above_exponent_boundary && d == dmin;
                    newfmt.just_below_exponent_boundary =
                        potentially_still_below_exponent_boundary && d == dmax;
                    newfmt.at_min_exp = cfmt.at_min_exp;

                    if (rounding) {
                        /*
                         * This formatter is now 'done', meaning that
                         * we've sent it all the digits we're going
                         * to. However, that's conditional on the
                         * number turning out to be in the right
                         * interval for this formatter after all - in
                         * some cases we can have two formatters in
                         * the done state, representing what will be
                         * output if the number ends up rounded down
                         * and up respectively, and then we have to
                         * keep processing until we find out which one
                         * is out of range, at which point we discard
                         * it and return just the other one.
                         */
                        newfmt.done = true;
                        newfmt.digits_since_done = 0;
                        newfmt.fmt->done(false);
                        if (n_newfmts == 1) {
                            newfmt.base = catchment.hi * this_scale + cfmt.base;
                            newfmt.round_down = true;
                            newfmt.round_open = catchment.hi_open;
                        } else {
                            newfmt.base = catchment.lo * this_scale + cfmt.base;
                            newfmt.round_down = false;
                            newfmt.round_open = catchment.lo_open;
                        }
                        newfmt.halfscale = cfmt.halfscale;
                    } else {
                        newfmt.done = false;
                        newfmt.base = cfmt.base + d*2*cfmt.halfscale;
                        newfmt.halfscale = cfmt.halfscale;
                        /* Fold the just-generated digit in to 'parity',
                         * if we're in an odd base; keep parity set to
                         * even, in an even base. Bit-twiddling to do
                         * this without any serious arithmetic. */
                        newfmt.parity = cfmt.parity ^ ((unsigned)d & this_dbase);
                    }
                }

                /*
                 * Loop on to the next possible digit.
                 */
            }
        }

        /*
         * Replace the old set of live formatters with the new set.
         */
        for (n_currfmts = 0; n_currfmts < n_newfmts; n_currfmts++)
            currfmts[n_currfmts] = move(newfmts[n_currfmts]);

        assert(n_currfmts > 0);

        /*
         * End condition: if all formatters are done and have the same
         * string in them, we really have finished. (Usually this
         * occurs because there's only one formatter left, but in the
         * special case of IEEE overflow we can find we have two
         * formatters marked as done and agreeing on all their text
         * despite not having even figured out which of their
         * exponents is live yet.)
         */
        done = true;
        for (int i = 0; i < n_currfmts; ++i) {
            if (!currfmts[i].done && !currfmts[i].fmt->complete()) {
                done = false;
                break;
            }
        }
        if (done) {
            for (int i = 1; i < n_currfmts; ++i) {
                if (currfmts[0].fmt->current_text() !=
                    currfmts[i].fmt->current_text()) {
                    done = false;
                    break;
                }
            }
        }

        if (done) {
            crReturnV;
            assert(!"Called again after finishing output");
        }

        /*
         * Premultiply in a translation and scaling matrix, and scale
         * up all the formatters' intervals and bases.
         */
        {
            bigint newbase = currfmts[0].base;

            for (int i = 0; i < n_currfmts; ++i) {
                CurrFmt &cfmt = currfmts[i];
                cfmt.base = (cfmt.base - newbase) * dbase;
            }

            Matrix matrix = { dbase, -newbase * dbase, 0, 1 };
            dprint("premultiplying post-digit zoom ", matrix);
            core->premultiply(matrix);
        }

        crReturnV;
    }

    crEnd;
}

bool BaseOutputGenerator::get_definite_output(string &out)
{
    if (done)
        return false;

    progress();
    assert(n_currfmts > 0);

    dump_formatters("output check");

    if (exponent_finding_phase) {
        /*
         * Special case: during exponent-finding, we only have one
         * CurrFmt active and yet we never generate definite output.
         */
        out = "";
        dprint("no output available");
        return true;
    } else if (n_currfmts == 1) {
        /*
         * If there's only one formatter live, then everything it's
         * produced is the only possible option and hence definite
         * output.
         */
        out = currfmts[0].fmt->current_text();
        dprint("unilateral \"", out, "\"");
        currfmts[0].fmt->consume_text(out.size());
        return true;
    } else {
        /*
         * With two formatters, we can only output what they agree on.
         */
        assert(n_currfmts == 2);
        string out0 = currfmts[0].fmt->current_text();
        string out1 = currfmts[1].fmt->current_text();
        size_t len = 0;
        while (len < out0.size() && len < out1.size() && out0[len] == out1[len])
            ++len;
        out = out0.substr(0, len);
        dprint("bilateral \"", out, "\"");
        currfmts[0].fmt->consume_text(len);
        currfmts[1].fmt->consume_text(len);
        return true;
    }
}

bool BaseOutputGenerator::get_tentative_output(string &out, int *digits)
{
    if (done)
        return false;

    if (exponent_finding_phase) {
        /*
         * Special case: during exponent-finding, we have exactly one
         * CurrFmt active and its output is all tentative.
         */
        assert(n_currfmts == 1);
        out = currfmts[0].fmt->current_text();
        char buf[256];
        sprintf(buf, " (%u^%d)", ebase, exponent);
        *digits = -exponent;
        out += buf;
        return true;
    } else if (n_currfmts == 2) {
        /*
         * Multiple live formatters are precisely the condition under
         * which we generate tentative output.
         *
         * If we haven't rounded yet, then the upper one of the two
         * formatters must contain what the answer might turn out to
         * exactly be; if we have, then we pick whichever formatter
         * has its rounding boundary closed.
         */
        int which, zeroes = 0;
        for (which = 0; which < 2; ++which)
            if (currfmts[which].done && !currfmts[which].round_open) {
                zeroes = currfmts[which].digits_since_done;
                break;                 // found a closed done formatter
            }
        if (which == 2)
            which = 1;                 // otherwise just go with #1
        out = currfmts[which].fmt->current_text();

        size_t last_nonzero = out.size();
        /*
         * Trim trailing zeroes from the upper formatter, and count
         * them, to use as our accuracy indicator.
         */
        while (last_nonzero > 0 && out[last_nonzero-1] == '0')
            last_nonzero--;
        zeroes += out.size() - last_nonzero;
        /*
         * Also trim a decimal point, if that's now the last thing in
         * the string, because it's ugly to print it unnecessarily.
         */
        if (last_nonzero > 0 && out[last_nonzero-1] == '.')
            last_nonzero--;
        out.resize(last_nonzero);
        char buf[256];
        sprintf(buf, " (%u^-%d)", dbase, zeroes);
        *digits = zeroes;
        out += buf;

        return true;
    } else {
        return false;
    }
}

/* ----------------------------------------------------------------------
 * Formatter for spigot's default output mode: just plain positional
 * notation, with a point if necessary but no exponent.
 */

class BaseFormatter : public FormatterImpl<BaseFormatter> {
    unsigned base;
    char a;                            // either 'a' or 'A'
    bool started, written_point;
    int our_min_exp;
    unsigned int_digits;
    unsigned min_int_digits;
    bool has_dlimit;
    unsigned digits;

    virtual unsigned ebase() override;
    virtual unsigned dbase() override;
    virtual bool has_min_exp() override;
    virtual int min_exp() override;
    virtual void sign_exp(int s, int e) override;
    virtual void digit(unsigned d) override;
    virtual void done(bool) override;
    virtual void exact_zero() override;
    virtual bool has_digit_limit() override;
    virtual unsigned digits_left() override;

  public:
    BaseFormatter(int abase, char aa, bool ahas_dlimit,
                  unsigned adigits, unsigned amin_int_digits);
};

BaseFormatter::BaseFormatter(int abase, char aa, bool ahas_dlimit,
                             unsigned adigits, unsigned amin_int_digits)
{
    base = abase;
    a = aa;
    started = written_point = false;
    int_digits = 0;
    has_dlimit = ahas_dlimit;
    digits = adigits;
    min_int_digits = amin_int_digits;
    if (min_int_digits < 1)
        min_int_digits = 1;

    /*
     * Minimum exponent: if we've been asked for a minimum number of
     * integer digits, the easiest way to achieve that is by
     * increasing the minimum exponent. Also, if we're rounding to a
     * position above the decimal point, that too is most easily
     * achieved by increasing the min exp.
     */
    our_min_exp = 0;
    if (our_min_exp < (int)min_int_digits-1)
        our_min_exp = (int)min_int_digits-1;
    if (has_dlimit && our_min_exp < -(int)digits)
        our_min_exp = -(int)digits;
}

unsigned BaseFormatter::ebase()
{
    return base;
}

unsigned BaseFormatter::dbase()
{
    return base;
}

bool BaseFormatter::has_min_exp()
{
    return true;
}

int BaseFormatter::min_exp()
{
    return our_min_exp;
}

void BaseFormatter::sign_exp(int s, int e)
{
    if (s < 0)
        write('-');

    int_digits = e+1;
    digits += int_digits;
}

void BaseFormatter::digit(unsigned d)
{
    // Skip this digit if it's a leading zero that we don't want
    if (started || int_digits <= min_int_digits || d != 0) {
        started = true;
        if (!written_point && int_digits == 0) {
            write('.');
            written_point = true;
        }
        write(digitchar(d, a));
    }
    if (int_digits > 0)
        --int_digits;
    --digits;
}

void BaseFormatter::done(bool)
{
    while (int_digits > 0)
        digit(0);
}

void BaseFormatter::exact_zero()
{
    sign_exp(0, our_min_exp);
    digit(0);
}

bool BaseFormatter::has_digit_limit()
{
    return has_dlimit;
}

unsigned BaseFormatter::digits_left()
{
    return digits;
}

unique_ptr<OutputGenerator> base_format(
    Spigot spig, int base, int uppercase,
    bool has_digitlimit, int digitlimit, RoundingMode rmode, int minintdigits)
{
    return make_unique<BaseOutputGenerator>
        (move(spig), make_unique<BaseFormatter>(base, uppercase?'A':'a',
                                                has_digitlimit, digitlimit,
                                                minintdigits), rmode);
}

/* ----------------------------------------------------------------------
 * Formatter for 'reversed scientific notation' output, _starting_
 * with an exponent (because it's the most significant part, that you
 * can determine first) and then giving the mantissa.
 */

class RevSciFormatter : public FormatterImpl<RevSciFormatter> {
    unsigned expbase, digitbase;
    char a;                            // either 'a' or 'A'
    int digit_index;                   // saturates at 2
    bool has_dlimit;
    unsigned digits;

    virtual unsigned ebase() override;
    virtual unsigned dbase() override;
    virtual bool has_min_exp() override;
    virtual int min_exp() override;
    virtual void sign_exp(int s, int e) override;
    virtual void digit(unsigned d) override;
    virtual void done(bool) override;
    virtual void exact_zero() override;
    virtual bool has_digit_limit() override;
    virtual unsigned digits_left() override;

  public:
    RevSciFormatter(int aexpbase, int adigitbase, char aa,
                    bool ahas_dlimit, unsigned adigits);
};

RevSciFormatter::RevSciFormatter(int aexpbase, int adigitbase, char aa,
                                 bool ahas_dlimit, unsigned adigits)
{
    expbase = aexpbase;
    digitbase = adigitbase;
    a = aa;
    digit_index = 0;
    has_dlimit = ahas_dlimit;
    digits = adigits;
}

unsigned RevSciFormatter::ebase()
{
    return expbase;
}

unsigned RevSciFormatter::dbase()
{
    return digitbase;
}

bool RevSciFormatter::has_min_exp()
{
    return false;
}

int RevSciFormatter::min_exp()
{
    return 0;
}

void RevSciFormatter::sign_exp(int s, int e)
{
    write(bigint_decstring(expbase) + "^" + bigint_decstring(e) +
          " * ");
    if (s < 0)
        write('-');
}

void RevSciFormatter::digit(unsigned d)
{
    if (digit_index == 0) {
        /*
         * The first output digit can go up to ebase, not
         * dbase. So we must format it into the output digit
         * base ourselves.
         */
        ostringstream os;
        do {
            os << digitchar(d % digitbase, a);
            d /= digitbase;
        } while (d != 0);

        const string &s = os.str();
        for (auto rit = s.rbegin(); rit != s.rend(); ++rit)
            write(*rit);

        digit_index++;
    } else {
        if (digit_index == 1) {
            write('.');
            digit_index++;
        }
        write(digitchar(d, a));
        --digits;
    }
}

void RevSciFormatter::done(bool)
{
}

void RevSciFormatter::exact_zero()
{
    sign_exp(0, 0);
    digit(0);
}

bool RevSciFormatter::has_digit_limit()
{
    return has_dlimit;
}

unsigned RevSciFormatter::digits_left()
{
    return digits;
}

unique_ptr<OutputGenerator> revsci_format(
    Spigot spig, int expbase, int digitbase, int uppercase,
    bool has_digitlimit, int digitlimit, RoundingMode rmode)
{
    return make_unique<BaseOutputGenerator>
        (move(spig), make_unique<RevSciFormatter>(
            expbase, digitbase, uppercase?'A':'a',
            has_digitlimit, digitlimit), rmode);
}

/* ----------------------------------------------------------------------
 * Formatter for hex bit patterns of IEEE 754-style floats, with
 * optional extra exponent digits.
 */

class IEEEFormatter : public FormatterImpl<IEEEFormatter> {
    int expscale, signexpdigits;
    int mantdigits_left;
    unsigned expbias;
    int last_expdigit;
    bool seen_first_digit;
    bool has_dlimit;
    unsigned digits;
    unsigned roundscale;
    bool overflow;

    virtual unsigned ebase() override;
    virtual unsigned dbase() override;
    virtual bool has_min_exp() override;
    virtual int min_exp() override;
    virtual void sign_exp(int s, int e) override;
    virtual void digit(unsigned d) override;
    virtual void done(bool) override;
    virtual void exact_zero() override;
    virtual bool complete() override;
    virtual bool has_digit_limit() override;
    virtual unsigned digits_left() override;
    virtual bigint first_digit_scale() override;
    virtual bigint round_digit_scale() override;

  public:
    IEEEFormatter(int abits, bool ahas_dlimit, int adigits,
                  bool parity_rounding);
};

IEEEFormatter::IEEEFormatter(int abits, bool ahas_dlimit, int adigits,
                  bool parity_rounding)
{
    int expbits;

    expbits = (abits == 16 ? 5 :
               abits == 32 ? 8 :
               abits == 64 ? 11 :
               abits == 128 ? 15 :
               -1);
    expbias = (1 << (expbits-1)) - 1;

    if (ahas_dlimit) {
        /*
         * Enforce that negative digit limits don't get too
         * excessive. In most rounding modes, we can cope with up
         * to the number of mantissa bits (i.e. removing all but
         * the implicit leading 1), so -S -d-23, or -D -d-52. But
         * in parity-based rounding modes (i.e. tie-breaking to
         * even or odd), we decrease that by one, because at that
         * extreme _all_ numbers count as even and so we can't
         * round sensibly.
         */
        int most_neg_dlimit = -(abits - expbits - 1);
        if (parity_rounding)
            most_neg_dlimit++;
        if (adigits < most_neg_dlimit)
            throw config_error("minimum -d value in this mode is ",
                               most_neg_dlimit);
    }

    signexpdigits = (expbits + 1 + 3) / 4;
    expscale = 1 << (signexpdigits*4 - expbits - 1);
    mantdigits_left = (abits / 4) - signexpdigits;
    seen_first_digit = false;

    has_dlimit = ahas_dlimit;
    if (has_dlimit) {
        digits = bigint(mantdigits_left) + fdiv(bigint(adigits) + 3, 4);
        roundscale = 1 << (3U & -adigits);
    } else {
        digits = 0;
        roundscale = 1;
    }

    overflow = false;
}

unsigned IEEEFormatter::ebase()
{
    return 2;
}

unsigned IEEEFormatter::dbase()
{
    return 16;
}

bool IEEEFormatter::has_min_exp()
{
    return true;
}

int IEEEFormatter::min_exp()
{
    return -(expbias - 1);
}

void IEEEFormatter::sign_exp(int s, int e)
{
    assert(e > -(int)expbias);
    unsigned biasexp = e + expbias;
    assert(biasexp > 0);
    unsigned signexp = biasexp * expscale;
    if (signexp >= (1U << (4*signexpdigits - 1)) - expscale) {
        /*
         * Overflow case.
         */
        signexp = (1 << (4*signexpdigits-1)) - expscale;
        if (s < 0)
            signexp |= 1 << (4*signexpdigits-1);
        for (int i = signexpdigits - 1; i >= 0; i--) {
            write(digitchar((signexp >> (4*i)) & 0xF));
        }
        for (int i = mantdigits_left; i-- > 0 ;) {
            write('0');
        }

        overflow = true;
        return;
    }
    if (s < 0)
        signexp |= 1 << (4*signexpdigits - 1);

    /*
     * We have to decide whether to print the final exponent
     * digit, or defer it. It must be deferred if any bits of
     * mantissa live in the same nibble, and also if there's a
     * possibility of denormalisation. Otherwise we can write it
     * out now.
     */
    bool print_last_expdigit_now = (biasexp > 1 && expscale == 1);
    int last_expdigit_to_print = print_last_expdigit_now ? 0 : 1;
    for (int i = signexpdigits - 1; i >= last_expdigit_to_print; i--) {
        write(digitchar((signexp >> (4*i)) & 0xF));
    }
    if (print_last_expdigit_now) {
        last_expdigit = -1;      // means we've already printed it
    } else {
        last_expdigit = signexp & 0xF;
    }
    // The mantissa digit that ends up combined with the exponent
    // must still be counted in our digit counts.
    mantdigits_left++;
    digits++;
}

void IEEEFormatter::digit(unsigned d)
{
    if (overflow)
        return;

    if (!seen_first_digit) {
        seen_first_digit = true;
        /*
         * The first digit is a special case. It will either need
         * to be combined with the last digit of the exponent
         * field, or else just dropped completely.
         */
        if (last_expdigit >= 0) {
            if ((int)d < expscale) {
                /*
                 * Denormalisation. In this case the exponent
                 * vanishes completely, so we ignore last_expdigit
                 * and just print d unchanged.
                 */
            } else {
                /*
                 * Otherwise, trim the leading bit from d and then
                 * combine it with the remaining exponent bits.
                 */
                d = (d & ~expscale) | last_expdigit;
            }
        } else {
            /*
             * In the case where we elide the leading digit
             * completely, we expect that it's always just the
             * leading 1 bit. If it's bigger than that, then we
             * should have folded it into the last exponent digit;
             * if it's smaller, we should have adjusted the
             * exponent field for denormalisation; either way, we
             * ought not to be in this case.
             */
            assert(d == 1);
            mantdigits_left--;
            digits--;
            return;                // do not output anything
        }
    }
    if (mantdigits_left >= 0 && mantdigits_left-- == 0)
        write('.');      // print a point before the mantissa extension
    write(digitchar(d));
    digits--;
}

void IEEEFormatter::done(bool)
{
    while (mantdigits_left-- > 0)
        write('0');
}

void IEEEFormatter::exact_zero()
{
    sign_exp(+1, -(expbias - 1));
    while (mantdigits_left-- > 0)
        write('0');
}

bool IEEEFormatter::complete()
{
    return overflow;
}

bool IEEEFormatter::has_digit_limit()
{
    return has_dlimit;
}

unsigned IEEEFormatter::digits_left()
{
    return digits;
}

bigint IEEEFormatter::first_digit_scale()
{
    return expscale;
}

bigint IEEEFormatter::round_digit_scale()
{
    return roundscale;
}

unique_ptr<OutputGenerator> ieee_format(
    Spigot spig, int bits,
    bool has_digitlimit, int digitlimit, RoundingMode rmode)
{
    return make_unique<BaseOutputGenerator>
        (move(spig), make_unique<IEEEFormatter>(
            bits, has_digitlimit, digitlimit,
            (rmode == ROUND_TO_NEAREST_EVEN || rmode == ROUND_TO_NEAREST_ODD)),
         rmode);
}

/* ----------------------------------------------------------------------
 * Formatter for all 'printf'-style output.
 */

class PrintfFormatter : public FormatterImpl<PrintfFormatter> {
    bool forcepoint;
    size_t fieldwidth;
    int precision;
    int intdigits, mindigits;
    bool print_commas;
    enum { E_MODE, F_MODE, G_MODE } mode;
    enum { PAD_BEFORE, PAD_MIDDLE, PAD_AFTER, PAD_CENTRE } padmode;
    int padchr;
    int expbase, expmult, digitbase;
    char expchr, poschr, a;
    string prefix, expstr, digits;
    bool output_started, finished;
    bool seen_point, stripzeroes;
    size_t padlen;
    int saved_zeroes;
    bool has_dlimit;
    int dlimit;

    void putstr(string s);
    size_t length_so_far();
    void start_output();
    void putch_inner(char c);
    void putch_middle(char c);
    void putch(char c);

    virtual unsigned ebase() override;
    virtual unsigned dbase() override;
    virtual bool has_min_exp() override;
    virtual int min_exp() override;
    virtual void sign_exp(int sign, int exponent) override;
    virtual void digit(unsigned d) override;
    virtual void done(bool) override;
    virtual void exact_zero() override;
    virtual bool has_digit_limit() override;
    virtual unsigned digits_left() override;

  public:
    PrintfFormatter(int width, int aprecision, int flags, int apadchr,
                    int specifier, bool nibble_mode);
};

PrintfFormatter::PrintfFormatter(
    int width, int aprecision, int flags, int apadchr,
    int specifier, bool nibble_mode)
{
    precision = aprecision;
    forcepoint = (flags & PRINTF_FORCE_POINT);
    print_commas = (flags & PRINTF_COMMAS);

    fieldwidth = (width > 0 ? width : 0);
    padchr = apadchr;

    if (flags & PRINTF_ALIGN_LEFT)
        padmode = PAD_AFTER;
    else if (flags & PRINTF_ALIGN_MIDDLE)
        padmode = PAD_MIDDLE;
    else if (flags & PRINTF_ALIGN_CENTRE)
        padmode = PAD_CENTRE;
    else
        padmode = PAD_BEFORE;

    bool uppercase = isupper(specifier);

    if (strchr("aA", specifier)) {
        if (nibble_mode) {
            expbase = 16;
            expmult = 4;
        } else {
            expbase = 2;
            expmult = 1;
        }
        digitbase = 16;
        prefix = (uppercase ? "0X" : "0x");
        expchr = (uppercase ? 'P' : 'p');
        a = (uppercase ? 'A' : 'a');
        mode = E_MODE;             // %a is just a hex version of %e
    } else {
        expbase = digitbase = 10;
        expmult = 1;
        expchr = (uppercase ? 'E' : 'e');
        if (precision < 0)
            precision = 6;
        mode = (strchr("gG", specifier) ? G_MODE :
                strchr("fF", specifier) ? F_MODE : E_MODE);
    }

    if (flags & PRINTF_SIGN_PLUS)
        poschr = '+';
    else if (flags & PRINTF_SIGN_SPACE)
        poschr = ' ';
    else
        poschr = '\0';

    output_started = false;
    seen_point = false;
    saved_zeroes = 0;
    finished = false;
    stripzeroes = false;
}

unsigned PrintfFormatter::ebase()
{
    return expbase;
}

unsigned PrintfFormatter::dbase()
{
    return digitbase;
}

bool PrintfFormatter::has_min_exp()
{
    return (mode == F_MODE);
}

int PrintfFormatter::min_exp()
{
    return 0;
}

void PrintfFormatter::sign_exp(int sign, int exponent)
{
    exponent *= expmult;

    if (mode == G_MODE) {
        /*
         * Change into F_MODE or E_MODE depending on exponent.
         */
        int P = (precision == 0 ? 1 : precision);
        int X = exponent;
        if (P > X && X >= -4) {
            mode = F_MODE;
            precision = P - (X + 1);
        } else {
            mode = E_MODE;
            precision = P - 1;
        }
        if (!forcepoint)
            stripzeroes = true;
    }

    if (sign < 0) {
        prefix = "-" + prefix;
    } else if (poschr) {
        prefix = poschr + prefix;
    }

    // Initialise 'mindigits' to a temporary value, to prevent
    // undefined behaviour when digit() looks at it. We'll set it
    // to the proper value further on.
    mindigits = 0;

    if (mode == F_MODE) {
        // In 'f' mode, we don't start counting precision digits
        // until after the decimal point, so adjust for that.
        intdigits = (exponent > 0 ? exponent : 0) + 1;
        if (precision >= 0)
            precision += intdigits;

        // If the exponent is negative, output some leading
        // zeroes. (This can't happen in _real_ 'f' mode, because
        // we set min_exp in that case, but it can happen if we
        // just converted 'g' mode into 'f' mode above).
        while (exponent < 0) {
            digit(0);
            exponent++;
            precision--;
            assert(precision > 0);
        }
    } else {
        // In non-'f' mode, we print an exponent suffix.
        char expbuf[256];
#if defined _MSC_VER
#define snprintf _snprintf
#endif
        snprintf(expbuf, sizeof(expbuf), "%c%+.*d", expchr,
                 expbase==10 ? 2 : 1,   // min 2 digits for decimal exp
                 exponent);
        expstr = expbuf;
        intdigits = 1;
        if (precision >= 0)
            precision++;      // this doesn't include the int part
    }

    mindigits = precision;

    if (precision >= 0) {
        has_dlimit = true;
        dlimit = precision;
    } else {
        has_dlimit = false;
    }
}

void PrintfFormatter::putstr(string s)
{
    for (size_t i = 0; i < s.length(); ++i)
        write(s[i]);
}

size_t PrintfFormatter::length_so_far()
{
    return prefix.length() + expstr.length() + digits.length();
}

void PrintfFormatter::start_output()
{
    size_t len = length_so_far();
    padlen = (fieldwidth > len ? fieldwidth - len : 0);

    if (padmode == PAD_BEFORE || padmode == PAD_CENTRE) {
        size_t padlen_before = padlen;
        if (padmode == PAD_CENTRE) {
            padlen_before = padlen / 2;
            padlen -= padlen_before;
        }
        for (size_t i = 0; i < padlen_before; i++)
            write(padchr);
    }

    putstr(prefix);

    if (padmode == PAD_MIDDLE)
        for (size_t i = 0; i < padlen; i++)
            write(padchr);

    putstr(digits);

    output_started = true;
}

void PrintfFormatter::putch_inner(char c)
{
    if (output_started) {
        write(c);
    } else {
        digits.push_back(c);
        if (length_so_far() >= fieldwidth)
            start_output();
    }
}

void PrintfFormatter::putch_middle(char c)
{
    if (!forcepoint && !seen_point && intdigits <= 0) {
        putch_inner('.');
        seen_point = true;
    }

    putch_inner(c);
    if (mindigits > 0)
        mindigits--;
    if (!seen_point) {
        intdigits--;
        if (print_commas && intdigits > 0 && intdigits % 3 == 0)
            putch_inner(',');
    }

    if (forcepoint && !seen_point && intdigits <= 0) {
        putch_inner('.');
        seen_point = true;
    }
}

void PrintfFormatter::putch(char c)
{
    if (stripzeroes && c == '0' && intdigits <= 0) {
        saved_zeroes++;
    } else {
        while (saved_zeroes > 0) {
            putch_middle('0');
            saved_zeroes--;
        }
        putch_middle(c);
    }
}

void PrintfFormatter::digit(unsigned d)
{
    putch(digitchar(d, a));
    dlimit--;
}

void PrintfFormatter::done(bool)
{
    for (int i = mindigits; i > 0; i--)
        putch('0');

    if (!output_started)
        start_output();

    putstr(expstr);

    if (padmode == PAD_AFTER || padmode == PAD_CENTRE)
        for (size_t i = 0; i < padlen; i++)
            write(padchr);

    finished = true;
}

void PrintfFormatter::exact_zero()
{
    sign_exp(0, 0);
    digit(0);
}

bool PrintfFormatter::has_digit_limit()
{
    return has_dlimit;
}

unsigned PrintfFormatter::digits_left()
{
    return dlimit;
}

unique_ptr<OutputGenerator> printf_format(
    Spigot spig, RoundingMode rmode, int width, int precision, int flags,
    char pad, int specifier, bool nibble_mode)
{
    return make_unique<BaseOutputGenerator>
        (move(spig), make_unique<PrintfFormatter>(
            width, precision, flags, pad, specifier, nibble_mode), rmode);
}
