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