Friday, June 12, 2020

STLSoft 1.9.133 released

Available at GitHub.

Added support for the ARM architecture when doing Android NDK GCC compilation (kindly provided by christopherplawrence)

Remember: STLSoft-1.10 is the latest and preferred.


Tuesday, October 15, 2019

COM VARIANT nameless union discrimination

Aficionados of COM may remember - because it's been a while, hey? - that the VARIANT structure is a composite of nested union and struct aggregates, as in:

typedef struct tagVARIANT { union { struct { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { LONGLONG llVal; LONG lVal; BYTE bVal; SHORT iVal; FLOAT fltVal;
. . . // and lots more members USHORT *puiVal; ULONG *pulVal; ULONGLONG *pullVal; INT *pintVal; UINT *puintVal; struct { PVOID pvRecord; IRecordInfo *pRecInfo; } __VARIANT_NAME_4; } __VARIANT_NAME_3; } __VARIANT_NAME_2; DECIMAL decVal; } __VARIANT_NAME_1; } VARIANT;

(The full definition is given in https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant.)

The relevant aspect(s) for this post is the apparent use of member names for the anonymous struct/union aggregates - __VARIANT_NAME_1, __VARIANT_NAME_2, etc. They are present because anonymous aggregates are not standard C++ and, prior to C11, were not part of standard C, even though they are commonly supported on many compilers: on supporting compilers, the apparent names are #defined to nothing; on non-supporting compilers they are #defined to, respectively, n1, n2, n3, brecVal, as in:


#if ... some condition ...
# define __VARIANT_NAME_1 n1
# define __VARIANT_NAME_2 n2
# define __VARIANT_NAME_3 n3
# define __VARIANT_NAME_4 brecVal
#else
# define __VARIANT_NAME_1
# define __VARIANT_NAME_2
# define __VARIANT_NAME_3
# define __VARIANT_NAME_4
#endif

This is all fine and well, except when you're writing COM code to work in C++ as well as in C, as is done for various components within the COMSTL project, as in the comstl_C_DECIMAL_compare() function (in comstl/util/DECIMAL_functions.h):

int
comstl_C_DECIMAL_compare(
    DECIMAL const* lhs
,   DECIMAL const* rhs
) /* noexcept */
{
  . . .

    COMSTL_ACCESS_VARIANT_vt_BYPTR(&vdecL) = VT_DECIMAL;
    COMSTL_ACCESS_VARIANT_decVal_BYPTR(&vdecL) = *lhs;

  . . .
}


In order to make it compile for both C and C++, the function is implemented in terms of COMSTL macros such as COMSTL_ACCESS_VARIANT_vt_BYREF(), which is defined as:

#if defined(COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_)

# define COMSTL_ACCESS_VARIANT_vt_BYPTR(pvar) \
           (pvar)->__VARIANT_NAME_1.__VARIANT_NAME_2.vt
#else

# define COMSTL_ACCESS_VARIANT_vt_BYPTR(pvar) (pvar)->vt
#endif

If the (internal / undocumented) COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_ macro is defined, then COMSTL_ACCESS_VARIANT_vt_BYPTR() obtains the vt member via the full retinue of named members; if not, then it obtains vt directly.

So, the question is, how is the COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_ macro discriminated?

It is defined in comstl/comstl.h, and up to STLSoft 1.10.1 beta-16, it was done as:

#if !defined(COMSTL_ASSUME_VARIANT_UNION_FORCE_ARMS_HAVE_NAMES) && \
    defined(_FORCENAMELESSUNION) && \
    !defined(NONAMELESSUNION)

# define COMSTL_ASSUME_VARIANT_UNION_FORCE_ARMS_HAVE_NAMES
#endif

#if defined(COMSTL_ASSUME_VARIANT_UNION_FORCE_ARMS_HAVE_NAMES)

# define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
#elif defined(STLSOFT_COMPILER_IS_GCC)

   /* GCC has different definitions to the other compilers, so have to treat
    * differently
    */
# if defined(NONAMELESSUNION)

#  define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
# endif /* NONAMELESSUNION */
#else /* ? compiler */

   /* Other compilers use the MS headers, which test against __STDC__,
    * _FORCENAMELESSUNION and NONAMELESSUNION
    */
# if (  __STDC__ && \
        !defined(_FORCENAMELESSUNION)) || \
     defined(NONAMELESSUNION)

#  define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
# endif /* (  __STDC__ && !_FORCENAMELESSUNION) || NONAMELESSUNION */
#endif /* compiler */

However, when compiling for MinGW GCC 8.1 today, this no longer suffices.

Searching the web for _FORCENAMELESSUNION and NONAMELESSUNION yielded little, so I did a thorough search of the implementation headers for a bunch of compilers and the Windows SDK, in order to get a (more) complete and up-to-date definition, arriving at the following - hopefully final - definition, which will appear in STLSoft 1.10.1 beta-17:

#if 1 && \
    !defined(COMSTL_ASSUME_VARIANT_UNION_FORCE_ARMS_HAVE_NAMES) && \
    !defined(_FORCENAMELESSUNION) && \
    defined(NONAMELESSUNION) && \
    1

# define COMSTL_ASSUME_VARIANT_UNION_FORCE_ARMS_HAVE_NAMES
#endif


#if 0
#elif defined(_FORCENAMELESSUNION)

#elif defined(COMSTL_ASSUME_VARIANT_UNION_FORCE_ARMS_HAVE_NAMES)

# define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
#else

 /* The observed extant discriminations are:
  *
  * 1 (VC++ 6):
  *
  *  (__STDC__ && !defined(_FORCENAMELESSUNION)) || defined(NONAMELESSUNION)
  *
  * 2 (*):
  *
  *  (__STDC__ && !defined(_FORCENAMELESSUNION)) || defined(NONAMELESSUNION) || (!defined(_MSC_EXTENSIONS) && !defined(_FORCENAMELESSUNION))
  *
  * 3 (MinGW GCC 4.9):
  *
  *  NONAMELESSUNION
  *  
  * 4 (MinGW GCC 8.1):
  *
  *  (__STDC__ && !defined(__cplusplus) && !defined(_FORCENAMELESSUNION)) || defined(NONAMELESSUNION) || (defined (_MSC_VER) && !defined(_MSC_EXTENSIONS) && !defined(_FORCENAMELESSUNION))
  *
  * which may be better understood as:
  *
  * 1 (VC++ 6):

    0 ||

    defined(NONAMELESSUNION) ||

    (  __STDC__ && \
        !defined(_FORCENAMELESSUNION)) ||
    
    0
  *
  * 2 (*):

    0 ||

    defined(NONAMELESSUNION) ||

    (   __STDC__ &&
        !defined(_FORCENAMELESSUNION)) ||

    (   !defined(_MSC_EXTENSIONS) &&
        !defined(_FORCENAMELESSUNION)) ||

    0
  *
  * 3 (MinGW GCC 4.9):

    0 ||

    defined(NONAMELESSUNION) ||

    0

  * 4 (MinGW GCC 8.1):


    0 ||

    defined(NONAMELESSUNION) ||

    (   __STDC__ &&
        !defined(__cplusplus) &&
        !defined(_FORCENAMELESSUNION)) ||

    (   defined (_MSC_VER) &&
        !defined(_MSC_EXTENSIONS) &&
        !defined(_FORCENAMELESSUNION)) ||

    0
  */

# if 0
# elif defined(NONAMELESSUNION)

#  define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
# elif defined(STLSOFT_COMPILER_IS_GCC)

#  if STLSOFT_GCC_VER >= 80000 /* NOTE: this number may be wrong - too large, but still old way with 4.9 */

#   if 0
#   elif __STDC__ && \
         !defined(__cplusplus) && \
         !defined(_FORCENAMELESSUNION)

#    define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
#   elif defined(_MSC_VER) && \
         !defined(_MSC_EXTENSIONS) && \
         !defined(_FORCENAMELESSUNION)

#    define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
#   endif /* ? GCC version */
#  endif
# elif __STDC__ && \
       defined(_FORCENAMELESSUNION)

#  define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
# elif !defined(_MSC_EXTENSIONS) && \
       !defined(_FORCENAMELESSUNION)

#  define COMSTL_VARIANT_UNION_ARMS_HAVE_NAMES_
# endif
#endif

If anyone else needs to understand _FORCENAMELESSUNION and NONAMELESSUNION, I hope this post can help.

Sunday, October 13, 2019

STLSoft 1.10.1 beta-16 : added stlsoft::count_bits(int)

In the recent 1.10.1-beta16 release of STLSoft, one of the changes was a minor enhancement to the stlsoft::count_bits() function suite, to make working with enumerations simpler.

The prior release(s) contained the following overloads of stlsoft::count_bits():

unsigned
count_bits(
  uint32_t v
) /* noexcept */
;

unsigned
count_bits(
  uint64_t v
) /* noexcept */
;

Pretty discoverable - either pass a 32-bit or a 64-bit unsigned integer. All the use-cases up to now for which I've needed this function have involved one of those types.

However, a new, and probably widely-applicable, use-case popped up. I have a CLI Windows program pown that prints the ownership of a file/directory. It recognises a number of CLI flags, some of which are mutually exclusive, and combines them into a flags parameter (of type int)  that is then passed into the program logic.

Some of the mutually-exclusive flag pertain to how the file path should be shown:


CLI flag Enumerator
'--show-file-rel-path' POWN_F_SHOW_FILE_REL_PATH (0x0010)
'--show-file-path' POWN_F_SHOW_FILE_PATH (0x0020)
'--show-file-stem' POWN_F_SHOW_FILE_STEM (0x0040)

POWN_F_SHOW_FILE_MASK_ (0x00f0)

The last enumerator, POWN_F_SHOW_FILE_MASK_,  is a mask for the show-file flags. In order to verify that, at most, a single relevant flag had been specified was code such as the following:

if (stlsoft::count_bits(flags & POWN_F_SHOW_FILE_MASK_) > 1)
{
  . . . // issue contingent report, and ...

  return EXIT_FAILURE; // ... exit the program
}

Neither of the two extant overloads was a best fit, to the compiler said no.

What I needed was an overload that takes an int. But which overload should it invoke?

I could just cast an int to  a uint64_t, but I didn't want to risk any performance costs in code generation in any of the many (versions of) compilers that are supported. Instead, it felt like an opportunity for some, admittedly pretty simple, template metaprogramming.

Without further ado, here's the implementation (with documentation and other stuff elided for brevity):


#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION

template <size_t N_bytes>


unsigned
count_bits_int_(
  int v
);

template <>
unsigned
count_bits_int_<4>(
  int v
)
{
  return count_bits(static_cast(v));
}

template <>
unsigned
count_bits_int_<8>(
  int v
)
{
  return count_bits(static_cast(v));
}
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */

unsigned
count_bits(
  int v
)
{
  return count_bits_int_<sizeof(int)>(v);
}


STLSoft 1.10.1 (beta 16) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-16.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta16; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-16 branch (as in "$ git checkout -b beta-10 origin/beta-16").

Changes

The substantive changes are:
  • added stlsoft_C_environment_variable_exists_a() / environment_variable_exists() (from STLSoft 1.10-alpha)
  • added stlsoft::count_bits(int) overload
  • added cbegin()cend()crbegin()crend() to platformstl::environment_map
  • significant additions and removals of WinSTL file creation functions
  • added WinSTL security functions (from STLSoft 1.10-alpha)
  • automatic recognising Mac OSX architecture as UNIX
  • canonicalising '\file' description sections
  • suppresses deprecation warning from reporting use of deprecated functions inside other deprecated functions.
I'll describe some these changes in future blog posts.

Friday, September 13, 2019

STLSoft 1.10.1 (beta 15) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-15.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta15; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-15 branch (as in "$ git checkout -b beta-10 origin/beta-15").

Changes

The substantive changes are:
  • added stlsoft::fast_strftime() and stlsoft::fast_wcsftime() as drop-in replacements for std::strftime() and std::wcsftime();
  • added stlsoft::get_ptr() shim overload for std::shared_ptr and std::unique_ptr
  • added stlsoft::get_top() attribute shim, which obtains the front/top element of a non-empty container;
  • added stlsoft::basic_string_view<>::substr() method;
  • added winstl_C_format_message_strerror_w();
  • removed stlsoft::literal_cast<>;
  • various portability improvements to newer compilers.
I'll describe these changes in a future blog post.

Sunday, August 4, 2019

STLSoft 1.10.1 (beta 14) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-14.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta14; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-14 branch (as in "$ git checkout -b beta-10 origin/beta-14").

Changes

The substantive changes are:
  • added SECURITY_DESCRIPTOR helpers() winstl::get_SECURITY_DESCRIPTOR() and winstl::free_SECURITY_DESCRIPTOR();
  • stlsoft::multibyte2wide (aka stlsoft::m2w) and stlsoft::wide2multibyte (aka stlsoft::w2m) are now more general: no longer implemented in terms of stlsoft::c_str_data(), stlsoft::c_str_ptr(), or stlsoft::c_str_len(), but their encoding-specific forms (i.e. _w() / _a()).
I'll describe these changes in a future blog post.

Tuesday, April 16, 2019

STLSoft 1.10.1 (beta 13) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-13.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta13; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-13 branch (as in "$ git checkout -b beta-10 origin/beta-13").

Changes

The substantive changes are:
  • fixed STLSOFT_ALWAYS_FALSE() / STLSOFT_ALWAYS_TRUE();
  • fixed character-encoding function selection defect in platformstl::FILE_stream;
  • canonicalised source file structure.

Wednesday, December 26, 2018

STLSoft 1.10.1 (beta 12) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-12.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta12; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-12 branch (as in "$ git checkout -b beta-10 origin/beta-12").

Changes

The substantive changes are:
  • added stlsoft::sas_to_string() (and related - _m and _w form) function templates, which create instances of std::basic_string<> by applying String Access Shims to the given parameter;
  • added stlsoft::errno_exception exception class (from the 1.12 branch);
  • added stlsoft::locale_scope scoping class;
  • STLSoft's struct tm String Access Shims now work for arbitrary locale;
  • UNIXSTL's timeval String Access Shims now work for arbitrary locale.

I'll describe these changes in a future blog post.

Saturday, December 22, 2018

STLSoft 1.10.1 (beta 11) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-11.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta11; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-11 branch (as in "$ git checkout -b beta-10 origin/beta-11").

Changes

The substantive changes are:

  • stlsoft::ref_ptr<> class template now has two creator template functions borrow() and own();
  • winstl::environment_variable now has the additional methods:
    • data();
    • equal();
    • equal_ignore_case();
    • exists(); and
    • operator ==() and operator !=().
I'll describe these changes in a future blog post.

Friday, December 21, 2018

STLSoft 1.10.1 (beta 10) released

The latest beta of STLSoft 1.10.1 is available, at https://github.com/synesissoftware/STLSoft-1.10/tree/beta-10.

Getting the beta

As usual, there are two ways to obtain the latest beta:
  1. Select one of the release archives (.zip, .tar.gz) at https://github.com/synesissoftware/STLSoft-1.10/releases/tag/1.10.1-beta10; or
  2. Clone the repo https://github.com/synesissoftware/STLSoft-1.10 and checkout the beta-10 branch (as in "$ git checkout -b beta-10 origin/beta-10").

Changes

The substantive changes are:
  • winstl::process_mutex() now provides two additional ctor overloads that take an additional HANDLE parameter to pass an event that will be signalled in case of an ABANDONED wait, which should (almost) always be treated as a terminal condition. This means that crucial mutex instances may now be connected to a shutdown event;
  • Special String Instances - those types generated by specialisations of stlsoft::special_string_instance_0 and stlsoft::special_string_instance_1 - are now automatically provided (in)equality operators: operator ==() and operator !=(). There are a bunch of such types, including (along with all their _a and _w variants):
    • unixstl::current_directory;
    • unixstl::home_directory;
    • winstl::absolute_path;
    • winstl::current_directory;
    • winstl::home_directory;
    • winstl::host_name;
    • winstl::module_directory;
    • winstl::module_filename;
    • winstl::system_directory;
    • winstl::temporary_directory;
    • winstl::temporary_file_name;
    • winstl::user_name; and
    • winstl::windows_directory.
These will be explained below with a few short examples.

Examples

Process Mutex abandonment

The Old New Thing's "Understanding the consequences of WAIT_ABANDONED" explains the situation well, so I won't repeat here. I'll just include code from a component test for the new functionality in winstl::process_mutex():

    SECTION("waiting on an abandoned mutex with an event") {

        winstl::event         ev(true, false);

        winstl::process_mutex mx(L"my-mx", false, nullptr, ev.handle());

        CHECK(!mx.abandoned());

        std::thread thread([&] {

            mx.lock(); // acquire but don't release, then quit (=> abandon)
        });

        thread.join();

        CHECK(mx.try_lock()); // acquire, which notes the abandonment

        DWORD const r = ::WaitForSingleObject(ev.handle(), 0);

        CHECK(WAIT_OBJECT_0 == r);

        CHECK(mx.abandoned());
    }

FYI: we're changing over to using the Catch Unit-testing library for STLSoft 1.10. (Still currently using Catch v1, tho ...)

Special String Instance(s)

Simply, where (in)equality-comparison would previously have been manual tasks, as in:

  unixstl::current_directory cwd;

  if (0 == ::strcmp("/Users/matt/dev/STLSoft/Releases/1.10", cwd.c_str())
  {}

and

  winstl::current_directory cwd;

  if (0 != ::stricmp("C:\\Users\\matt\\dev\\STLSoft\\Releases\\1.10", cwd.c_str())
  {}

they are now provided with a natural syntax (due to internal use of String Access Shims):

  unixstl::current_directory cwd;

  if ("/Users/matt/dev/STLSoft/Releases/1.10" == cwd)
  {}


and

  winstl::current_directory cwd;

  if (cwd != "C:\\Users\\matt\\dev\\STLSoft\\Releases\\1.10")
  {}


Note that the case-sensitivity is handled automatically. Hence winstl::current_directory's specialising policy template now includes the member constant caseSensitive, which is now required by the special string instance class templates:

  template <typename C>
  struct cwd_policy
  {
    typedef C                         char_type;
    typedef processheap_allocator<C>  allocator_type;
    typedef size_t                    size_type;
    typedef size_type               (*pfn_type)(char_type *, size_type);

    enum { internalBufferSize       =   128 };
    enum { allowImplicitConversion  =   1   };
    enum { caseSensitive            =   0   };
    enum { sharedState              =   0   };

    static pfn_type get_fn()
    {
      return winstl::filesystem_traits::get_current_directory;
    }
  };


There's a further benefit in that the comparisons are all length-aware, so that (tiny) bit more efficient. Which is nice.






Sunday, September 27, 2015

GitHub access

STLSoft GitHub access now at:



Fork away!


STLSoft 1.9.121 released

Download from https://sourceforge.net/projects/stlsoft/files/

============================================================================


Changes for 1.9.121 (26th September 2015)


STLSoft:
========

~ stlsoft/conversion/char_conversions.hpp:
~ stlsoft/conversion/truncation_test.hpp:
+ stlsoft/internal/cccap/clang.h:
~ stlsoft/util/integral_printf_traits.hpp:
~ stlsoft/util/limit_traits.h:
~ stlsoft/util/std/iterator_helper.hpp:

+ Clang-compatibility


WinSTL:
=======

~ winstl/util/struct_initialisers.hpp:

~ VC++ 11/12/14 compatibility


============================================================================


Monday, May 21, 2012

Extended Radio Silence - ending in Q3 2012

To anyone who's still following any of my public works - FastFormat, Pantheios, STLSoft, Breaking Up The Monolith, Quality Matters, VOLE, etc. - and wondering whether these activities are permanently moribund, I want to let you know that I'll soon be free of a very intense and overwhelmingly consuming commercial engagement over the last 2.5 years, and the second half of this year should see much activity in open-source, commercial, and writing activities.

Cheers

Matt