simon-git: spigot (master): Simon Tatham

Commits to Tartarus hosted VCS tartarus-commits at lists.tartarus.org
Mon Mar 5 21:03:56 GMT 2018


TL;DR:
  2c6438c Fix two format-string mismatches in diagnostics.
  9252399 C++ cleanup: use 'copy-swap idiom' in bi_internal.
  0a222cf C++ cleanup: mark bigint move constructors 'noexcept'.
  f7f83b5 C++ cleanup: user-defined bigint literals.
  d076df1 C++ cleanup: stop using C-style casts to bigint.
  f83c1fa C++ cleanup: delete lots of copy and move constructors.
  8eb6ba4 C++ cleanup: define virtual destructors as '= default'.
  248f12f C++ cleanup: use 'typename' for template params, not 'class'.
  7fc80ec C++ cleanup: rework the exception classes.
  4f758a8 C++ cleanup: tidy up member function visibility.
  66a68cc C++ cleanup: move method bodies out of class declarations.
  8476b5b C++ cleanup: use templates for class-cloning functions.
  b52da53 C++ cleanup: use std::array for matrices and tensors.
  ea20586 C++ cleanup: type-safe formatting via variadic templates.
  ffad390 C++ cleanup: tidy baseout.cpp's Interval class.
  7c132a3 Add 'all' as a valid option to --debug.
  fe8a7a4 Add an -o option to redirect the output.

Repository:     https://git.tartarus.org/simon/spigot.git
On the web:     https://git.tartarus.org/?p=simon/spigot.git
Branch updated: master
Committer:      Simon Tatham <anakin at pobox.com>
Date:           2018-03-05 21:03:56

commit 2c6438c9fe82f0701cf2b8be43be6d82aba2ed9e
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=2c6438c9fe82f0701cf2b8be43be6d82aba2ed9e;hp=924e0361f3c77d98b4af4ba0f7bcd7c8693b79b9
Author: Simon Tatham <anakin at pobox.com>
Date:   Sun Mar 4 16:54:53 2018 +0000

    Fix two format-string mismatches in diagnostics.
    
    The dprint() function is printf-like in general concept, in that it
    has a format string parameter followed by a variadic argument list.
    But since I had to define my own format string syntax including
    directives for spigot's common data types, I wasn't able to use gcc's
    helpful type-checking of the format against the argument list, and so
    two mismatched diagnostics managed to sneak into the code without
    being caught.
    
    I found these in the course of some upcoming refactoring, and I intend
    to fix the problem more permanently in a later commit.

 cfracout.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

commit 9252399acf4e7dec257562b25a5306b9ae93c450
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=9252399acf4e7dec257562b25a5306b9ae93c450;hp=2c6438c9fe82f0701cf2b8be43be6d82aba2ed9e
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 11:49:59 2018 +0000

    C++ cleanup: use 'copy-swap idiom' in bi_internal.
    
    I've been on a C++ training course recently, which recommended this
    technique as a way to handle the need for copy and move constructors
    and copy and move assignment operators without having to write
    everything a zillion times.
    
    The general idea is that you write your class's copy constructor in
    the normal way, and also a swap function which exchanges the object's
    fields with another object (which will internally use move semantics
    in all the individual swaps); then your move constructor works by
    filling in this object's fields as trivially as possible (consistent
    with it being safe to run the destructor) and then swapping them with
    the source object.
    
    And the clever bit is that having done that, you can then write both
    the copy and move assignment operators in one go, by writing a single
    operator= which takes its argument by _value_, because then the code
    generated at the _call site_ decides whether to copy- or move-
    construct the by-value argument, and all the operator= actually has to
    do is run that swap function again to put the old contents of 'this'
    into the argument that's about to be destructed.
    
    I haven't switched to the same system in the GMP bigints, because
    timing suggested that it made matters worse rather than better. (I
    haven't worked out why yet - I had a theory involving mpz_init being
    too expensive to call in the move constructor, but it doesn't hold
    water, because mpz_init is called in the old move constructor too.)
    But in bi_internal, timing suggests that it's a performance win over
    the previous code.

 bi_internal.h | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

commit 0a222cf9bdb706c4b28314f9cae804aa3754538e
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=0a222cf9bdb706c4b28314f9cae804aa3754538e;hp=9252399acf4e7dec257562b25a5306b9ae93c450
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 11:50:07 2018 +0000

    C++ cleanup: mark bigint move constructors 'noexcept'.
    
    This is another thing I learned on my C++ training course: some parts
    of the STL - notably std::vector - will want to use your object's move
    constructor in contexts where it would be inconvenient to throw an
    exception, so they will avoid it if it isn't marked noexcept. Of
    course, being essentially a swap operation, move constructors
    typically _won't_ throw exceptions, so it's just a matter of making
    sure the language knows that.

 bi_gmp.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit f7f83b5ea03bc756dc6fd0406b70b912ddbe800b
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=f7f83b5ea03bc756dc6fd0406b70b912ddbe800b;hp=0a222cf9bdb706c4b28314f9cae804aa3754538e
Author: Simon Tatham <anakin at pobox.com>
Date:   Wed Feb 28 19:33:00 2018 +0000

    C++ cleanup: user-defined bigint literals.
    
    This allows me to stop writing things like '(bigint)2' all over the
    source code: now I can write '2_bi', which expands to a call to a
    templated function that receives the text of the integer literal as a
    template argument and builds a bigint out of it.
    
    The nice thing is that, being _templated_ on the text of the literal
    rather than receiving it as an argument, the linker will common
    together all the copies of that function with the same text. So every
    reference to, say, '2_bi' throughout the entire program will all go to
    the same run-time instance of the function - and since that function
    returns a const reference to an internal static variable, that
    variable in turn will only need to be constructed once. So this is
    actually more _efficient_ than the old technique, in addition to being
    nicer to write in the source code!

 baseout.cpp   |  2 +-
 bi_gmp.h      | 12 ++++++++++++
 bi_internal.h | 34 ++++++++++++++++++++++++++++++++++
 spigot.cpp    |  6 +++---
 sqrt.cpp      |  8 ++++----
 trig.cpp      |  4 ++--
 zeta.cpp      | 10 +++++-----
 7 files changed, 61 insertions(+), 15 deletions(-)

commit d076df1eed505daf01dfd6a20a3c790e76e6740e
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=d076df1eed505daf01dfd6a20a3c790e76e6740e;hp=f7f83b5ea03bc756dc6fd0406b70b912ddbe800b
Author: Simon Tatham <anakin at pobox.com>
Date:   Wed Feb 28 20:48:23 2018 +0000

    C++ cleanup: stop using C-style casts to bigint.
    
    In the course of the previous commit, I searched the source code for
    '(bigint)' to find constructions that I ought to be switching over to
    the new user-defined literal system. Of course I also found a lot of
    casts of _non_-constant values to bigint.
    
    This commit changes all of those remaining casts so that (bigint)expr
    becomes bigint(expr), i.e. explicitly calling the bigint class
    constructor. This is a more accurate expression of what I really
    wanted to happen, and avoids the use of the C cast syntax, which is a
    bit ambiguous in various parts of C++ (though I admit that in this
    particular case I don't think there was any ambiguity).

 baseout.cpp                | 6 +++---
 exp.cpp                    | 2 +-
 python-module/internal.cpp | 2 +-
 zeta.cpp                   | 7 ++++---
 4 files changed, 9 insertions(+), 8 deletions(-)

commit f83c1fad4d9581f3fd7d725032b54cc80a3d8530
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=f83c1fad4d9581f3fd7d725032b54cc80a3d8530;hp=d076df1eed505daf01dfd6a20a3c790e76e6740e
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 12:03:49 2018 +0000

    C++ cleanup: delete lots of copy and move constructors.
    
    Many objects in the spigot world are not usefully copyable, because
    their internal state is half way through generating a number to be
    consumed by a particular client object, and copying them in that state
    would generate an object of no use to anything. They also shouldn't be
    moved, because other objects will hold references to them.
    
    In C++11, you can conveniently enforce that such objects are not
    _accidentally_ copied or moved by a casual misuse of some innocent
    piece of syntax (such as missing an & and hence assigning an object
    rather than taking a reference), by deleting the copy and move
    constructors and assignment operators.
    
    This commit does just that. For conciseness I've put the deletions in
    a base class 'Immovable', so that it's easy for assorted other class
    hierarchies to inherit from that at the base. All Coreables are now
    immovable, and several things in the Python support module have also
    switched to using this system.

 python-module/internal.cpp | 24 ++++++------------------
 spigot.h                   | 24 ++++++++++++++++++++++--
 2 files changed, 28 insertions(+), 20 deletions(-)

commit 8eb6ba47206d82566a132ea0484ae7bb94c0fdef
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=8eb6ba47206d82566a132ea0484ae7bb94c0fdef;hp=f83c1fad4d9581f3fd7d725032b54cc80a3d8530
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 12:06:19 2018 +0000

    C++ cleanup: define virtual destructors as '= default'.
    
    My C++ training course consider this the preferred style over the
    old-style 'virtual ~ClassName() {}', and although I'm not sure I see
    any semantic distinction, I kind of agree that it's stylistically
    nicer, in that what's in the class is not a _definition_ (with its
    'implicit inline' semantics that are meaningless anyway for a virtual
    function in an abstract class) but a declaration that explains why a
    definition is not needed. So, while I'm generally modernising the C++
    in spigot anyway, let's switch all those empty destructors over to
    being default ones.

 baseout.cpp                | 2 +-
 expr.cpp                   | 4 ++--
 funcs.h                    | 2 +-
 io.h                       | 4 ++--
 python-module/internal.cpp | 1 -
 spigot.cpp                 | 4 ----
 spigot.h                   | 5 ++---
 7 files changed, 8 insertions(+), 14 deletions(-)

commit 248f12fef91281a4ae7fb12df23fadbae8894882
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=248f12fef91281a4ae7fb12df23fadbae8894882;hp=8eb6ba47206d82566a132ea0484ae7bb94c0fdef
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 12:07:32 2018 +0000

    C++ cleanup: use 'typename' for template params, not 'class'.
    
    This is another purely stylistic cleanup suggested by my recent C++
    training. I've always been a bit indecisive and inconsistent about
    which of those keywords to use, so if someone's going to express a
    strong opinion then I think I'll take the opportunity to standardise
    my own practice on it.
    
    There is apparently no semantic distinction in this case - in
    particular, declaring a template parameter as 'class' certainly does
    not constrain the type in an instantiation to be of a _class_ type
    rather than a fundamental type like int. And for exactly that reason,
    'typename' seems more literally accurate as a description of the range
    of things you can put in such a parameter.

 bi_internal.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

commit 7fc80ec2b695a95aec8aa12f7665c226214ff1ff
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=7fc80ec2b695a95aec8aa12f7665c226214ff1ff;hp=248f12fef91281a4ae7fb12df23fadbae8894882
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 11:48:03 2018 +0000

    C++ cleanup: rework the exception classes.
    
    Now they follow the general good practice that anything I plan to
    throw is a derived class of std::exception. Also, while I'm about it,
    I've cleaned them up a bit: removed unnecessary default constructors,
    and provided a text() method that avoids having to cumbersomely repeat
    e.errmsg.c_str() everywhere I catch one.

 error.h                    | 17 +++++++++++------
 main.cpp                   |  6 +++---
 python-module/internal.cpp | 22 +++++++++++-----------
 3 files changed, 25 insertions(+), 20 deletions(-)

commit 4f758a8c4621ade4c47bf3df698f053af3da68e5
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=4f758a8c4621ade4c47bf3df698f053af3da68e5;hp=7fc80ec2b695a95aec8aa12f7665c226214ff1ff
Author: Simon Tatham <anakin at pobox.com>
Date:   Sat Mar 3 17:50:36 2018 +0000

    C++ cleanup: tidy up member function visibility.
    
    Yet another thing my C++ training course taught me was the idea that
    when a concrete class implements an interface defined by an abstract
    base class, its overrides of the pure virtual functions in the base
    class can usefully be private rather than public. The effect of this
    is that you can't call those methods as long as the newly constructed
    object is still being referred to by its true type; instead, it's only
    once you cast the pointer to the base class type that the methods
    become public and hence usable. The idea is that this makes you less
    likely to accidentally write long pieces of code that's specialised to
    a particular implementation of the interface by virtue of interleaving
    calls to the generic interface methods with calls to any extra methods
    provided by that subclass; instead, there's a setup phase when you
    treat the new object as its own type, and then a clear moment where
    you switch over to treating it as just another interchangeable
    implementation of the interface.
    
    In this same change, while I was messing about with all the virtual
    function overrides anyway, I've started declaring overridden virtual
    functions as 'virtual' and using the 'override' keyword, which
    protects against making a typo in the function name or a type-o in its
    parameters and thereby accidentally _not_ overriding the function you
    meant to (instead silently creating a fresh virtual function alongside
    it that never gets used).
    
    While I'm messing with visibility, I've also changed the visibility of
    pure virtual functions in cases like CfracOutputBaseClass, where an
    abstract base class defines a public API made of _non_-virtual methods
    but parametrised by missing pieces that derived classes will all fill
    in differently. In that situation the virtual functions are only there
    to be called by the top-level public API, so they are now 'protected'
    to avoid accidental calls to them from outside the class.
    
    Finally, just because this rework made them easy to spot, I've fixed a
    couple of straight-up mistakes in _whether_ things were virtual or
    not, like StaticGenerator::get_sign() which shouldn't have been
    virtual in the first place.

 algebraic.cpp              |   9 ++-
 arithmetic.cpp             |  10 ++--
 baseout.cpp                | 111 ++++++++++++++++++-----------------
 cfracout.cpp               |  44 ++++++++------
 consts.cpp                 |  24 ++++----
 enforce.cpp                |   7 ++-
 erf.cpp                    |  20 ++++---
 exp.cpp                    |  33 ++++++-----
 expint.cpp                 |  56 ++++++++++--------
 expr.cpp                   | 143 ++++++++++++++++++++++++++-------------------
 expr.h                     |   3 +-
 gamma.cpp                  |  44 +++++++-------
 holefiller.h               |   6 +-
 io.cpp                     |  12 ++--
 iocli.cpp                  |  47 ++++++++-------
 lambertw.cpp               |  39 +++++++------
 main.cpp                   |   8 +--
 monotone.cpp               |  12 ++--
 python-module/internal.cpp |  42 ++++++++-----
 spigot.cpp                 |  26 +++++----
 spigot.h                   |  33 ++++++-----
 sqrt.cpp                   |  25 +++++---
 trig.cpp                   |  55 +++++++++--------
 trigint.cpp                |  16 ++---
 unary.cpp                  |  12 ++--
 zeta.cpp                   |   7 ++-
 26 files changed, 477 insertions(+), 367 deletions(-)

commit 66a68ccf2eda9597498649de3a732a93fef79134
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=66a68ccf2eda9597498649de3a732a93fef79134;hp=4f758a8c4621ade4c47bf3df698f053af3da68e5
Author: Simon Tatham <anakin at pobox.com>
Date:   Sun Mar 4 14:11:24 2018 +0000

    C++ cleanup: move method bodies out of class declarations.
    
    This has several advantages just for code legibility. Firstly, it
    means the class declaration is a nice short summary that you can
    typically see all of on your screen at once. Secondly, it gives
    freedom to present the method names in a different order between the
    class declaration and the actual function definitions, so that the
    former can group together methods that have a related role in the
    class's interactions with other classes (e.g. all the private ones, or
    all the overridden virtual functions) while the latter presents things
    in an appropriate order for the implementation (e.g. showing the
    constructor filling fields in before showing what gets done with them
    by the subsequent methods). And thirdly, the method bodies now start
    one tab stop further to the left, leaving that much more space for
    long lines and deep nesting inside them :-)
    
    Also, moving function bodies out of the class declaration makes them
    not implicitly 'inline'. Of course that's only a hint and the compiler
    is free to ignore it, but it _should_ mean that less inlining takes
    place and the compiler doesn't have to keep re-running all its
    expensive optimisation phases on the same code in multiple places,
    which should improve build time. (Most obviously in the case of
    holefiller.cpp and error.cpp, which are new source files in this
    commit, to which I've moved code that previously lived in the header
    files of the same names.) This may reduce performance, of course, but
    if it's noticeable then it should be possible to restore it by putting
    an explicit 'inline' keyword or two back in once profiling identifies
    the important candidates. And perhaps it won't reduce performance
    anyway, if the compiler makes the right judgments already about what
    to inline - it may well already be cleverer than I am, after all.

 algebraic.cpp              |  111 ++--
 baseout.cpp                | 1369 +++++++++++++++++++++++++------------------
 bi_gmp.h                   |  651 +++++++++++++++++----
 bi_internal.h              | 1385 ++++++++++++++++++++++++++++----------------
 cfracout.cpp               |  449 ++++++++------
 consts.cpp                 |  270 ++++-----
 enforce.cpp                |   83 +--
 erf.cpp                    |  193 +++---
 error.cpp                  |   69 +++
 error.h                    |   51 +-
 exp.cpp                    |  472 ++++++++-------
 expint.cpp                 |  541 +++++++++--------
 expr.cpp                   | 1196 ++++++++++++++++++++++----------------
 gamma.cpp                  |  673 +++++++++++----------
 holefiller.cpp             |  212 +++++++
 holefiller.h               |  258 +--------
 io.cpp                     |  283 +++++----
 io.h                       |   12 +-
 iocli.cpp                  |  225 ++++---
 lambertw.cpp               |   18 +-
 main.cpp                   |   28 +-
 monotone.cpp               |  404 ++++++-------
 python-module/internal.cpp |  528 ++++++++++-------
 sources.mk                 |    2 +-
 spigot.cpp                 |   29 +-
 spigot.h                   |   13 +-
 sqrt.cpp                   | 1086 +++++++++++++++++-----------------
 trig.cpp                   |  475 ++++++++-------
 trigint.cpp                |  375 ++++++------
 unary.cpp                  |  130 +++--
 zeta.cpp                   |  312 ++++++----
 31 files changed, 6962 insertions(+), 4941 deletions(-)

commit 8476b5bea58a3e45533b0e1289b02c30f702f324
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=8476b5bea58a3e45533b0e1289b02c30f702f324;hp=66a68ccf2eda9597498649de3a732a93fef79134
Author: Simon Tatham <anakin at pobox.com>
Date:   Sun Mar 4 15:18:53 2018 +0000

    C++ cleanup: use templates for class-cloning functions.
    
    Several hierarchies of classes in spigot have a method called clone(),
    which every derived class has to implement, and which makes another
    instance of the same kind of class and returns it in some particular
    form such as unique_ptr<base class type>. It's always vaguely annoyed
    me that each derived class has to tediously re-state its own name,
    e.g. SinRational::clone() has to make_unique<SinRational>(arguments).
    
    But since my C++ training course taught me how to do proper argument-
    list forwarding through variadic templates, I can now do this in a way
    that's a bit more concise, by defining a template that infers the type
    being cloned from the 'this' pointer you give it as its first
    argument, and then forwards the rest of its argument list to the
    constructor. So now SinRational::clone(), and all the other methods
    like it, say spigot_clone(this, constructor arguments), which is more
    of a win the longer the class name gets :-)
    
    I've set up a mechanism of this form for the descendants of Coreable
    (all the subclasses that yield a unique_ptr<Coreable>, i.e. a Spigot),
    and one for the descendants of Formatter in baseout.cpp.
    
    For the latter, I've also renamed the clone() method to copy(), on the
    basis that it has different semantics. The Spigot clone() method
    doesn't copy the object in its _current_ state, but rather constructs
    a fresh object that will emit the same sequence of output starting
    again from the beginning (in which respect I suddenly realise it's
    quite similar to biological cloning, going back to the embryo stage
    :-). But Formatters precisely _do_ copy the object in its current
    state, because the aim of doing so is to keep several possible choices
    of what to add next to that state, and later, abandon the ones that
    turned out to be wrong.
    
    (This also means that the template-based copying tool for Formatters
    doesn't even need a variadic argument list: it can always copy the
    provided formatter via its copy constructor.)
    
    There was a third hierarchy of classes with a clone method, namely the
    descendants of MonotoneConstructor. But when I came to look at those,
    I realised there's actually no need to clone _or_ copy them: their
    contents are fixed once they're constructed, so all that's required is
    to address them via shared_ptr rather than unique_ptr, and then
    cloning a spigot class that uses one doesn't have to clone the
    associated MonotoneConstructor class at all, just copy the shared_ptr.

 algebraic.cpp              |  2 +-
 arithmetic.cpp             |  7 ++++---
 baseout.cpp                | 46 ++++++++++++++++++++++++++++------------------
 consts.cpp                 |  6 +++---
 enforce.cpp                |  3 +--
 erf.cpp                    | 22 +++++-----------------
 exp.cpp                    | 23 +++++------------------
 expint.cpp                 | 26 +++++++-------------------
 funcs.h                    |  9 ++++++---
 gamma.cpp                  | 32 +++++++-------------------------
 io.cpp                     |  4 ++--
 lambertw.cpp               | 10 ++--------
 monotone.cpp               | 28 +++++++++++++---------------
 python-module/internal.cpp |  4 ++--
 spigot.cpp                 |  7 +++----
 spigot.h                   | 12 ++++++++++++
 sqrt.cpp                   |  6 +++---
 trig.cpp                   | 46 ++++++++--------------------------------------
 trigint.cpp                | 16 +++++-----------
 unary.cpp                  |  4 ++--
 zeta.cpp                   |  2 +-
 21 files changed, 120 insertions(+), 195 deletions(-)

commit b52da53388ae533579f68f57e1f6fc204d4d9c34
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=b52da53388ae533579f68f57e1f6fc204d4d9c34;hp=8476b5bea58a3e45533b0e1289b02c30f702f324
Author: Simon Tatham <anakin at pobox.com>
Date:   Sun Mar 4 16:56:26 2018 +0000

    C++ cleanup: use std::array for matrices and tensors.
    
    The fundamental type used in all the spigot-algorithm machinery is an
    array of four bigints representing a 2x2 matrix over Z. Core2 also
    uses an array of eight bigints representing a 2x2x2 tensor.
    
    Previously, these were simply C-based arrays, i.e. 'bigint matrix[4]'
    or 'bigint tensor[8]'. Now they're std::array<bigint, [4 or 8]>.
    
    Partly, the aim of this is to improve type-checking if you pass the
    wrong one of them to a function. Partly it also permits them to be
    returned from functions (e.g. the innermost matrix multiply routine)
    by value rather than by a cumbersome reference parameter. But mostly,
    the usefulness of this is that there's now a much more elegant
    assignment syntax available: nearly every piece of code that sets up a
    matrix to return from a Source subclass has been rewritten so that
    instead of separately assigning to matrix[0], matrix[1], matrix[2] and
    matrix[3], it can just say 'matrix = { 1, 0, 0, 1 };' or similar. Far
    more concise and legible!

 algebraic.cpp              |  10 +--
 arithmetic.cpp             | 163 ++++++++++++++++++++-------------------------
 baseout.cpp                |  39 ++++-------
 cfracout.cpp               |  31 +++------
 consts.cpp                 |  28 +++-----
 erf.cpp                    |  13 ++--
 exp.cpp                    |  28 ++++----
 expint.cpp                 |  37 +++-------
 funcs.h                    |   9 +--
 gamma.cpp                  |  51 +++++---------
 misc.cpp                   |  28 ++++++--
 monotone.cpp               |  29 ++------
 python-module/internal.cpp |   6 +-
 spigot.cpp                 | 112 ++++++++++++-------------------
 spigot.h                   |  16 +++--
 sqrt.cpp                   | 104 ++++++++++-------------------
 trig.cpp                   |  53 ++++++---------
 trigint.cpp                |  16 ++---
 unary.cpp                  |   9 +--
 19 files changed, 306 insertions(+), 476 deletions(-)

commit ea205863c91166a1e82f2ca359c0fd3c929d468f
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=ea205863c91166a1e82f2ca359c0fd3c929d468f;hp=b52da53388ae533579f68f57e1f6fc204d4d9c34
Author: Simon Tatham <anakin at pobox.com>
Date:   Sun Mar 4 18:46:52 2018 +0000

    C++ cleanup: type-safe formatting via variadic templates.
    
    Following up my recent discovery of a couple of cases in which a
    dprint() format string didn't match its C-style variadic argument list
    (see commit 2c6438c9f), I've decided I'm tired of format-string based
    debugging in general. It's just too easy to introduce that kind of
    mismatch bug, especially if your format string syntax is customised
    enough that gcc can't apply its standard __attribute__((printf))
    checking, and also, it's a pain having to prefix any nontrivial C++
    object with an &.
    
    So I've completely thrown out the previous stdarg.h-based dprint, and
    in its place is a new shiny system using variadic templates, with a
    call-site syntax more or less like Pascal writeln() or Python print():
    you just provide an arbitrary list of arguments of any types that the
    system can handle, and each one gets formatted in an appropriate way
    and concatenated into the complete diagnostic message.
    
    The basic implementation strategy is that misc.cpp defines a family of
    functions overloaded on the argument type which do sensible formatting
    of every type I care about - including the usual suspects like
    integers, strings and booleans, plus some spigot-specific ones like
    bigint, Matrix and Tensor. Then the top-level dprint function
    (actually dprint_unconditional(), which is the thing that the dprint
    _macro_ invokes if the initial check of the debugging flag doesn't
    skip the entire statement) is implemented as a variadic template which
    contrives to iterate over its argument list calling debug_print_item
    for each argument in turn - and the system will automatically expand
    each call to debug_print_item into the appropriate overload for that
    argument's type.
    
    (In the course of thise, I had to change the type Debuggable::Id so
    that instead of simply being a typedef for an integer type, it's now
    an 'enum class' based on the same integer type and defining no actual
    values. The effect is that now I have to use static_cast to turn it
    into an actual integer and back, because it's no longer _implicitly_
    compatible with any integral type - but the compensating benefit is
    that now the debug_print_item overload family can spot the difference
    and give it the same special output formatting that %D generated in
    the previous system.)
    
    A particularly nice feature of this system is that it can be extended
    to handle extra types in a manner localised to a particular source
    file. For example, the setup code in algebraic.cpp deals with
    polynomials in both integers and rationals, represented as vectors of
    two different types - and by defining another member of the
    debug_print_item family in that file and declaring it 'static', I can
    make dprint() calls in algebraic.cpp alone output vectors in a syntax
    that formats them as polynomials.
    
    Speaking of the algebraic.cpp preparation code, the diagnostics in
    there were previously all commented out, because they happen in free
    functions rather than class methods and hence can't partake of the
    command-line based switching provided by the Debuggable base class.
    While I was reworking the diagnostics in general, I've eliminated that
    exception, by creating a short-lived AlgebraicPrep class and making
    all those setup functions methods of it. So now it can inherit from
    Debuggable in the usual way, and I can replace the commented-out
    diagnostics with entirely active ones in the new style, and now I can
    enable them from the command line just like I can for any other class.
    
    Finally, while I'm at it, I've implemented the same system for the
    spigot_error constructor, which also had a format string plus variadic
    argument list (this time based on standard printf), with a similar
    system that just pushes things into a standard-library ostringstream.
    So I've also got rid of the nasty manoeuvrings with vsnprintf in
    error.cpp, and the workarounds for it not having the right return
    value in some implementations.

 algebraic.cpp  | 426 ++++++++++++++++++++++++++++-----------------------------
 arithmetic.cpp |  43 +++---
 baseout.cpp    | 105 +++++++-------
 bi_gmp.h       |   6 +-
 bi_internal.h  |   4 +-
 cfracout.cpp   |  37 ++---
 enforce.cpp    |   6 +-
 erf.cpp        |  12 +-
 error.cpp      |  53 ++-----
 error.h        |  42 +++++-
 exp.cpp        |  17 ++-
 expint.cpp     |   6 +-
 expr.cpp       |  54 ++++----
 funcs.h        |   1 -
 gamma.cpp      |   7 +-
 holefiller.cpp |  28 ++--
 iocli.cpp      |   8 +-
 lambertw.cpp   |  20 +--
 main.cpp       |   3 +-
 misc.cpp       | 161 +++++++---------------
 monotone.cpp   |  16 +--
 spigot.cpp     |  74 ++++------
 spigot.h       |  60 +++++++-
 sqrt.cpp       |  54 +++-----
 trigint.cpp    |   9 +-
 unary.cpp      |   2 +-
 zeta.cpp       |   2 +-
 27 files changed, 605 insertions(+), 651 deletions(-)

commit ffad3908e9e8cf965de805d656a48ce08fcd521b
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=ffad3908e9e8cf965de805d656a48ce08fcd521b;hp=ea205863c91166a1e82f2ca359c0fd3c929d468f
Author: Simon Tatham <anakin at pobox.com>
Date:   Sun Mar 4 22:04:37 2018 +0000

    C++ cleanup: tidy baseout.cpp's Interval class.
    
    I had another look at it and realised that copy constructor and
    assignment operator are both completely unnecessary, because the
    standard default implementations do the right thing for this class. So
    I've thrown out my own implementations.
    
    Also, I realise that the init() method is redundant, because it's just
    as easy to use the (default, implicit) assignment operator to
    construct a new object with the given parameters and assign it over
    the top of the old one. Better still, this can be done using the brace
    syntax without even having to mention the class name, i.e. I can
    replace the contents of an Interval just by saying 'var = { params }'
    like the Matrix and Tensor assignments.

 baseout.cpp | 35 +++--------------------------------
 1 file changed, 3 insertions(+), 32 deletions(-)

commit 7c132a3ad1d5d81a237eefeacc60a197f1cd458b
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=7c132a3ad1d5d81a237eefeacc60a197f1cd458b;hp=ffad3908e9e8cf965de805d656a48ce08fcd521b
Author: Simon Tatham <anakin at pobox.com>
Date:   Mon Mar 5 19:16:45 2018 +0000

    Add 'all' as a valid option to --debug.
    
    This does the obvious thing: enables the debug messages for _every_
    class inheriting from Debuggable. I wanted it when I was testing the
    revised dprint, and I can imagine it coming in useful again (e.g.
    perhaps if it's not obvious which of a linkage of classes is getting
    stuck, running in this mode might show the one that's spewing endless
    diagnostics in a loop).

 main.cpp   | 2 ++
 spigot.cpp | 9 ++++++++-
 spigot.h   | 3 ++-
 3 files changed, 12 insertions(+), 2 deletions(-)

commit fe8a7a4637ffddc7835cdf03647c6732432cb09c
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=fe8a7a4637ffddc7835cdf03647c6732432cb09c;hp=7c132a3ad1d5d81a237eefeacc60a197f1cd458b
Author: Simon Tatham <anakin at pobox.com>
Date:   Mon Mar 5 19:16:53 2018 +0000

    Add an -o option to redirect the output.
    
    This is probably not all that useful given that you can redirect
    spigot's standard output anyway, but one situation where it does come
    in handy is when --debug is active - since the debug data goes to
    standard output (mostly to make it easy to pipe to 'less'), sending
    the proper output elsewhere - even /dev/null - might have its uses.

 main.cpp    | 104 +++++++++++++++++++++++++++++++++++++-----------------------
 manpage.but |   5 +++
 manual.but  |   3 ++
 3 files changed, 73 insertions(+), 39 deletions(-)



More information about the tartarus-commits mailing list