Add more features to span and unit tests (#5002)

* Add more span util and test

* apply review suggestions

* add throw in at operator in span

Co-authored-by: Patryk Elszkowski <patryk.elszkowki@intel.com>
This commit is contained in:
Patryk Elszkowski 2021-04-02 13:47:35 +02:00 committed by GitHub
parent 440d2abd1f
commit 60bd0178a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 259 additions and 2 deletions

View File

@ -6,6 +6,7 @@
#include <iterator>
#include <limits>
#include <stdexcept>
#include <type_traits>
namespace ngraph
@ -81,9 +82,21 @@ namespace ngraph
constexpr Element& front() const noexcept { return *m_data; }
constexpr Element& back() const noexcept { return *(m_data + (m_size - 1)); }
constexpr Element& operator[](std::size_t idx) const { return *(m_data + idx); }
Element& at(std::size_t idx) const { return *(m_data + idx); }
Element& at(std::size_t idx) const
{
if (idx >= m_size)
{
throw std::out_of_range{"index out of range"};
}
return *(m_data + idx);
}
/**
* @brief return sub part of span starting from offset and not greater than size
*
*/
Span subspan(std::size_t offset,
std::size_t size = std::numeric_limits<std::size_t>::max())
std::size_t size = std::numeric_limits<std::size_t>::max()) const
{
if (offset > m_size)
{
@ -92,6 +105,41 @@ namespace ngraph
return {m_data + offset, std::min(size, m_size - offset)};
}
/**
* @brief drop number of elements from front
*
*/
Span& drop_front(std::size_t number_of_elements)
{
if (number_of_elements < m_size)
{
m_data += number_of_elements;
m_size -= number_of_elements;
}
else
{
m_size = 0;
}
return *this;
}
/**
* @brief drop number of elements from back
*
*/
Span& drop_back(std::size_t number_of_elements)
{
if (number_of_elements < m_size)
{
m_size -= number_of_elements;
}
else
{
m_size = 0;
}
return *this;
}
private:
Element* m_data{nullptr};
std::size_t m_size{0};

View File

@ -90,6 +90,7 @@ set(SRC
provenance.cpp
replace_node.cpp
shape.cpp
span.cpp
specialize_function.cpp
tensor.cpp
type_prop/assign.cpp

208
ngraph/test/span.cpp Normal file
View File

@ -0,0 +1,208 @@
// Copyright (C) 2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "gtest/gtest.h"
#include <algorithm>
#include <array>
#include <vector>
#include "ngraph/runtime/reference/utils/span.hpp"
using namespace ngraph::runtime::reference;
TEST(span_util, create_from_vector)
{
std::vector<int> data{1, 2, 3, 4};
const auto s = span(data);
ASSERT_EQ(s.size(), data.size());
EXPECT_TRUE(std::equal(begin(data), end(data), begin(s)));
const auto si = span(begin(data), end(data));
ASSERT_EQ(si.size(), data.size());
EXPECT_TRUE(std::equal(begin(data), end(data), begin(si)));
}
TEST(span_util, create_from_const_vector)
{
const std::vector<int> data{1, 2, 3, 4};
const auto s = span(data);
ASSERT_EQ(s.size(), data.size());
EXPECT_TRUE(std::equal(begin(data), end(data), begin(s)));
const auto si = span(begin(data), end(data));
ASSERT_EQ(si.size(), data.size());
EXPECT_TRUE(std::equal(begin(data), end(data), begin(si)));
}
TEST(span_util, create_from_memory)
{
std::array<int, 4> data{1, 2, 3, 4};
const auto s = span(data);
ASSERT_EQ(s.size(), data.size());
EXPECT_TRUE(std::equal(begin(data), end(data), begin(s)));
}
TEST(span_util, create_from_const_memory)
{
const std::array<int, 4> data{1, 2, 3, 4};
const auto s = span(data);
ASSERT_EQ(s.size(), data.size());
EXPECT_TRUE(std::equal(begin(data), end(data), begin(s)));
}
TEST(span_util, empty_span_stay_empty_for_drop_front)
{
{
constexpr std::array<int, 1> data{1};
auto s = span(data);
EXPECT_EQ(1, s.size());
EXPECT_FALSE(s.empty());
EXPECT_EQ(data.front(), s.front());
s.drop_front(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
s.drop_front(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
}
{
constexpr std::array<int, 2> data{1, 2};
auto s = span(data);
EXPECT_EQ(2, s.size());
EXPECT_FALSE(s.empty());
EXPECT_EQ(data.front(), s.front());
s.drop_front(1);
EXPECT_FALSE(s.empty());
EXPECT_EQ(data.back(), s.front());
s.drop_front(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
s.drop_front(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
}
}
TEST(span_util, empty_span_stay_empty_for_drop_back)
{
{
constexpr std::array<int, 1> data{1};
auto s = span(data);
EXPECT_EQ(1, s.size());
EXPECT_FALSE(s.empty());
EXPECT_EQ(data.front(), s.front());
s.drop_back(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
s.drop_back(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
}
{
constexpr std::array<int, 2> data{1, 2};
auto s = span(data);
EXPECT_EQ(2, s.size());
EXPECT_FALSE(s.empty());
EXPECT_EQ(data.back(), s.back());
s.drop_back(1);
EXPECT_FALSE(s.empty());
EXPECT_EQ(data.front(), s.back());
s.drop_back(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
s.drop_back(1);
EXPECT_EQ(0, s.size());
EXPECT_TRUE(s.empty());
}
}
TEST(span_util, create_substring)
{
const std::array<int, 4> data{1, 2, 3, 4};
const auto s = span(data.data(), data.size());
{
const auto sub = s.subspan(1, 1000);
EXPECT_EQ(sub.size(), data.size() - 1);
EXPECT_FALSE(sub.empty());
}
{
const auto sub = s.subspan(data.size() - 1);
EXPECT_EQ(sub.size(), 1);
EXPECT_FALSE(sub.empty());
}
{
const auto sub = s.subspan(10000, 1000);
EXPECT_EQ(sub.size(), 0);
EXPECT_TRUE(sub.empty());
}
}
TEST(span_util, compare_substr_with_drop_front)
{
const std::array<int, 4> data{1, 2, 3, 4};
const auto s = span(data.data(), data.size());
auto sf = s;
auto ss = s;
for (size_t i = 0; i != data.size() + 1; ++i)
{
sf.drop_front(1);
ss = ss.subspan(1);
EXPECT_EQ(sf.size(), ss.size());
EXPECT_EQ(sf.empty(), ss.empty());
if (!sf.empty())
{
EXPECT_EQ(sf.front(), ss.front());
}
}
}
TEST(span_util, drop_elements)
{
const std::array<int, 4> data{1, 2, 3, 4};
const auto s = span(data.data(), data.size());
auto length = s.size();
for (auto sub = s; !sub.empty(); sub.drop_back(1))
{
EXPECT_EQ(sub.front(), data.front());
EXPECT_EQ(sub.size(), length);
length--;
}
length = s.size();
for (auto sub = s; !sub.empty(); sub.drop_front(1))
{
EXPECT_EQ(sub.back(), data.back());
EXPECT_EQ(sub.size(), length);
length--;
}
}
TEST(span_util, throw_on_out_of_range)
{
std::array<int, 2> data{};
EXPECT_THROW(Span<char>{}.at(0), std::out_of_range);
EXPECT_NO_THROW(span(data).at(0));
EXPECT_NO_THROW(span(data).at(1));
EXPECT_THROW(span(data).at(2), std::out_of_range);
EXPECT_THROW(span(data).at(3), std::out_of_range);
}