Checking in to continue working elsewhere.

This commit is contained in:
Neil MacIntosh 2016-02-28 00:50:53 -08:00
parent cc22f2bf42
commit 502cd6650a
2 changed files with 101 additions and 72 deletions

View File

@ -94,20 +94,22 @@ public:
constexpr static const index_type extent = Extent; constexpr static const index_type extent = Extent;
// [span.cons], span constructors, copy, assignment, and destructor // [span.cons], span constructors, copy, assignment, and destructor
constexpr span() noexcept : data_(nullptr), size_(0) constexpr span() noexcept : storage_(nullptr, extent_type<0>())
{ static_assert(extent == dynamic_extent || extent == 0, "Cannot default initialize a fixed-length span."); } {}
constexpr span(nullptr_t) noexcept : span() constexpr span(nullptr_t) noexcept : span()
{} {}
constexpr span(pointer ptr, index_type count) : data_(ptr), size_(count) constexpr span(pointer ptr, index_type count) : storage_(ptr, count)
{ Expects(((!ptr && count == 0) || (ptr && count >= 0)) && (extent == dynamic_extent || extent == count)); } { Expects(((!ptr && count == 0) || (ptr && count >= 0))); }
constexpr span(pointer firstElem, pointer lastElem) : data_(firstElem), size_(std::distance(firstElem, lastElem)) constexpr span(pointer firstElem, pointer lastElem)
{ Expects(size_ >= 0 && (extent == dynamic_extent || extent == size_)); } : storage_(firstElem, std::distance(firstElem, lastElem))
{}
template <size_t N> template <size_t N>
constexpr span(element_type(&arr)[N]) {} constexpr span(element_type(&arr)[N]) : storage_(&arr[0], extent_type<N>())
{}
#if 0 // TODO #if 0 // TODO
template <size_t N> template <size_t N>
@ -141,7 +143,7 @@ public:
#endif #endif
// [span.obs], span observers // [span.obs], span observers
constexpr index_type length() const noexcept { return size(); } constexpr index_type length() const noexcept { return size(); }
constexpr index_type size() const noexcept { return size_; } constexpr index_type size() const noexcept { return storage_.size(); }
constexpr index_type length_bytes() const noexcept { return size_bytes(); } constexpr index_type length_bytes() const noexcept { return size_bytes(); }
constexpr index_type size_bytes() const noexcept { return size() * sizeof(element_type); } constexpr index_type size_bytes() const noexcept { return size() * sizeof(element_type); }
constexpr bool empty() const noexcept { return size() == 0; } constexpr bool empty() const noexcept { return size() == 0; }
@ -149,11 +151,11 @@ public:
// [span.elem], span element access // [span.elem], span element access
constexpr reference operator[](index_type idx) const constexpr reference operator[](index_type idx) const
{ {
Expects(idx >= 0 && idx < size_); Expects(idx >= 0 && idx < storage_.size());
return data_[idx]; return storage_.data()[idx];
} }
constexpr reference operator()(index_type idx) const { return this->operator[](idx); } constexpr reference operator()(index_type idx) const { return this->operator[](idx); }
constexpr pointer data() const noexcept { return data_; } constexpr pointer data() const noexcept { return storage_.data(); }
#if 0 // TODO #if 0 // TODO
// [span.iter], span iterator support // [span.iter], span iterator support
iterator begin() const noexcept; iterator begin() const noexcept;
@ -169,8 +171,70 @@ public:
const_reverse_iterator crend() const noexcept; const_reverse_iterator crend() const noexcept;
#endif #endif
private: private:
pointer data_; template <index_type Extent>
class extent_type;
template <index_type Extent>
class extent_type
{
public:
static_assert(Extent >= 0, "A fixed-size span must be >= 0 in size.");
constexpr extent_type() noexcept {}
template <index_type Other>
constexpr extent_type(extent_type<Other>) noexcept
{
static_assert(Other == Extent,
"Mismatch between fixed-size extent and size of initializing data.");
}
constexpr extent_type(index_type size)
{ Expects(size == Extent); }
constexpr inline index_type size() const noexcept { return Extent; }
};
template <>
class extent_type<dynamic_extent>
{
public:
template <index_type Other>
explicit constexpr extent_type(extent_type<Other> ext) : size_(ext.size())
{}
explicit constexpr extent_type(index_type size) : size_(size)
{ Expects(size >= 0); }
constexpr inline index_type size() const noexcept
{ return size_; }
private:
index_type size_; index_type size_;
};
// this implementation detail class lets us take advantage of the
// empty base class optimization to pay for only storage of a single
// pointer in the case of fixed-size spans
template <class ExtentType>
class storage_type : public ExtentType
{
public:
template <class OtherExtentType>
storage_type(pointer data, OtherExtentType ext)
: ExtentType(ext), data_(data) {}
//storage_type(pointer data, ExtentType ext)
// : ExtentType(ext), data_(data) {}
constexpr inline pointer data() const noexcept
{ return data_; }
private:
pointer data_;
};
storage_type<extent_type<Extent>> storage_;
}; };

View File

@ -73,6 +73,19 @@ SUITE(span_tests)
} }
} }
TEST(size_optimization)
{
{
span<int> s;
CHECK(sizeof(s) == sizeof(int*) + sizeof(ptrdiff_t));
}
{
span<int, 0> s;
CHECK(sizeof(s) == sizeof(int*));
}
}
TEST(from_nullptr_constructor) TEST(from_nullptr_constructor)
{ {
{ {
@ -250,7 +263,7 @@ SUITE(span_tests)
// CHECK_THROW(workaround_macro(), fail_fast); // CHECK_THROW(workaround_macro(), fail_fast);
//} //}
} }
#if 0
TEST(from_array_constructor) TEST(from_array_constructor)
{ {
int arr[5] = {1, 2, 3, 4, 5}; int arr[5] = {1, 2, 3, 4, 5};
@ -265,10 +278,11 @@ SUITE(span_tests)
CHECK(s.length() == 5 && s.data() == &arr[0]); CHECK(s.length() == 5 && s.data() == &arr[0]);
} }
{ int arr2d[2][3] = { 1, 2, 3, 4, 5, 6 };
#ifdef CONFIRM_COMPILATION_ERRORS #ifdef CONFIRM_COMPILATION_ERRORS
{
span<int, 6> s{arr}; span<int, 6> s{arr};
#endif
} }
{ {
@ -276,8 +290,6 @@ SUITE(span_tests)
CHECK(s.length() == 0 && s.data() == &arr[0]); CHECK(s.length() == 0 && s.data() == &arr[0]);
} }
int arr2d[2][3] = {1, 2, 3, 4, 5, 6};
{ {
span<int> s{arr2d}; span<int> s{arr2d};
CHECK(s.length() == 6 && s.data() == &arr2d[0][0]); CHECK(s.length() == 6 && s.data() == &arr2d[0][0]);
@ -290,43 +302,17 @@ SUITE(span_tests)
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS span<int, 6> s{ arr2d };
span<int, 5> s{arr2d}; }
#endif #endif
}
{ {
span<int, 6> s{arr2d}; span<int[3]> s{ arr2d[0] };
CHECK(s.length() == 6 && s.data() == &arr2d[0][0]);
CHECK(s[0] == 1 && s[5] == 6);
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
span<int, 7> s{arr2d};
#endif
}
{
span<int[3]> s{arr2d[0]};
CHECK(s.length() == 1 && s.data() == &arr2d[0]); CHECK(s.length() == 1 && s.data() == &arr2d[0]);
} }
{
span<int, 2, 3> s{arr2d};
CHECK(s.length() == 6 && s.data() == &arr2d[0][0]);
auto workaround_macro = [&]() { return s[{1, 2}] == 6; };
CHECK(workaround_macro());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
span<int, 3, 3> s{arr2d};
#endif
}
int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; int arr3d[2][3][2] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
#ifdef CONFIRM_COMPILATION_ERRORS
{ {
span<int> s{arr3d}; span<int> s{arr3d};
CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]);
@ -339,9 +325,7 @@ SUITE(span_tests)
} }
{ {
#ifdef CONFIRM_COMPILATION_ERRORS
span<int, 11> s{arr3d}; span<int, 11> s{arr3d};
#endif
} }
{ {
@ -349,32 +333,13 @@ SUITE(span_tests)
CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]); CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]);
CHECK(s[0] == 1 && s[5] == 6); CHECK(s[0] == 1 && s[5] == 6);
} }
{
#ifdef CONFIRM_COMPILATION_ERRORS
span<int, 13> s{arr3d};
#endif #endif
}
{ {
span<int[3][2]> s{arr3d[0]}; //span<int[3][2]> s{arr3d[0]};
CHECK(s.length() == 1 && s.data() == &arr3d[0]); //CHECK(s.length() == 1 && s.data() == &arr3d[0]);
}
{
span<int, 3, 2, 2> s{arr3d};
CHECK(s.length() == 12 && s.data() == &arr3d[0][0][0]);
auto workaround_macro = [&]() { return s[{2, 1, 0}] == 11; };
CHECK(workaround_macro());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
span<int, 3, 3, 3> s{arr3d};
#endif
} }
} }
#if 0
TEST(from_dynamic_array_constructor) TEST(from_dynamic_array_constructor)
{ {
double(*arr)[3][4] = new double[100][3][4]; double(*arr)[3][4] = new double[100][3][4];