Musings of an STL-extension library designer (who's renowned for producing high-quality software with low-quality documentation).
Thursday, January 21, 2010
STLSoft 1.9.90: unixstl::filesystem_traits::get_full_path_name() defect fixed
Prior to version 1.9.90, unixstl::filesystem_traits::get_full_path_name() contained a defect, causing it to fault if passed "." - indicating the local directory - and instead contain spurious information. This is now fixed.
Tuesday, January 12, 2010
STLSoft 1.9.88: fixed conversion between const_reverse_iterator and reverse_iterator
For a long while, I've been aware of the limitations of the reverse iterator abstraction components in the STLSoft libraries - specifically and - which prevent assigning an instance of a collection's reverse_iterator to an instance of its const_reverse_iterator. This has caused trouble for me on occasion, and also for some users.
As of version 1.9.88 this has been addressed, via addition of conversion constructor template and operator != templates.
As of version 1.9.88 this has been addressed, via addition of conversion constructor template and operator != templates.
STLSoft 1.9.88: throwOnAccessFailure search flag for winstl::basic_findfile_sequence
As anticipated, winstl::basic_findfile_sequence, which is described in detail in Extended STL, volume 1, now defines, and responds to, the member constant throwOnAccessFailure. In the case of an access failure an instance of winstl::access_exception is thrown.
This allows for better response in cases where access may be denied.
This allows for better response in cases where access may be denied.
STLSoft 1.9.88: max_size() for file_path_buffer and path
As of version 1.9.88, winstl::basic_file_path_buffer now has a (static) max_size() method, and winstl::basic_path::max_size() is changed to be static.
STLSoft 1.9.88: all-integer handling for comstl::variant
The latest release (1.9.88) of STLSoft contains an updated comstl::variant class. The previous version had three constructors for integer types: short, int and long. The new version has six constructors for integer types: sint8_t, uint8_t, sint16_t, uint16_t, sint32_t, uint32_t. (It also has short, int and long constructors for those compilers that have distinct types against the 8/16/32-fixed integer types; see chapter 29 of Imperfect C++)
Monday, January 11, 2010
STLSoft 1.9.88 released
STLSoft 1.9.88 is released today.
This version will be required for forthcoming releases, including:
This version will be required for forthcoming releases, including:
- STLSoft (1.10)
- FastFormat
- Pantheios
- recls
- VOLE
Saturday, November 21, 2009
STLSoft 1.9.88 imminent
I'm just preparing a new release of recls, and in the process have needed to enhance winstl::basic_findfile_sequence, adding a new throwOnAccessFailure flag, which (as should be obvious from the name), causes an exception to be thrown in the event of access failure. This will allow consistent behaviour between recls (C/C++) and the new recls 100% .NET library.
Friday, May 29, 2009
frequency_map: new merge() method
The stlsoft::frequency_map container class template now includes a merge() method, which allows the contents from two frequency map instances to be merged into one, as in:
typedef std::string string_t;
typedef stlsoft::frequency_map<string_t> fmap_t;
fmap_t map1;
fmap_t map2;
map1.push("key-11");
map1.push("key-22");
XTESTS_TEST_BOOLEAN_FALSE(map1.empty());
XTESTS_TEST_INTEGER_EQUAL(2u, map1.size());
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-22"]);
map2.push("key-11");
map2.push("key-21");
XTESTS_TEST_BOOLEAN_FALSE(map2.empty());
XTESTS_TEST_INTEGER_EQUAL(2u, map2.size());
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-21"]);
map1.merge(map2);
XTESTS_TEST_BOOLEAN_FALSE(map1.empty());
XTESTS_TEST_INTEGER_EQUAL(3u, map1.size());
XTESTS_TEST_INTEGER_EQUAL(2u, map1["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-21"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-22"]);
XTESTS_TEST_BOOLEAN_FALSE(map2.empty());
XTESTS_TEST_INTEGER_EQUAL(2u, map2.size());
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-21"]);
map2.clear();
XTESTS_TEST_BOOLEAN_FALSE(map1.empty());
XTESTS_TEST_INTEGER_EQUAL(3u, map1.size());
XTESTS_TEST_INTEGER_EQUAL(2u, map1["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-21"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-22"]);
XTESTS_TEST_INTEGER_EQUAL(0u, map2.size());
XTESTS_TEST_BOOLEAN_TRUE(map2.empty());
typedef std::string string_t;
typedef stlsoft::frequency_map<string_t> fmap_t;
fmap_t map1;
fmap_t map2;
map1.push("key-11");
map1.push("key-22");
XTESTS_TEST_BOOLEAN_FALSE(map1.empty());
XTESTS_TEST_INTEGER_EQUAL(2u, map1.size());
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-22"]);
map2.push("key-11");
map2.push("key-21");
XTESTS_TEST_BOOLEAN_FALSE(map2.empty());
XTESTS_TEST_INTEGER_EQUAL(2u, map2.size());
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-21"]);
map1.merge(map2);
XTESTS_TEST_BOOLEAN_FALSE(map1.empty());
XTESTS_TEST_INTEGER_EQUAL(3u, map1.size());
XTESTS_TEST_INTEGER_EQUAL(2u, map1["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-21"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-22"]);
XTESTS_TEST_BOOLEAN_FALSE(map2.empty());
XTESTS_TEST_INTEGER_EQUAL(2u, map2.size());
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map2["key-21"]);
map2.clear();
XTESTS_TEST_BOOLEAN_FALSE(map1.empty());
XTESTS_TEST_INTEGER_EQUAL(3u, map1.size());
XTESTS_TEST_INTEGER_EQUAL(2u, map1["key-11"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-21"]);
XTESTS_TEST_INTEGER_EQUAL(1u, map1["key-22"]);
XTESTS_TEST_INTEGER_EQUAL(0u, map2.size());
XTESTS_TEST_BOOLEAN_TRUE(map2.empty());
Saturday, May 23, 2009
STLSoft 1.10 new additions: integer_to_array()
A new component with STLSoft 1.10 (alpha 11 onwards) is the stlsoft::integer_to_array() function template. It is used to turn a single integer value into an array of bit-chunk values.
For example, given the integer i with value 0x01020304, we can split this into the 8 nibbles as follows:
stlsoft::integer_array r = stlsoft::integer_to_array(i, 4);
r[0] will be 4, r[1] will be 0, r[2] will be 3, r[3] will be 0, r[4] will be 2, r[5] will be 0, r[6] will be 1, and r[7] will be 0.
The split can be on any value between 0 and the bitsize of the input parameter (which can be any of the integral types); so you can split on 3 bits, 1 bit, 17 bits, whatever.
I've done extensive automated tests, and they all pass (natch), but I'm still a little dubious about the component, so I'm definitely interested in feedback.
In case you're wondering, the original rationale for this was a simple way to go from the s_addr member of struct in_addr, which is held in network byte order but is otherwise "opaque".
For example, given the integer i with value 0x01020304, we can split this into the 8 nibbles as follows:
stlsoft::integer_array r = stlsoft::integer_to_array(i, 4);
r[0] will be 4, r[1] will be 0, r[2] will be 3, r[3] will be 0, r[4] will be 2, r[5] will be 0, r[6] will be 1, and r[7] will be 0.
The split can be on any value between 0 and the bitsize of the input parameter (which can be any of the integral types); so you can split on 3 bits, 1 bit, 17 bits, whatever.
I've done extensive automated tests, and they all pass (natch), but I'm still a little dubious about the component, so I'm definitely interested in feedback.
In case you're wondering, the original rationale for this was a simple way to go from the s_addr member of struct in_addr, which is held in network byte order but is otherwise "opaque".
LP64 and -Wshorten-64-to-32
Along with new Mac OS-X 64-bit makefiles for FastFormat and Pantheios, I'm also playing around with the -Wshorten-64-to-32 warning flag.
In compiling FF with this I encountered a lot of similars, amounting to the following:
enum { x = sizeof(Y) };
Obviously an enum, being int in size, is too small to hold size_t (the result of sizeof operator). The ugly but effective solution to this is:
enum { x = int(sizeof(Y)) };
which you'll now see more of in the STLSoft libs.
In compiling FF with this I encountered a lot of similars, amounting to the following:
enum { x = sizeof(Y) };
Obviously an enum, being int in size, is too small to hold size_t (the result of sizeof operator). The ugly but effective solution to this is:
enum { x = int(sizeof(Y)) };
which you'll now see more of in the STLSoft libs.
Friday, May 22, 2009
Safely abstracting use of strerror / strerror_s (part 1)
A recent bug report on the STLSoft SourceForge project site reported that the stlsoft::error_desc component did not use the new "safe string" library function strerror_s(). This was actually a surprise, because I thought I'd already taken care of that.
Since I hadn't, I decided that I should. The change in implementation to use strerror_s() (when in the presence of the "safe string" library) goes along the lines of the following
The dumb part of the strerror_s() function is that it doesn't tell you how many characters were received. This means that you cannot rely on having elicited the full message unless ::strlen() over the returned string is less than (buffer size - 1). So, the above code could return a partial error string (although the likelihood of that is, of course, vanishingly small).
Instead, what I've done is used an auto_buffer to provide resizable storage, and then strerror_s() is called in a loop until either it fails, or no more storage can be allocated, or the length of the returned string is less than (buffer size - 1). The code looks like the following:
There's another problem with the class template, but that'll have to wait until a later time to discuss ...
Since I hadn't, I decided that I should. The change in implementation to use strerror_s() (when in the presence of the "safe string" library) goes along the lines of the following
char buff[1001];
if(0 != ::strerror_s(buff,
STLSOFT_NUM_ELEMENTS(buff) - 1, errno))
{
buff[0] = '\0';
}
else
{
buff[STLSOFT_NUM_ELEMENTS(buff) - 1] = '\0';
}
The dumb part of the strerror_s() function is that it doesn't tell you how many characters were received. This means that you cannot rely on having elicited the full message unless ::strlen() over the returned string is less than (buffer size - 1). So, the above code could return a partial error string (although the likelihood of that is, of course, vanishingly small).
Instead, what I've done is used an auto_buffer to provide resizable storage, and then strerror_s() is called in a loop until either it fails, or no more storage can be allocated, or the length of the returned string is less than (buffer size - 1). The code looks like the following:
stlsoft::auto_bufferbuff(128);
for(;;)
{
int n = ::strerror_s(&buff[0], buff.size() - 1, error);
buff[buff.size() - 1u] = '\0';
if(0 == n)
{
size_t cch = ::strlen(buff.data());
if(cch < buff.size() - 2u)
{
m_length = cch;
buff.resize(cch + 1u);
break;
}
}
if(!buff.resize(1u + buff.size() * 2u))
{
buff.resize(1u);
break;
}
}
There's another problem with the class template, but that'll have to wait until a later time to discuss ...
Monday, May 18, 2009
WinSTL Registry library mods and fixes, part 3: exception-safety
In reviewing the implementation of the WinSTL Registry Library's winstl::basic_reg_value class - as described in part 1 and part 2 of this series of posts - I've also spotted a defect in exception-safety.
Consider the (chopped-down) definition of the basic_reg_value class:
The m_hkey member is obtained via winstl::reg_traits<>::reg_dup_key(). It is the basic_reg_value class itself that provides the RAII. Consequently, if any exception occur during its constructor, the release of m_hkey will not be carried out.
Since the m_name is a string class instance, its constructor can throw. Consequently, basic_reg_value is not exception safe.
Thankfully, the fix is very simple. Simply reverse the order of declaration of the two members. If m_name's constructor throws, that'll happen before the key duplication takes place. If the key duplication throws an exception, the (fully constructed) m_name's destructor will be invoked. Q.E.D.
Consider the (chopped-down) definition of the basic_reg_value class:
template < . . . >
class basic_reg_value
{
. . .
private:
hkey_type m_hkey; // The parent key of the value
string_type m_name; // The name of the value
. . . // other members
};
The m_hkey member is obtained via winstl::reg_traits<>::reg_dup_key(). It is the basic_reg_value class itself that provides the RAII. Consequently, if any exception occur during its constructor, the release of m_hkey will not be carried out.
Since the m_name is a string class instance, its constructor can throw. Consequently, basic_reg_value is not exception safe.
Thankfully, the fix is very simple. Simply reverse the order of declaration of the two members. If m_name's constructor throws, that'll happen before the key duplication takes place. If the key duplication throws an exception, the (fully constructed) m_name's destructor will be invoked. Q.E.D.
WinSTL Registry library mods and fixes, part 2: race conditions
As discussed at great length in section 33.3 of Extended STL, volume 1, the Windows Registry API is one that is prone to race conditions, due to the fact that separate processes may make independent changes to the registry contents without any control over each other.
The recently discovered defect in the WinSTL Registry Library's winstl::basic_reg_value class, gave me cause to consider the implementation in detail again. It's been a long time since I've done that, and with the understanding of the registry race-conditions I gained while researching and writing Extended STL, I saw immediately the possibility of such a race accounting for the reported fault.
Consider again the implementation of winstl::basic_reg_value<>::value_sz() method. Assume that prior to the invocation of winstl::reg_traits<>::reg_query_info that the registry-value's value was non-zero size. The call commences. Meanwhile, another process overwrites the registry-value, with a zero size. reg_query_info returns, and indicates that the data size is zero. Without a further check on the data size, the same fault will be experienced. Naturally, the fix for the non-race defect will fix the race one as well. Which is nice.
The recently discovered defect in the WinSTL Registry Library's winstl::basic_reg_value class, gave me cause to consider the implementation in detail again. It's been a long time since I've done that, and with the understanding of the registry race-conditions I gained while researching and writing Extended STL, I saw immediately the possibility of such a race accounting for the reported fault.
Consider again the implementation of winstl::basic_reg_value<>::value_sz() method. Assume that prior to the invocation of winstl::reg_traits<>::reg_query_info that the registry-value's value was non-zero size. The call commences. Meanwhile, another process overwrites the registry-value, with a zero size. reg_query_info returns, and indicates that the data size is zero. Without a further check on the data size, the same fault will be experienced. Naturally, the fix for the non-race defect will fix the race one as well. Which is nice.
Subscribe to:
Posts (Atom)