Thursday, October 27, 2011

range copy

The range library proposal for the std library included copy_range which required that the dest range have a constructor that took begin and end iterators. This was not applicable to C struct ranges like UNICODE_STRING.

I decided to fix this by following the pattern for the begin and end free-functions. A free-function named copy calls a free-function named range_copy via ADL that can be overloaded for each Range type. The default range_copy has the same behavior that the proposed copy_range provided, but now other range_copy overloads can be written.

UNICODE_STRING usage

This snippet shows some of the operations now enabled.

auto helloRange = as_literal(L"hello");
auto title = copy<std::wstring>(helloRange);

auto unicodeHello = copy<UNICODE_STRING>(helloRange);
auto stringRange = make_range(unicodeHello);
auto unicodeTitle = copy<UNICODE_STRING>(
    make_range_raw(title)
    );
stringRange = make_range(unicodeTitle);
  • line 1 will make a range<const wchar_t*> that points to the static string array.
  • line 2 will make a std::wstring that holds a copy of the static string array.
  • line 4 will make a UNICODE_STRING that points to the static string array.
  • line 5 will make a range<PWSTR> that points to the static string array.
  • line 6 will make a UNICODE_STRING that points to the wstring copy of the static string array.
  • line 9 will make a range<PWSTR> that points to the wstring copy of the static string array.

Implementation

maintained here

template< class RangeTo, class RangeFrom >
auto range_copy(RangeFrom && r, RangeTo*) ->
decltype(
  RangeTo(
      begin(std::forward<RangeFrom>(r)),
      end(std::forward<RangeFrom>(r))
  )
)
{
  return RangeTo(
      begin(std::forward<RangeFrom>(r)),
      end(std::forward<RangeFrom>(r))
      );
}

template< class RangeTo, class RangeFrom >
auto copy(RangeFrom && r) ->
decltype(
  range_copy(
      std::forward<RangeFrom>(r),
      reinterpret_cast<RangeTo*>(nullptr)
  )
)
{
  return range_copy(
      std::forward<RangeFrom>(r),
      reinterpret_cast<RangeTo*>(nullptr)
      );
}

line 27 passes in a nullptr cast to a RangeTo* this dummy parameter is ugly but required to enable Argument-Dependent-Lookup (ADL) when range_copy is implemented in RangeTo's namespace. I considered using the parameter rather than returning a RangeTo by-value, but then RangeTo must be default-constructable since the copy free-function would have to have one on the stack in order to pass a pointer into range_copy. The current definition allows the overload for RangeTo to use any constructor.

UNICODE_STRING implementation

Now enabling UNICODE_STRING for use with the range library requires only this

// enable UNICODE_STRING <-> range

PWSTR range_begin(const UNICODE_STRING& string)
{
  return string.Buffer;
}

PWSTR range_end(const UNICODE_STRING& string)
{
  return string.Buffer + (string.Length / 2);
}

template< class RangeFrom >
UNICODE_STRING range_copy(
  RangeFrom && r,
  UNICODE_STRING*
)
{
  UNICODE_STRING result = {};

  result.Buffer = const_cast<PWSTR>(
      begin(std::forward<RangeFrom>(r))
      );
  result.Length = size_cast<USHORT>(
      size(std::forward<RangeFrom>(r)) * 2
      );
  result.MaximumLength = size_cast<USHORT>(
      size(std::forward<RangeFrom>(r)) * 2
      );

  return result;
}

No comments:

Post a Comment