InitUtil:
An STL Container Initialization Library
by Leor Zolman
Open Source Freeware for Any Standard C++ Compiler
Click here
to download the ZIP archive for v2.1b [updated
March 26, 2004][change
log] Compiles with MSVC 7.1 (stock, Dinkum libs), Comeau C++
4.3 (libcomo and Dinkum libs), gcc 3.2, Intel C++ 7/8. This version
is the most streamlined and the easiest to use. If anyone figures
out how to make it run under other platforms/libraries, please let
me know.
Click here
to download the ZIP archive for v0.9293 [updated
March 26, 2004] [change
log] Compiles with Comeau 4.2.45.2c and above, Metrowerks Pro
8, MSVC 7.1 and gcc 3.x. Supports all standard and hashed
containers with fewer function names, but does require more Standard-conforming
compilers than the version below.
Click here to download the ZIP archive for v0.918ms [updated
March 26, 2004][change
log] Compiles with MSVC 6/7, but currently lacks support for
associative containers.
Introduction (All Versions):
STL containers are a pain to initialize with constant values. One
approach is to create a plain old array and use it to initialize
the container, as in:
int vals[] = { 10, 100, -30, 0, -50, 22 };
const size_t size =
sizeof vals / sizeof vals[0];
vector v(vals, vals + size);
[And of course the last line turns into something even uglier using
VC6's native library due to the lack of member function templates.]
Or, you can manually stuff values into the container one at a time:
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(100);
// ad nauseum...
In the STL Tutorial and Reference Guide, 2nd Edition (Musser et.
al., 2001), a convenience template named "make" is presented
on page 22 to initialize a container of characters from a string
literal, one character at a time. This provides a handy way to illustrate
various container mechanisms and STL algorithms without getting
bogged down in the initialization of the containers...but it only
applies to containers of characters.
I've combined Musser's idea with a technique dating back to 1979
that I used to initialize arrays in BDS C, my old CP/M C compiler.
BDS C didn't support initialization, so to set an array of ints,
I provided a function initw() that was used like this:
initw(array, "1,2,3,4,5,100,200");
to parse the values in the string as ints and stuff them into the
array.
Based on this hack, I've come up with what I believe to be a fairly
convenient way to populate any standard STL container with an arbitrary
list of values of that container's value_type. I personally needed
this ability more for quick-and-dirty testing of STL facilities
than for production work, but if memory use isn't a critical issue
this may in fact prove useful in production code as well. Remember,
however, that memory efficiency (or any kind of efficiency,
actually) did not drive the design. Convenience, and convenience
alone, did.
Usage (Version 2.x):
For example, to load up a bunch of arbitrary numeric values into
a vector or deque:
vector<int> vi = make_cont("1,9,-5,13,22,100,40");
deque<double> dd = make_cont("2.5, 1.9, -3e50");
Maps and multimaps are supported by writing parenthesized key-value
pairs separated by a delimiter (the intra-pair delimiter defaults
to a comma, but may be specified explicitly in the function call;
the inter-pair comma delimiter may be omitted entirely):
map<string, int> msi = make_cont("(leor, 10), (lisa, 20),"
"(ray, 30), (katie, 40)");
These forms are not limited to built-in types; in the demo program,
you can see a vector of Widgets being initialized. Any user-defined
types will work provided they have an extractor, and the ability
for input values to be written in an unambiguous delimited format.
Initialization of string values is also supported. A boolean argument
controls whether or not to strip leading spaces from the strings
(the default value is true, to strip the spaces):
// by default, strip spaces preceding strings
list<string> ls = make_cont("this, is, a, test");
// or, a final arg of false retains all spaces:
deque<string> ds = make_cont("this, is, a, test", false);
Numerical sequences are also supported. Sequences are specified
by size, initial value, and increment. The size is required, while
the initial value and increment arguments both have default values
of 1:
// 100 elements: 50, 53, 56, 59, ...
vector<int> vi = make_cont(100, 50, 3);
// 100 elements: 20, 21, 22, ...
deque<long> vl = make_cont(100, 20);
// 100 elements: 1, 2, 3, ...
vector<int> vi = make_cont(100);
You can replace values in existing containers (effectively assigning
the desired values to the containers) using the set_cont
variant with the same choice of formats:
vector<int> vi;
deque<double> dd;
list<string> ls;
// ...
set_cont(vi, "1,3,3,5");
set_cont(dd, 100, 50.9, 3.2); set_cont(ls, "these, are, now, in, ls");
You can append/insert values to existing containers (preserving
existing values) using the app_cont
variants:
vector<int> vi; deque<double> dd; list<string> ls;
// ... put values in all the above containers...
app_cont(vi, "1,3,3,5");
app_cont(dd, 100, 50.9, 3.2);
app_cont(ls,
"these, strings, have, been, appended, to, ls");
Finally, the ability to create and reassign containers of pointers
is provided via the make_cont_p
, set_cont_p and
app_cont_p template
variations. In the case of make_cont_p,
either the first argument must be the container, or explicit specialization
must be used to invoke the function template. In all cases, these
functions take a NULL-terminated
list of pointers in their parameter lists:
int i = 10, j = 20, k = 30;
vector<int *> v = make_cont_p(v, &i, &j, &k, NULL);
vector<int *> v2 =
make_cont_p<vector<int *> >(&i, &j, &k, NULL);
set_cont_p(v2, &k, &j, &i, NULL); // now there are 3...
app_cont_p(v2, &x, &y, &, NULL); // and now there are 6
To use these facilities, simply include "InitUtil.h"
in your programs.
In the distribution archive, test2.cpp demonstrates many of the
variations. The other header files are there just in support of
the test program, providing some utilities for displaying the contents
of a container.
Usage (Versions .91 and .92):
For example, to load up a bunch of arbitrary numeric values into
a vector or deque:
vector<int> vi = make_cont<vector<int> >
("1,9,-5,13,22,100,40");
deque<double> dd = make_cont<deque<double> >
("2.5, 1.9, -3e50");
Instead of the clunky explicit template specialization syntax,
I also allow the container name to be written as the first argument
(solely for the purpose of providing type information at compile
time to the template specialization mechanism):
set<int> si = make_cont(si, "1,9,-5,...");
list<double> ld = make_cont(ld, "2.5, 1.9, -3e50");
Maps and multimaps are supported by writing parenthesized key-value
pairs separated by a delimiter (the intra-pair delimiter defaults
to a comma, but may be specified explicitly in the function call;
the inter-pair comma delimiter may be omitted entirely):
map<string, int> msi = make_cont(msi,
"(leor, 10), (lisa, 20),"
"(ray, 30), (katie, 40)");
These forms are not limited to built-in types; in the demo program,
you can see a vector of Widgets being initialized. Any user-defined
types will work provided they have an extractor, and the ability
for input values to be written in an unambiguous delimited format.
Initialization of string values is also supported. A boolean argument
controls whether or not to strip leading spaces from the strings
(the default value is true, to strip the spaces).
Due to variations in support for partial template specialization
among compilers, there are currently two versions of the library
available: v0.92X supports string value initializations using the
same function name as for other types, make_cont;
v0.91Xms requires a different function name for the string-initializing
functions, make_cont_str,
and works with MSVC, except that support for associative containers
was dropped (to avoid having to duplicate most of the code in order
to support containers requiring insert()
rather than push_back()
calls). Use .92 if your compiler supports it (Comeau 4.2.45.2c and
later, CodeWarrior Pro 8, gcc 3.x), else use v0.91ms.
Under .91, initializing containers of strings looks like this:
// by default, strip spaces preceding strings
list<string> ls = make_cont_str(ls, "this, is, a, test");
// or, a final arg of false retains all spaces:
deque<string> ds = make_cont_str(ds, "this, is, a, test", false);
Under .92, you'd just say:
// by default, strip spaces preceding strings
list<string> ls = make_cont(ls, "this, is, a, test");
// or, a final arg of false retains all spaces:
deque<string> ds = make_cont(ds,
"this, is, a, test", false);
You can also specify a numerical sequence by size, initial value,
and increment. The size is required, while the initial value and
increment arguments both have default values of 1:
// 100 elements: 50, 53, 56, 59, ...
vector<int> vi = make_cont<vector<int> >(100, 50, 3);
// 100 elements: 20, 21, 22, ...
deque<long> vl = make_cont(vl, 100, 20);
// 100 elements: 1, 2, 3, ...
vector<int> vi = make_cont(vi, 100);
You can replace values in existing containers (effectively assigning
the desired values to the containers) using the set_cont
variant with the same choice of formats:
vector<int> vi;
deque<double> dd;
list<string> ls;
// ...
set_cont(vi, "1,3,3,5");
set_cont(dd, 100, 50.9, 3.2);
set_cont_str(ls,
"these, are, now, in, ls"); // v0.91
set_cont(ls,
"these, are, now, in, ls"); // v0.92
You can append/insert values to existing containers (preserving
existing values) using the app_cont
variants:
vector<int> vi; deque<double> dd; list<string> ls;
// ... put values in all the above containers...
app_cont(vi, "1,3,3,5");
app_cont(dd, 100, 50.9, 3.2);
app_cont(ls,
"these, strings, have, been, appended, to, ls");
Finally, the ability to create and reassign containers of pointers
is provided via the make_cont_p
, set_cont_p and
app_cont_p template
variations. These accept a NULL-terminated
list of pointers in their parameter list:
int i = 10, j = 20, k = 30;
vector<int *> v = make_cont_p(v, &i, &j, &k, NULL);
vector<int *> v2 =
make_cont_p<vector<int *> >(&i, &j, &k, NULL);
set_cont_p(v2, &k, &j, &i, NULL); // now there are 3...
app_cont_p(v2, &x, &y, &, NULL); // and now there are 6
To use these facilities, simply include "InitUtil.h"
in your programs.
In the distribution archives, test9n.cpp (where n is 1 or 2, depending
on the version you download) demonstrates many of the variations.
The other header files are there just for the test program, providing
some utilities for displaying the contents of a container.
Notes:
For a great new addtion to the Boost libraries that does this kind
of thing for arbitrary expressions (not just constant expressions)
-- based on safe overloading of the comma and () operators
-- check out Thorsten Ottosen's Boost
Assign Library.
If you are sick of the gobbledegook most compilers spit out in
response to most STL-related coding errors, be sure to check out
BD Software's STL Error Message Decryptor
(another free download).
Feedback (bugs, suggestions, whatever) is always appreciated --
contact leor@bdsoft.com.
Home |
Courses |
Tools |
Resources
Clients |
Successes |
Contact |
Site Map |
Links |
About Us
All text and images on this website are Copyright © 2001-2003 BD Software. All rights reserved.
|
 |