[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Chapter summary: General utilities are often handy. vul has a few.
Like vbl, vul also provides some basic utilities. The difference is philosophical: vbl includes things that could be thought of as extending the STL, while vul provides just plain utilities which don't claim to be useful or general enough to incorporate into the STL, and may not follow the spirit of the STL. The key elements of this library are:
vul_file
vul_directory
File handling utilities, directory reading
vul_url
Downloading files over HTTP.
vul_arg
Parse command-line arguments conveniently.
vul_redirector
Simplify redirection of standard output/error
vul_awk
Read text files, breaking each line into fields.
vul_reg_exp
Regular expression matching.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
vul_redirector
The class vul_redirector
is provided to simplify the task of
filtering the output of vcl_cerr
and vcl_cout
, a common requirement
in graphical applications. This encapsulates some of the subtleties of
deriving from vcl_streambuf
, providing a simpler interface.
The basic usage is to subclass from vul_redirector
, implementing the
putchunk
method, which is then called whenever characters are ready
for output. The vul_redirector
constructor takes care of attaching
the new buffer to the stream, and of restoring the original behaviour on
destruction. Here is a simple example, which switches output on or off
depending on the value of a global flag;
#include <vul/vul_redirector.h> bool on = true; struct my_redirector : vul_redirector { my_redirector(vcl_ostream& s): vul_redirector(s) {} int putchunk(char const* buf, int n) { if (on) return vul_redirector::put_passthru(buf, n); else return n; } }; |
and here is a calling program which exercises the example.
int main(int argc, char* argv[]) { vcl_cerr << "hi\n"; { my_redirector redir(vcl_cerr); on = false; vcl_cerr << "magic\n"; } vcl_cerr << "what did I miss?\n"; return 0; } |
When this program is run, the word magic
is not displayed, because
my_redirector::putchunk
finds that on == false
. Question,
what to you think put_passthru
does? What happens if you set
on = true
on line 6?
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
vul_printf
While it is possible to achieve all of the functionality
of the C printf
function in C++, it is very very difficult.
There are many times when programs can be made clearer by the use
of printf formatting, rather than the standard iostream operators.
On the other hand, one needs iostreams for type-safe (and convenient)
output of user-defined objects. Thus vul provides a stream-aware
version, vul_printf
:
vcl_ostream& vul_printf(vcl_ostream&, char const* format, ...); |
so that one can say, for example,
vul_printf(vcl_cerr, "Line %05d, Code %-30s\n", __LINE__, code); |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
vul_arg
My favourite bit of vul is the vul_arg
header which provides the
easiest way to parse command-line arguments that I've seen. The basic idea
is that a minimal specification for a command-line argument includes: the
argument's type, a variable to hold it, its flag, and possibly some
descriptive text and a default value.
In the default, easy to use (and a bit naughty) form, each argument is declared anywhere in the program, like so:
vul_arg<double> my_threshold("-fudge", "Twiddle fudge", 1.7); // Type Variable Flag Help text Default |
and when vul_arg_parse
is called, all the arguments are gathered,
and extracted from the command line. To use an argument anywhere in the
program, use its ()
operator:
vcl_cerr << "The threshold = " << my_threshold() << vcl_endl; |
To check if an argument was changed from its default value, one can check
bool my_threshold.set()
.
Here is a complete example which uses vul_arg
. I tend to give these
argument variables names beginning with a_
, but don't let that put
you off.
#include <vcl_iostream.h> #include <vul/vul_arg.h> vul_arg<double> a_naughty_global_arg("-hack", "Fudge", 1.2); void main(int argc, char* argv[]) { vul_arg<char const*> a_filename(0, "Input filename"); vul_arg<bool> a_fast("-fast", "Go fast", false); vul_arg_parse(argc, argv); vcl_cerr << "Filename [" << a_filename() << "]\n"; } |
Passing a 0
as the flag string means that the argument is
obligatory, and will be taken as the first unparsed word on the command
line.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As shown in the example above, a very simple method to set an argument as
obligatory is passing a 0
(or an empty string) as the flag string.
If there are two or more arguments, the parser extracts these arguments
using the order they appear on the command line.
In that case, there is not a flag string. This method to provide obligatory arguments is very common (i.e. when you use operating system shells). However, if you have many arguments or want a more readable interface, you could prefer a required argument which includes a flag string.
To add this functionality, vul includes a special constructor to indicate that
the argument is required. If you want the paremeter to be obligatory, add the
special value is_required
as the third parameter. For example:
vul_arg<int> key ("-key", "Required int", vul_arg<int>::is_required); // Type Variable Flag Help text dummy parameter |
Note that there is not a default value, because it does not make sense.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The help text supplied with each argument is used to provide a summary of
options when the special argument -?
is seen. Running this example
with the -?
flag produces the output.
Usage: ./example_vul_arg.exe [-hack float] string [-fast bool] REQUIRED: string Input filename ['-'] Optional: Switch Type Help [value] -hack float Quick hack factor [1.2] -fast bool Go fast [not set] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A very useful specialization also exists to read ranges of numbers. Imagine a program called makemovie which operates on a list of frames, specified on the command line:
makemovie -frames 1:10,9:-1:1,0,0,0,0 |
These can be easily read into a vcl_list<int>
:
#include <vcl_list.h> vul_arg<vcl_list<int> > a_frame_list("-frames", "List of indices"); |
The list will preserve the order specified on the command line, so in the above example, the result of printing the list would be
1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1 0 0 0 0 |
As a gratuitous STL example, here is the code that printed that list
vcl_copy(a_frame_list().begin(), a_frame_list().end(), vcl_ostream_iterator<int>(vcl_cout, " ")); |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Of course, it's disgraceful programming practice to throw args around ones
program higgledy piggledy, so one can collect arguments in objects of type
vul_arg_list
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If you want to measure elapsed time, for example to find out how long a
section of your program takes to run, use the vul_timer
class. When
a vul_timer
is initialized, like so, it records the current time.
vul_timer mytimer; |
Later, you can find out the elapsed time using the real()
method:
vcl_cerr << "That took " << mytimer.real() << " milliseconds\n"; |
If you want to reset the timer to make a new measurement, use the
mark()
method.
mytimer.mark(); // Reset and start counting from zero again. |
If you are running other jobs on your computer, you might like to know how
much time was used by your program alone. For that, one would use the
user()
method.
vcl_cerr << "Of which " << mytimer.user() << "ms was actually me\n"; |
In general, it is better to use the real
, "wall-clock" elapsed
time, as the CPU time returned by user can fail to include work carried out
on your program's behalf by the operating system. For example, if you're
using a lot of memory, the system will swap pages in and out of virtual
memory, and your program will run slowly, but user()
will not report
it.
Finally, there's a super-convenient print
method, which is used
to just print the real and user times to a stream without any
formatting, for quick testing purposes. Here's an example
vul_timer tic; // Start timing // do stuff tic.print(vcl_cerr); // Print times to vcl_cerr. |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
vul_awk
It is often convenient to read text files a line at a time, and split each
line into space-separated fields. The vul_awk
class is an easy way
to do this. It also adds a few handy extras like stripping comments, and
remembering the line number for error messages. It is used like this:
vcl_ifstream thefile("myfile.txt"); vul_awk awk(thefile); // initialize and read 1st line for (; awk; ++awk) { vcl_cerr << "Field 0 = " << awk[0] << vcl_endl; vcl_cerr << "Field 2 = " << awk[2] << vcl_endl; } |
If myfile.txt
contained the text
dapple dawn-drawn falcon, solihull 1 grimsby 3 |
the above program would print
Field 0 = dapple Field 2 = falcon, Field 0 = solihull Field 2 = grimsby |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
vul_reg_exp
A regular expression allows a programmer to specify complex patterns that can be searched for and matched against the character string of a string object. In its simplest form, a regular expression is a sequence of characters used to search for exact character matches. However, many times the exact sequence to be found is not known, or only a match at the beginning or end of a string is desired. The vul regular expression class implements regular expression pattern matching as is found and implemented in many UNIX commands and utilities, notably perl. The perl code
$filename =~ m"([a-z]+)\.h"; print $1; |
is written as follows in vxl
vul_reg_exp re("([a-z]+)\\.h"); re.find(filename); vcl_cerr << re.match(1); |
The vul syntax is similar to perl's, although not quite as clean. Here are the metacharacters:
^ Matches at beginning of a line $ Matches at end of a line . Matches any single character [ ] Matches any character(s) inside the brackets [^ ] Matches any character(s) not inside the brackets - Matches any character in range on either side of a dash * Matches preceding pattern zero or more times + Matches preceding pattern one or more times ? Matches preceding pattern zero or once only () Saves a matched expression and uses it in a later match. |
Note that more than one of these metacharacters can be used in a single
regular expression in order to create complex search patterns. For example,
the pattern [^ab1-9]
says to match any character sequence that does
not begin with the characters "ab" followed by numbers in the series 1-9.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
vul_url
vul_url
provides a useful means of downloading files over the internet.
For example, if you used to have code like this
bool read_ascii(vcl_istream &); ... int main() { ... vcl_ifstream input(filename); if (!(!input)) read_ascii(input); input.close; ... |
You can get this code to work, even if filename
begins with "http://"
by modifying your code to look like.
bool read_ascii(vcl_istream &); ... int main() { ... vcl_istream *p_input = vul_url::open(filename); if (p_input != 0 && !(!(*input))) read_ascii(*input); delete input; ... |
This will now work both when filename is an HTTP URL and when it is an ordinary filename.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on May, 1 2013 using texi2html 1.76.