George is a software engineer in the System Design and Verification group at Cadence Design Systems. He can be reached at georgefrazieryahoo.com.
Null Iterator Type for STL
by Dan Shappir
shappirmath.tau.ac.il
Sometimes it's worthwhile to do nothing. That is why many operating systems let you redirect output to null devices. Similarly, C/C++ functions that use pointers for output parameters often allow passing NULL as an indication that a particular value should be discarded. If possible, such a value shouldn't even be calculated in the first place. Given how useful and widespread this idiom is, I was surprised to find it missing from the Standard Template Library (STL).
STL uses iterators as an abstraction that lets a section of code read data from a variety of sources. For example, you can use the find algorithm to search the members in any STL collection, the characters in an std::string, and also inside a file, using the std::istream_iterator. Likewise, output iterators let a section of code write data to a variety of destinations. What STL lacks is an output iterator type that simply discards any data written into it. Ideally, such an iterator should be defined in such a way that would allow an optimizing compiler to discard the entire calculation of the output values.
I created such an iterator, which I've named null_iterator (Listing One). I would have liked to put this iterator in the std namespace, but the C++ Standard prohibits the placement of programmer-defined identifiers into that namespace. Using null_iterator, I can create generic algorithms that, among other operations, also generate optional output (logs). When this output is needed, I will direct it to a standard iterator. When it isn't needed, I direct it to a null_iterator.
For example, the following code does absolutely nothing:
std::copy(someContainer.begin(),
someContainer.end(), null_iterator());
Indeed, with optimizations enabled, the compiler should emit no code for it at all. null_iterator is implemented in such a way that it supports every type of output data. Because the STL implementation in Microsoft VC6 was not fully standard compliant, I had to use conditional compilation to support that compiler.
Debug Formats in GCC
by George F. Frazier
georgefrazieryahoo.com
One of the "black arts" of GCC configuration and usage is the interaction between the debug format GCC outputs and its consumption by open-source tools like GDB and proprietary tools such as IBM's (aka Rational's) Purify. For example, if you have a language tool and you ship or bundle a version of GCC so that you know your users are going to use the same version you used to build your libraries with, it is important to be able to support the basic debugging tools that those customers are accustomed to using. If you are taking the time to "ship" GCC, you are probably also either shipping or recommending a specific version of GDB as well.
A common scenario that causes problems is when GCC is configured to use Dwarf 2 as the default debug format for better symbol table info in GDB. The choice of debug format is highly platform specific, but Dwarf 2 can buy you extra debug info if you are using some of the more common platforms such as Solaris and Linux. You configure GCC to default to Dwarf 2 at configure time by specifying with-dwarf2. Specify that the compiler should use DWARF 2 debugging information as the default. Most platforms default to stabs otherwise.
The problem here is that Purify doesn't understand Dwarf 2 so if you load up your code in Purify, you won't have line number info, source annotation, or the ability to descend into a function hierarchy in the GUI.
The simple solution here is to instruct your users to build their code with the -gstabs or -gstabs+ option to GCC. You are in effect robbing Peter to pay Paul: GDB info suffers to some extent if you are relying on Dwarf 2 and have compiled your libraries that way; but most users are willing to do a special build for Purified info and then switch back to the standard compile options once they have fixed memory leaks, memory corruption, or whatever they are hunting down in Purify. The moral here is that for symbol table formats, one size doesn't fit all, but GCC provides an excellent level of control both at the configure and compile stage for determining the format for debug output. Make sure you understand your requirements first and then communicate them to your customers.
Enumerating Registry
Subkeys in D
by Matthew Wilson
matthewsynesis.com.au
In the implementation of the D.win32.registry module for Phobos (the D Standard Library, http://digitalmars.com/d/), I had handled the enumeration of registry subkeys by using a helper function _Reg_EnumKeyName(). This function originally performed the task of hiding all the un- needed parameters to the Win32 API C function RegEnumKeyExA(), and was defined as in Example 1(a).
The client code that used this helper for the lookup or enumeration of keys was contained within methods of several of the classes in the registry module, as shown in Example 1(b).
This function uses another helper function _Reg_GetNumSubKeys(), which uses the Win32 API C function RegQueryInfoKeyA() to determine the number of sub-keys and the maximum length of the names of the subkeys. This enables the array sName to be allocated accordingly; see Example 1(c).
The problem is that, in a very few cases, the registry API tells lies. On my machine, there were four keys for which the maximum subkey length was misreported, leading to the name lookup failing with the error ERROR_MORE_DATA. (Interestingly they were all within HKEY_LOCAL_MACHINE\SYSTEM\ControlSet00x, which makes me wonder whether they crept in during the backup of CurrentControlSet.) The only answer to this kind of bug is to make a workaround that will work for all operating-system versions, broken or not. The answer is in the new form of the _Reg_EnumKeyName() helper in Listing Two.
The new version of the function requires that a D character array (char[]) is passed as an inout parameter, whereas the original form just took a pointer to a fixed buffer. This change allows the buffer to be changed within the helper function, as you can see in the case where RegEnumKeyExA() returns ERROR_MORE_DATA. The array is resized by doubling in size until ERROR_MORE_DATA is not returned, using D's helpful array-length assignment.
DDJ
class null_iterator #if defined(_MSC_VER) && _MSC_VER < 1300 : public std::iterator #else : public std::iterator #endif { public: typedef void container_type; private: class proxy { public: template proxy& operator=(const _Ty&) { return *this; } }; public: proxy operator*() { return proxy(); } null_iterator& operator++() { return *this; } null_iterator operator++(int) { return *this; } bool operator==(const null_iterator&) const { return true; } bool operator!=(const null_iterator&) const { return false; } };Back to article
Listing Two
private LONG _Reg_EnumKeyName( in HKEY hkey , in DWORD index , inout char[] name , out DWORD cchName) in { assert(null !== hkey); assert(null !== name); assert(0 < name.length); } body { LONG res; for(;;) { cchName = name.length; res = RegEnumKeyExA(hkey, index, name , cchName, RESERVED, null, null, null); if(ERROR_MORE_DATA != res) { break; } else { // Increase the size of the buffer and try again name.length = 2 * name.length; } } return res; }Back to article