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);
}


No comments: