Added span to object rep conversions.

This commit is contained in:
Neil MacIntosh 2016-05-29 17:06:29 -07:00
parent d63c9803da
commit ba8ebef509
4 changed files with 124 additions and 38 deletions

33
include/byte.h Normal file
View File

@ -0,0 +1,33 @@
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GSL_BYTE_H
#define GSL_BYTE_H
namespace gsl
{
// This is a simple definition for now that allows
// use of byte within span<> to be standards-compliant
//
// Ultimately a small language change would allow a more
// robust definition (see WG21 proposal P0257 for details).
using byte = unsigned char;
} // namespace gsl
#endif // GSL_BYTE_H

View File

@ -21,6 +21,7 @@
#include "gsl_assert.h" #include "gsl_assert.h"
#include "gsl_util.h" #include "gsl_util.h"
#include "byte.h"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cassert> #include <cassert>
@ -1053,9 +1054,6 @@ template <typename Span>
class contiguous_span_iterator; class contiguous_span_iterator;
template <typename Span> template <typename Span>
class general_span_iterator; class general_span_iterator;
enum class byte : std::uint8_t
{
};
template <std::ptrdiff_t DimSize = dynamic_range> template <std::ptrdiff_t DimSize = dynamic_range>
struct dim struct dim

View File

@ -21,6 +21,7 @@
#include "gsl_assert.h" #include "gsl_assert.h"
#include "gsl_util.h" #include "gsl_util.h"
#include "byte.h"
#include <array> #include <array>
#include <limits> #include <limits>
#include <iterator> #include <iterator>
@ -126,13 +127,13 @@ struct is_allowed_element_type_conversion
}; };
template <class From> template <class From>
struct is_allowed_element_type_conversion<From, char> struct is_allowed_element_type_conversion<From, byte>
: std::integral_constant<bool, !std::is_const<From>::value> : std::integral_constant<bool, !std::is_const<From>::value>
{ {
}; };
template <class From> template <class From>
struct is_allowed_element_type_conversion<From, const char> struct is_allowed_element_type_conversion<From, const byte>
: std::integral_constant<bool, true> : std::integral_constant<bool, true>
{ {
}; };
@ -507,14 +508,33 @@ constexpr bool operator>=(const span<ElementType, Extent>& l, const span<Element
{ return !(l < r); } { return !(l < r); }
#if 0 // TODO namespace details
{
// if we only supported compilers with good constexpr support then
// this pair of classes could collapse down to a constexpr function
// we should use a narrow_cast<> to go to size_t, but older compilers may not see it as constexpr
// and so will fail compilation of the template
template <class ElementType, ptrdiff_t Extent>
struct calculate_byte_size :
std::integral_constant<std::ptrdiff_t, static_cast<ptrdiff_t>(sizeof(ElementType) * static_cast<size_t>(Extent))>
{};
template <class ElementType>
struct calculate_byte_size<ElementType, dynamic_extent> :
std::integral_constant<std::ptrdiff_t, dynamic_extent>
{};
}
// [span.objectrep], views of object representation // [span.objectrep], views of object representation
template <class ElementType, ptrdiff_t Extent> template <class ElementType, ptrdiff_t Extent>
constexpr span<const char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_bytes(span<ElementType, Extent> s) noexcept; constexpr span<const byte, details::calculate_byte_size<ElementType, Extent>::value> as_bytes(span<ElementType, Extent> s) noexcept
{ return {reinterpret_cast<const byte*>(s.data()), s.size_bytes()}; }
template <class ElementType, ptrdiff_t Extent> template <class ElementType, ptrdiff_t Extent, class = std::enable_if_t<!std::is_const<ElementType>::value>>
constexpr span<char, ((Extent == dynamic_extent) ? dynamic_extent : (sizeof(ElementType) * Extent))> as_writeable_bytes(span<ElementType, Extent>) noexcept; constexpr span<byte, details::calculate_byte_size<ElementType, Extent>::value> as_writeable_bytes(span<ElementType, Extent> s) noexcept
#endif { return {reinterpret_cast<byte*>(s.data()), s.size_bytes()}; }
} // namespace gsl } // namespace gsl

View File

@ -921,6 +921,69 @@ SUITE(span_tests)
} }
} }
TEST(as_bytes)
{
int a[] = {1, 2, 3, 4};
{
span<const int> s = a;
CHECK(s.length() == 4);
span<const byte> bs = as_bytes(s);
CHECK(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data()));
CHECK(bs.length() == s.length_bytes());
}
{
span<int> s;
auto bs = as_bytes(s);
CHECK(bs.length() == s.length());
CHECK(bs.length() == 0);
CHECK(bs.size_bytes() == 0);
CHECK(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data()));
CHECK(bs.data() == nullptr);
}
{
span<int> s = a;
auto bs = as_bytes(s);
CHECK(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data()));
CHECK(bs.length() == s.length_bytes());
}
}
TEST(as_writeable_bytes)
{
int a[] = {1, 2, 3, 4};
{
#ifdef CONFIRM_COMPILATION_ERRORS
// you should not be able to get writeable bytes for const objects
span<const int> s = a;
CHECK(s.length() == 4);
span<const byte> bs = as_writeable_bytes(s);
CHECK(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
CHECK(bs.length() == s.length_bytes());
#endif
}
{
span<int> s;
auto bs = as_writeable_bytes(s);
CHECK(bs.length() == s.length());
CHECK(bs.length() == 0);
CHECK(bs.size_bytes() == 0);
CHECK(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
CHECK(bs.data() == nullptr);
}
{
span<int> s = a;
auto bs = as_writeable_bytes(s);
CHECK(static_cast<void*>(bs.data()) == static_cast<void*>(s.data()));
CHECK(bs.length() == s.length_bytes());
}
}
#if 0 #if 0
TEST(fixed_size_conversions) TEST(fixed_size_conversions)
{ {
@ -1018,34 +1081,6 @@ SUITE(span_tests)
CHECK_THROW(f(), fail_fast); CHECK_THROW(f(), fail_fast);
} }
TEST(as_writeable_bytes)
{
int a[] = {1, 2, 3, 4};
{
#ifdef CONFIRM_COMPILATION_ERRORS
// you should not be able to get writeable bytes for const objects
span<const int, dynamic_range> av = a;
auto wav = av.as_writeable_bytes();
#endif
}
{
span<int, dynamic_range> av;
auto wav = as_writeable_bytes(av);
CHECK(wav.length() == av.length());
CHECK(wav.length() == 0);
CHECK(wav.size_bytes() == 0);
}
{
span<int, dynamic_range> av = a;
auto wav = as_writeable_bytes(av);
CHECK(wav.data() == (byte*) &a[0]);
CHECK(wav.length() == sizeof(a));
}
}
#endif #endif
} }