/* -*- c++ -*-
 * spigot.h: Declare the base classes for spigot-based exact real
 * arithmetic.
 */

#ifndef SPIGOT_SPIGOT_H
#define SPIGOT_SPIGOT_H

#ifdef HAVE_CMAKE_H
#include "cmake.h"
#endif

#include "bigint.h"

// No-op template function which can only be instantiated for arrays
template<typename T, size_t n>
static inline void enforce_array(T (&)[n]) {}

// Macro to return the element count of an array, via sizeof(x)/sizeof(*x).
// Also puts an enforce_array() in the sizeof, to protect against being
// called by mistake with a pointer instead of an array.
#define lenof(x) (sizeof(enforce_array(x), x)/sizeof(*(x)))

#if HAVE_FDOPEN && HAVE_TCSETATTR
/*
 * The code which permits expressions to contain atoms of the form
 * 'base10fd:3' and 'cfracfd:4', identifying a Unix file descriptor
 * from which to read a number formatted in a particular way, is
 * conditionalised on autoconf having told us we've got the necessary
 * API functions available. This should remove one obstacle to
 * compiling this program on non-Unix.
 */
#define HAVE_FDS
#endif

#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>

#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <array>
#include <memory>
#include <utility>
#include <type_traits>
using std::string;
using std::vector;
using std::set;
using std::max;
using std::array;
using std::unique_ptr;
using std::make_unique;
using std::move;
using std::forward;
using std::enable_if;
using std::is_base_of;
using std::is_integral;
using std::is_signed;
using std::is_unsigned;

using Matrix = array<bigint, 4>;
using Tensor = array<bigint, 8>; // used by Core2 in arithmetic.cpp

class bigint_or_inf; // forward reference

/*
 * Below are the main class definitions for the central parts of the
 * spigot algorithm.
 *
 * There are three basic components, which I've called Source, Core
 * and Generator.
 *
 * A Source is something which delivers a description of a specific
 * real number, in the spigot representation of a stream of matrices
 * and a starting interval.
 *
 * The Generator base class contains the top-level loop of the main
 * spigot algorithm, which checks to see if it has enough information
 * to produce some output, and if so, produces it and premultiplies in
 * a matrix representing the extraction of that output, and otherwise,
 * fetches more stuff from the Source. A derived class of Generator
 * exists for each possible format the output might be needed in:
 * digits in a base-n positional system, continued fraction terms,
 * random queries useful to clients doing further computation on the
 * numbers, and there's also a special-purpose Generator which
 * reconstitutes the number as a Source again so that it can be fed to
 * further computations.
 *
 * But Generator doesn't contain the whole spigot algorithm. About
 * half of it is separated out into the Core class. The interface
 * between Generator and Core consists of three key methods: Generator
 * can ask Core where the current endpoints of its output interval lie
 * (in a form rich enough to also spot things like constant functions
 * and poles), it can tell Core to go and absorb more data from its
 * Source to refine those endpoints, and it can pass a matrix back to
 * Core to premultiply in when it's extracting output.
 *
 * Splitting the algorithm up at that point turns out to be a good
 * idea purely on legibility grounds, but the main purpose is to
 * permit alternative Cores. The primary default Core takes a single
 * Source, but this system also permits a two-input Core to be slotted
 * in in place of the default one, to do arithmetic on two input
 * numbers, without having to affect the Generator side of the
 * mechanism.
 */

class Debuggable {
    /*
     * Everything in this hierarchy derives from Debuggable. This
     * class assigns each created debuggable object a unique
     * identifier, and provides a convenient means for all those
     * objects to do diagnostic print statements which automatically
     * include that identifier.
     */
  public:
    enum class Id : unsigned long {};

    // Debuggable classes must provide something inherited from this
    // which gives the name of the class for dgreet purposes.
    class ClassName {
      protected:
        ClassName(const char *name);
      public:
        string name;
    };

  private:
    static set<Id> debug_ids;
    static set<string> debug_names;
    Id debuggable_object_id;
    string debuggable_object_name;
  protected:
    static bool debug_all_greetings, debug_all_objects;
    bool debugging;
    void set_debuggable_object_name(const ClassName &);
  public:
    Debuggable();
    virtual ~Debuggable() = default;

    void dprint_item(const char *);

    template<typename... Args>
    void dprint_internal(Args&&... args);
    template<typename... Args>
    void dprint_unconditional(Args&&... args);
    void dgreet_unconditional();
    template<typename Arg1, typename... Args>
    void dgreet_unconditional(Arg1&& arg1, Args&&... args);

    template<typename... Args>
    void internal_fault(Args&&... args);

    Id dbg_id();

    /*
     * Macro wrappers to arrange that objects can write dgreet() and
     * dprint() statements as if they are unconditional, but in
     * non-debugging mode, even the argument lists won't be evaluated.
     */
    #define dprint(...) do                                  \
        {                                                   \
            if (debugging)                                  \
                dprint_unconditional(__VA_ARGS__);          \
        } while (0)
    #define dgreet(...) do                                  \
        {                                                   \
            set_debuggable_object_name(classname(this));    \
            if (debugging || debug_all_greetings)           \
                dgreet_unconditional(__VA_ARGS__);          \
        } while (0)

    static void add_debug_id(Id id);
    static bool is_known_class_name(const string &name);
    static vector<string> known_class_names();
    static void add_debug_name(const string &name);
    static void debug_greetings();
    static void debug_all();
};

#define MAKE_CLASS_GREETER(Foo)                                         \
    class Foo ## Greeter : public Debuggable::ClassName {               \
      public:                                                           \
        Foo ## Greeter() : ClassName(#Foo) {}                           \
    };                                                                  \
    static const Foo ## Greeter Foo ## GreeterInstance;                 \
    static const Debuggable::ClassName &classname(const Foo *) {        \
        return Foo ## GreeterInstance;                                  \
    }

// Type-based debug subfunctions in misc.cpp
void debug_print_item(FILE *fp, intmax_t i);
void debug_print_item(FILE *fp, uintmax_t u);
void debug_print_item(FILE *fp, Debuggable::Id id);
void debug_print_item(FILE *fp, const char *s);
void debug_print_item(FILE *fp, const string &s);
void debug_print_item(FILE *fp, bool b);
void debug_print_item(FILE *fp, const bigint &bi);
void debug_print_item(FILE *fp, const bigint_or_inf &bi);
void debug_print_item(FILE *fp, const Matrix &mx);
void debug_print_item(FILE *fp, const Tensor &ts);

// Another related helper function
string debuggable_id_string(Debuggable::Id id);

// Convert all other integral types to the widest signed/unsigned one
template<typename Integer, intmax_t = 0,
         typename = typename enable_if<is_integral<Integer>::value &&
                                       is_signed<Integer>::value>::type>
inline void debug_print_item(FILE *fp, Integer i)
{
    debug_print_item(fp, static_cast<intmax_t>(i));
}
template<typename Integer, uintmax_t = 0,
         typename = typename enable_if<is_integral<Integer>::value &&
                                       is_unsigned<Integer>::value>::type>
inline void debug_print_item(FILE *fp, Integer i)
{
    debug_print_item(fp, static_cast<uintmax_t>(i));
}

// For placating optimiser warnings about dummy[] in the definition
// below not being used
template<typename T> inline void ignore(T &&) {}

template<typename... Args>
inline void Debuggable::dprint_internal(Args&&... args)
{
    struct Empty {};
    Empty dummy[] = {
        (debug_print_item(stdout, forward<Args>(args)), Empty())...
    };
    ignore(dummy);
    debug_print_item(stdout, "\n");
}

template<typename... Args>
inline void Debuggable::dprint_unconditional(Args&&... args)
{
    dprint_internal("[", debuggable_object_id, "] ", args...);
}

inline void Debuggable::dgreet_unconditional()
{
    dprint_internal("[", debuggable_object_id, "] hello ",
                    debuggable_object_name);
}

template<typename Arg1, typename... Args>
inline void Debuggable::dgreet_unconditional(Arg1&& arg1, Args&&... args)
{
    dprint_internal("[", debuggable_object_id, "] hello ",
                    debuggable_object_name, " ", arg1, args...);
}

class Immovable {
    /*
     * A base class that makes it convenient to prohibit any copying
     * or moving of a class. All of the classes in the spigot
     * number-production hierarchy want to have this property: they
     * can't usefully be copied, because they contain lots of state of
     * an ongoing computation (though many of them will have a clone
     * method that generates a fresh object that can restart the same
     * computation _from the beginning_), and they shouldn't be moved
     * either because other objects will hold references to them.
     */
  public:
    Immovable() = default;
    Immovable(const Immovable &) = delete;
    Immovable(Immovable &&) = delete;
    Immovable &operator=(const Immovable &) = delete;
    Immovable &operator=(Immovable &&) = delete;
};

class Core;
class Source;
class BaseSource;
class CfracSource;

class Coreable : public Debuggable, public Immovable {
    /*
     * Cores and Sources are more or less interchangeable, because any
     * Source is easily turned into a Core by putting a Core1 on the
     * front (the default one-source core, defined in spigot.cpp), and
     * conversely any Core can be turned back into a Source by putting
     * a SourceGenOuter on the front (also in spigot.cpp).
     *
     * Hence, we define this common base class of Core and Source
     * which makes that interchangeability explicit; in each
     * descendant, one of toCore and toSource just returns the input
     * pointer (appropriately type-converted) and the other puts an
     * appropriate shim on the front. These must each be called with a
     * bare pointer, which has been extracted from a unique_ptr via
     * the release() method.
     */
  public:
    virtual unique_ptr<Coreable> clone() = 0;
    virtual unique_ptr<Core> toCore() = 0;
    virtual unique_ptr<Source> toSource() = 0;

    /*
     * Lots of parts of this program can do something more useful if
     * they *know* a number is rational. Hence, all Cores and Sources
     * provide this virtual function, which will give their rational
     * value if they're known to have one.
     */
    virtual bool is_rational(bigint *n, bigint *d);
};

template<typename T, typename... Args,
         typename = typename enable_if<is_base_of<Coreable, T>::value>::type>
unique_ptr<Coreable> spigot_clone(const T *, Args&&... args)
{
    return make_unique<T>(forward<Args>(args)...);
}

/*
 * 'Coreable' is a sensible name in terms of how the above class fits
 * into the complicated structure. But outside the core modules that
 * have to care about that structure, I want a more generic name for
 * the type that the implementations of individual functions will be
 * mostly defined in terms of and constantly passing to each other.
 *
 * A thoroughly appropriate name for that type is 'Spigot', so here's
 * a typedef that will let me use that name most of the time, and only
 * worry about Cores and Sources and Coreables when it's really
 * relevant.
 *
 * This typedef is also a unique_ptr, which partly makes life easier
 * because you don't need to manually free it, but also has the side
 * effect that it can't be copied - which is appropriate, because most
 * functions to which you pass a Spigot will incorporate it into their
 * own evaluation tree and consume all its output. So in general
 * you'll make values of type Spigot by two methods: one is by
 * make_unique<some particular subclass of Core or Source>(params),
 * and the other is by passing one or more existing Spigots as
 * arguments to a function, using std::move which will consume them,
 * e.g. spigot_sin(move(x)) or spigot_add(move(x), move(y)).
 *
 * (Though you don't need the move() if the argument to one function
 * comes straight from the return value of another, e.g. you can write
 * spigot_sin(spigot_sqrt(move(x))) without needing a second move
 * around the return value of spigot_sqrt. This is because unnamed
 * subexpressions are 'rvalues' in C++11 terms; more concretely, it's
 * because there's no variable accessible after the expression has
 * been evaluated that still contains a copy of that return value. You
 * only need move() when there's some named Spigot-type variable that
 * persists after you've used up its contents, in which case move()
 * will set it back to nullptr as a side effect.)
 */
typedef unique_ptr<Coreable> Spigot;

struct endpoint {
    bigint n, d;
    endpoint(const bigint &an, const bigint &ad);
};

class Core : public Coreable {
    /*
     * Ancestor of all Core classes. The boilerplate toCore and
     * toSource methods are filled in here, but all the routines for
     * doing interesting work are left to the concrete descendant.
     */
  public:
    virtual void premultiply(const Matrix &matrix) = 0;
    virtual void refine() = 0;
    virtual void endpoints(vector<endpoint> &) = 0;
  private:
    virtual unique_ptr<Core> toCore() override;
    virtual unique_ptr<Source> toSource() override;
};

class bigint_or_inf {
    bool is_infinite;
    bigint n;
    class Infinity {};
    bigint_or_inf(Infinity);
  public:
    static const bigint_or_inf infinity;

    bigint_or_inf() = default;
    bigint_or_inf(const bigint &an);
    bigint_or_inf(const bigint_or_inf &) = default;
    bigint_or_inf(bigint_or_inf &&) = default;
    bool finite(bigint *value = nullptr) const;

    bigint_or_inf &operator=(const bigint &an);
    bigint_or_inf &operator=(const bigint_or_inf &) = default;
    bigint_or_inf &operator=(bigint_or_inf &&) = default;
};

class Source : public Coreable {
    /*
     * Ancestor of all Source classes. The boilerplate toCore and
     * toSource methods are filled in here, but all the routines for
     * doing interesting work are left to the concrete descendant.
     *
     * You can override this class and fill in the three pure virtual
     * methods, or some still-abstract descendants are provided below
     * in case that's easier.
     */
    bigint int_lo;
    bigint_or_inf int_hi;
    bool got_interval { false };
    bool started { false };
    Matrix pending_matrix { { 1, 0, 0, 1 } };
  public:
    bool get_interval(bigint *low, bigint_or_inf *high);
    bool get_matrix(Matrix &matrix);
  protected:
    virtual bool gen_interval(bigint *low, bigint_or_inf *high) = 0;
    virtual bool gen_matrix(Matrix &matrix) = 0;
  private:
    virtual unique_ptr<Core> toCore() override;
    virtual unique_ptr<Source> toSource() override;

    friend class Prepend;
};

class BaseSource : public Source {
    /*
     * Abstract base class for turning a stream of digits in a
     * specified base into a Source. Override this class and fill in
     * gen_digit() (and clone() from the parent).
     */
    bool first_digit;
    bigint base;
    bool negate;
  public:
    BaseSource(bigint base, bool negate);
  protected:
    virtual bool gen_digit(bigint *digit) = 0;
  private:
    virtual bool gen_interval(bigint *low, bigint_or_inf *high) override;
    virtual bool gen_matrix(Matrix &matrix) override;
};

class CfracSource : public Source {
    /*
     * Abstract base class for turning a stream of continued fraction
     * terms into a Source. Override this class and fill in
     * gen_term() (and clone() from the parent).
     */
  protected:
    virtual bool gen_term(bigint *term) = 0;
  private:
    virtual bool gen_interval(bigint *low, bigint_or_inf *high);
    virtual bool gen_matrix(Matrix &matrix);
};

class BinaryIntervalSource : public Source {
    /*
     * Abstract base class for turning a stream of binary intervals
     * (that is, intervals of rationals with a power-of-2 denominator)
     * into a Source. Override this class and fill in
     * gen_bin_interval() (and clone() from the parent).
     */
    bigint lo, hi;
    unsigned bits;
    bool started;
  public:
    BinaryIntervalSource();
  protected:
    virtual void gen_bin_interval(bigint *lo, bigint *hi, unsigned *bits) = 0;
  private:
    virtual bool gen_interval(bigint *low, bigint_or_inf *high) override;
    virtual bool gen_matrix(Matrix &matrix) override;
};

class Generator : public Debuggable, public Immovable {
    /*
     * Ancestor of all Generator classes. This base class contains the
     * main function iterate_spigot_algorithm that everything ends up
     * coming back to, but exposes no way to get the results out. So
     * it's conceptually an abstract base class, even though it
     * doesn't happen to have any pure virtual methods; regardless of
     * that, you have to override it to get anything useful done,
     * because you have to add public methods that produce output.
     *
     * Generator objects have the common feature that you pass them a
     * Core (or at least Coreable) at construction time, and they take
     * ownership of it - they expect it to have been be dynamically
     * allocated, and they will delete it when destructed.
     */
    bool started;
    bool we_are_now_constant;
    vector<endpoint> endpoints;
  private:
    void iterate_spigot_algorithm(bool force);
  protected:
    unique_ptr<Core> core;
    void ensure_started();
    void iterate_to_bounds(bigint *rlo, bigint *rhi,
                           bool *rlo_open, bool *rhi_open,
                           int minwidth, const bigint *scale,
                           bool force_refine);
    bool iterate_to_floor_or_inf(bigint *rfloor, bool *rconstant = nullptr);
    bigint iterate_to_floor(bool *constant = nullptr);
  public:
    Generator(Spigot acore);
    virtual ~Generator() = default;
};

class CfracGenerator : public Generator {
    /*
     * Generator that produces continued fraction terms of the number.
     * The first call to get_term() returns the integer part;
     * subsequent calls return the following terms.
     *
     * No special handling is done for negative numbers. So the
     * integer part returned will always be floor of the actual
     * number, and the next term has positive sense, i.e. if the
     * numbers returned are a, b, c, ... then the actual number is
     * equal to
     *
     *   a + 1
     *       -----------
     *       b + 1
     *           -------
     *           c + 1
     *               ---
     *               ...
     */
    bool done;
  public:
    CfracGenerator(Spigot acore);
    bool get_term(bigint *retterm);
};

class ConvergentsGenerator {
    /*
     * Class that returns continued-fraction _convergents_ to the
     * number, i.e. the actual rational numbers resulting from
     * successive truncations of the continued fraction.
     *
     * This class _looks_ like a generator, and you can treat it as
     * one for all practical purposes, but it isn't actually descended
     * from the Generator base class because I need to ensure that
     * nobody accidentally calls get_term() on the CfracGenerator it's
     * based on. (Otherwise a term will be missed by the tracker in
     * this class, and all the subsequent convergents will come out
     * wrong). Therefore, it _has_ a CfracGenerator rather than being
     * one.
     *
     * (I suppose that makes the class's name a misnomer - but it
     * would surely be even uglier to call it something like
     * ConvergentsNotReallyAGenerator.)
     */
    CfracGenerator cfg;
    bigint cvn, pcvn, cvd, pcvd;

  public:
    ConvergentsGenerator(Spigot acore);
    bool get_convergent(bigint *n, bigint *d);
};

class BracketingGenerator : public Generator {
    /*
     * Class that returns pairs of increasingly precise rational
     * numbers over a common denominator bracketing the target number,
     * but which avoids exactness hazards by not insisting that they
     * be the very best rationals for a given denominator.
     *
     * The denominators are always powers of two, and at your option
     * you can receive them as bigints (via get_bracket) or as plain
     * bit-shift counts (get_bracket_shift).
     */
    unsigned bits, prevbits;

  public:
    BracketingGenerator(Spigot acore);
    void get_bracket(bigint *nlo, bigint *nhi, bigint *d);
    void get_bracket_shift(bigint *nlo, bigint *nhi, unsigned *dbits);
    void set_denominator_lower_bound(bigint d);
    void set_denominator_lower_bound_shift(unsigned dbits);
};

class StaticGenerator : public Generator {
    /*
     * This generator never premultiplies anything into its core,
     * unless explicitly told to. Therefore, its various methods can
     * safely be called in any interleaving without interfering with
     * one another; the only one that modifies state is the
     * premultiply() method, and you know when you're calling that.
     */
  public:
    StaticGenerator(Spigot acore);
    bigint get_floor(bool *constant);
    bigint get_approximate_approximant(const bigint &d);
    int get_sign();                 /* +1, -1, or 0 if exactly zero */
    int try_get_sign();             /* +1, -1, or 0 if not yet sure */
    void premultiply(const Matrix &matrix);
    /* Also, in this derived class we expose iterate_to_bounds() as public. */
    using Generator::iterate_to_bounds;
};

/*
 * Abstract base class of the various generators used in main() to
 * produce spigot's final output.
 */
class OutputGenerator : public Generator {
  protected:
    OutputGenerator(Spigot acore);
  public:
    virtual bool get_definite_output(string &out) = 0;
    virtual bool get_tentative_output(string &out, int *digits) = 0;
};

/*
 * Function called periodically during the inner loop of
 * iterate_spigot_algorithm, which can check for an interruption of
 * some sort and handle it by throwing a C++ exception to terminate
 * the iteration.
 */
void spigot_check_exception();

/*
 * Functions in misc.cpp.
 */
void bigint_print_nl(const bigint &a);
/* Exact sign test. Will take ownership of x and deletes it. */
int get_sign(Spigot x);
/* Tries to find the sign of one of x1,x2, whichever gets there first.
 * Returns +1 or -1 if the sign is of x1, or +2 or -2 if it's x2. Will
 * take ownership of both x1,x2 and delete them. */
int parallel_sign_test(Spigot x1, Spigot x2);
bigint gcd(bigint a, bigint b);
bigint lcm(bigint a, bigint b);

/*
 * Some functions available inline to all source files.
 */

/*
 * match_dyadic_rationals() is a variadic template function with the
 * following semantics. You call it with a collection of (bigint &n,
 * unsigned dbits) argument pairs:
 *
 *    unsigned match_dyadic_rationals(bigint &n1, unsigned dbits1,
 *                                    bigint &n2, unsigned dbits2,
 *                                    // ... as many pairs as you like ...
 *                                    bigint &nK, unsigned dbitsK);
 *
 * Each argument pair is taken to represent a rational of the form
 * (n/2^dbits), with the bigint numerator passed by reference. The
 * function finds and returns the maximum of all the dbits values, and
 * shifts each n value left to compensate. So if you write
 *
 *    db = match_dyadic_rationals(n1, db1, n2, db2);
 *
 * then n1 and n2 are modified in such a way that (n1,db) and (n2,db)
 * on output represent the same values that (n1,db1) and (n2,db2)
 * represented on input.
 *
 * The implementation uses several subroutines that are also
 * variadically templated. To keep those namespaced away from
 * accidental collisions, I've put them in a fake class.
 */
class DyadicRationalMatcher {
    /*
     * Pass 1 of match_dyadic_rationals: just compute the maximum
     * dbits value.
     */
    static inline unsigned max_dbits() {
        /* Base case, with no input parameter pairs */
        return 0;
    }
    template<typename... Rest>
    static inline unsigned max_dbits(
        bigint &n, unsigned dbits_in, Rest&&... rest)
    {
        /* Inductive case: peel off one parameter pair and recurse */
        unsigned dbits_rest = max_dbits(std::forward<Rest>(rest)...);
        unsigned dbits_out = max(dbits_rest, dbits_in);
        return dbits_out;
    }

    /*
     * Pass 2 of match_dyadic_rationals: knowing the output dbits
     * value, shift each input numerator left to match it.
     */
    static inline void set_dbits(unsigned dbits) {
        /* Base case, with no input parameter pairs */
    }
    template<typename... Rest>
    static inline void set_dbits(
        unsigned dbits, bigint &n, unsigned dbits_n, Rest&&... rest)
    {
        /* Inductive case: peel off one parameter pair and recurse */
        if (dbits_n < dbits)
            n <<= dbits - dbits_n;
        set_dbits(dbits, std::forward<Rest>(rest)...);
    }

  public:
    /*
     * Putting it together, this function does the whole job. It has
     * to be defined inside the helper class so that it can access the
     * private methods, but that gives it a cumbersome name, so we
     * define a wrapper below.
     */
    template<typename... Rest>
    static inline unsigned match_dyadic_rationals(Rest&&... rest)
    {
        unsigned dbits = max_dbits(std::forward<Rest>(rest)...);
        set_dbits(dbits, std::forward<Rest>(rest)...);
        return dbits;
    }
};

/*
 * This is the function the user will actually call.
 */
template<typename... Rest>
unsigned match_dyadic_rationals(Rest&&... rest)
{
    return DyadicRationalMatcher::match_dyadic_rationals(
        std::forward<Rest>(rest)...);
}

/*
 * Another small helper function: given two intervals with integer
 * bounds, overwrite the first of them (passed by mutable reference)
 * to be the intersection of the two intervals.
 */
inline void intersect_intervals(bigint &lo1, bigint &hi1,
                                const bigint &lo2, const bigint &hi2)
{
    if (lo1 < lo2)
        lo1 = lo2;
    if (hi1 > hi2)
        hi1 = hi2;
}

// Declare the enumerated type 'RoundingMode', without defining its
// values. The values live in rmode.h, which is only included where
// needed (to cut down on rebuilds).
enum RoundingMode : int;

#endif /* SPIGOT_SPIGOT_H */
