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