diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | include/armnn/utility/TransformIterator.hpp | 82 | ||||
-rw-r--r-- | src/armnn/Graph.hpp | 9 | ||||
-rw-r--r-- | src/armnnUtils/test/TransformIteratorTest.cpp | 102 | ||||
-rw-r--r-- | src/backends/backendsCommon/WorkloadFactory.cpp | 43 |
5 files changed, 213 insertions, 25 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f6301eb1..13a8a962fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -254,6 +254,7 @@ list(APPEND armnn_sources include/armnn/utility/NumericCast.hpp include/armnn/utility/PolymorphicDowncast.hpp include/armnn/utility/StringUtils.hpp + include/armnn/utility/TransformIterator.hpp src/armnn/layers/LayerCloneBase.hpp src/armnn/layers/LayerWithParameters.hpp src/armnn/layers/ActivationLayer.hpp @@ -701,6 +702,7 @@ if(BUILD_UNIT_TESTS) src/armnnUtils/test/PrototxtConversionsTest.cpp src/armnnUtils/test/QuantizeHelperTest.cpp src/armnnUtils/test/TensorUtilsTest.cpp + src/armnnUtils/test/TransformIteratorTest.cpp src/profiling/test/BufferTests.cpp src/profiling/test/FileOnlyProfilingDecoratorTests.cpp src/profiling/test/PrintPacketHeaderHandler.cpp diff --git a/include/armnn/utility/TransformIterator.hpp b/include/armnn/utility/TransformIterator.hpp new file mode 100644 index 0000000000..d4f32c5d8a --- /dev/null +++ b/include/armnn/utility/TransformIterator.hpp @@ -0,0 +1,82 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// +#pragma once + +#include <iterator> + +namespace armnn +{ + +template<typename Function, + typename Iterator, + typename Category = typename std::iterator_traits<Iterator>::iterator_category, + typename T = typename std::iterator_traits<Iterator>::value_type, + typename Distance = typename std::iterator_traits<Iterator>::difference_type, + typename Pointer = typename std::iterator_traits<Iterator>::pointer, + typename Reference = + typename std::result_of<const Function(typename std::iterator_traits<Iterator>::reference)>::type +> +class TransformIterator : public std::iterator<Category, T, Distance, Pointer, Reference> +{ + +public: + + TransformIterator() = default; + TransformIterator(TransformIterator const& transformIterator) = default; + TransformIterator(TransformIterator&& transformIterator) = default; + + TransformIterator(Iterator& it, Function fn) : m_it(it), m_fn(fn) {} + TransformIterator(Iterator&& it, Function fn) : m_it(it), m_fn(fn) {} + + ~TransformIterator() = default; + + TransformIterator operator=(TransformIterator const& transformIterator) + { + return{ transformIterator.it, transformIterator.fn}; + } + + TransformIterator operator=(TransformIterator&& transformIterator) + { + return{ transformIterator.it, transformIterator.fn}; + } + + TransformIterator operator++() {++m_it; return *this;} + TransformIterator operator--() {--m_it; return *this;} + + TransformIterator operator++() const {++m_it; return *this;} + TransformIterator operator--() const {--m_it; return *this;} + + TransformIterator operator++(int n) const {m_it += n; return *this;} + TransformIterator operator--(int n) const {m_it -= n; return *this;} + + TransformIterator operator[](Distance n) const {m_it[n]; return *this;}; + + Distance operator-(const TransformIterator& other) {return m_it - other.m_it;} + + TransformIterator operator-(const Distance n) {return {m_it - n, m_fn};} + TransformIterator operator+(const Distance n) {return {m_it + n, m_fn};} + + bool operator>(const TransformIterator& rhs) const {return m_it > rhs.m_it;} + bool operator<(const TransformIterator& rhs) const {return m_it < rhs.m_it;} + bool operator>=(const TransformIterator& rhs) const {return m_it >= rhs.m_it;} + bool operator<=(const TransformIterator& rhs) const {return m_it <= rhs.m_it;} + + bool operator==(TransformIterator other) const {return (m_it == other.m_it);} + bool operator!=(TransformIterator other) const {return !(m_it == other.m_it);} + + Reference operator*() const {return m_fn(*m_it);} + +private: + Iterator m_it; + const Function m_fn; +}; + +template<typename Function, typename Iterator> +constexpr TransformIterator<Function, Iterator> MakeTransformIterator(Iterator i, Function f) +{ + return TransformIterator<Function, Iterator>(i, f); +} + +}
\ No newline at end of file diff --git a/src/armnn/Graph.hpp b/src/armnn/Graph.hpp index 87e0da826f..731ae1e5aa 100644 --- a/src/armnn/Graph.hpp +++ b/src/armnn/Graph.hpp @@ -13,6 +13,7 @@ #include <armnn/Exceptions.hpp> #include <armnn/utility/Assert.hpp> #include <armnn/utility/PolymorphicDowncast.hpp> +#include <armnn/utility/TransformIterator.hpp> #include <list> #include <map> @@ -20,8 +21,6 @@ #include <unordered_set> #include <vector> -#include <boost/iterator/transform_iterator.hpp> - namespace armnn { @@ -51,9 +50,9 @@ public: using Iterator = LayerList::const_iterator; // Const so pointers in the list can't be modified externally. using IteratorDifference = Iterator::difference_type; - using ConstIterator = boost::transform_iterator<decltype(&PtrCast<const Layer>), Iterator>; - using ConstIteratorInputs = boost::transform_iterator<decltype(&PtrCast<const InputLayer>), Iterator>; - using ConstIteratorOutputs = boost::transform_iterator<decltype(&PtrCast<const OutputLayer>), Iterator>; + using ConstIterator = TransformIterator<decltype(&PtrCast<const Layer>), Iterator>; + using ConstIteratorInputs = TransformIterator<decltype(&PtrCast<const InputLayer>), Iterator>; + using ConstIteratorOutputs = TransformIterator<decltype(&PtrCast<const OutputLayer>), Iterator>; /// Wrapper class returned by Graph::GetInputLayers() struct InputLayersAccessor diff --git a/src/armnnUtils/test/TransformIteratorTest.cpp b/src/armnnUtils/test/TransformIteratorTest.cpp new file mode 100644 index 0000000000..c44e454312 --- /dev/null +++ b/src/armnnUtils/test/TransformIteratorTest.cpp @@ -0,0 +1,102 @@ +// +// Copyright © 2020 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <armnn/utility/TransformIterator.hpp> + +#include <boost/test/unit_test.hpp> +#include <iostream> + +using namespace armnn; + +BOOST_AUTO_TEST_SUITE(TransformIteratorSuite) + +namespace +{ + +static int square(const int val) +{ + return val * val; +} + +static std::string concat(const std::string val) +{ + return val + "a"; +} + +BOOST_AUTO_TEST_CASE(TransformIteratorTest) +{ + struct WrapperTestClass + { + TransformIterator<decltype(&square), std::vector<int>::const_iterator> begin() const + { + return { m_Vec.begin(), &square }; + } + + TransformIterator<decltype(&square), std::vector<int>::const_iterator> end() const + { + return { m_Vec.end(), &square }; + } + + const std::vector<int> m_Vec{1, 2, 3, 4, 5}; + }; + + struct WrapperStringClass + { + TransformIterator<decltype(&concat), std::vector<std::string>::const_iterator> begin() const + { + return { m_Vec.begin(), &concat }; + } + + TransformIterator<decltype(&concat), std::vector<std::string>::const_iterator> end() const + { + return { m_Vec.end(), &concat }; + } + + const std::vector<std::string> m_Vec{"a", "b", "c"}; + }; + + WrapperStringClass wrapperStringClass; + WrapperTestClass wrapperTestClass; + int i = 1; + + for(auto val : wrapperStringClass) + { + BOOST_CHECK(val != "e"); + i++; + } + + i = 1; + for(auto val : wrapperTestClass) + { + BOOST_CHECK(val == square(i)); + i++; + } + + i = 1; + // Check original vector is unchanged + for(auto val : wrapperTestClass.m_Vec) + { + BOOST_CHECK(val == i); + i++; + } + + std::vector<int> originalVec{1, 2, 3, 4, 5}; + + auto transformBegin = MakeTransformIterator(originalVec.begin(), &square); + auto transformEnd = MakeTransformIterator(originalVec.end(), &square); + + std::vector<int> transformedVec(transformBegin, transformEnd); + + i = 1; + for(auto val : transformedVec) + { + BOOST_CHECK(val == square(i)); + i++; + } +} + +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp index 54a4157fe3..5e3eed086a 100644 --- a/src/backends/backendsCommon/WorkloadFactory.cpp +++ b/src/backends/backendsCommon/WorkloadFactory.cpp @@ -11,14 +11,13 @@ #include <armnn/ILayerSupport.hpp> #include <armnn/BackendRegistry.hpp> #include <armnn/utility/PolymorphicDowncast.hpp> +#include <armnn/utility/TransformIterator.hpp> #include <backendsCommon/WorkloadFactory.hpp> #include <backendsCommon/CpuTensorHandle.hpp> #include <backendsCommon/test/WorkloadTestUtils.hpp> -#include <boost/iterator/transform_iterator.hpp> - #include <sstream> namespace armnn @@ -26,6 +25,8 @@ namespace armnn namespace { +using LayerList = std::list<Layer*>; +using Iterator = LayerList::const_iterator; // Const so pointers in the list can't be modified externally. const TensorInfo OverrideDataType(const TensorInfo& info, Optional<DataType> type) { @@ -667,16 +668,18 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, { return OverrideDataType(slot.GetConnectedOutputSlot()->GetTensorInfo(), dataType); }; - auto beginI = boost::make_transform_iterator(layer.GetInputSlots().begin(), getTensorInfo); - auto endI = boost::make_transform_iterator(layer.GetInputSlots().end(), getTensorInfo); + + auto beginI = MakeTransformIterator(layer.GetInputSlots().begin(), getTensorInfo); + auto endI = MakeTransformIterator(layer.GetInputSlots().end(), getTensorInfo); std::vector<TensorInfo> inputs(beginI, endI); auto getTensorInfoPtr = [](const TensorInfo& info) { return &info; }; - auto beginPtr = boost::make_transform_iterator(inputs.begin(), getTensorInfoPtr); - auto endPtr = boost::make_transform_iterator(inputs.end(), getTensorInfoPtr); + + auto beginPtr = MakeTransformIterator(inputs.begin(), getTensorInfoPtr); + auto endPtr = MakeTransformIterator(inputs.end(), getTensorInfoPtr); std::vector<const TensorInfo*> inputPtrs(beginPtr, endPtr); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -1011,8 +1014,8 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, { return OverrideDataType(slot.GetTensorInfo(), dataType); }; - auto beginI = boost::make_transform_iterator(layer.GetOutputSlots().begin(), getTensorInfo); - auto endI = boost::make_transform_iterator(layer.GetOutputSlots().end(), getTensorInfo); + auto beginI = MakeTransformIterator(layer.GetOutputSlots().begin(), getTensorInfo); + auto endI = MakeTransformIterator(layer.GetOutputSlots().end(), getTensorInfo); std::vector<TensorInfo> outputs(beginI, endI); const std::vector<std::reference_wrapper<TensorInfo>> outputPtrs(outputs.begin(), outputs.end()); @@ -1032,16 +1035,16 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, { return OverrideDataType(slot.GetConnectedOutputSlot()->GetTensorInfo(), dataType); }; - auto beginI = boost::make_transform_iterator(layer.GetInputSlots().begin(), getTensorInfo); - auto endI = boost::make_transform_iterator(layer.GetInputSlots().end(), getTensorInfo); + auto beginI = MakeTransformIterator(layer.GetInputSlots().begin(), getTensorInfo); + auto endI = MakeTransformIterator(layer.GetInputSlots().end(), getTensorInfo); std::vector<TensorInfo> inputs(beginI, endI); auto getTensorInfoPtr = [](const TensorInfo& info) { return &info; }; - auto beginPtr = boost::make_transform_iterator(inputs.begin(), getTensorInfoPtr); - auto endPtr = boost::make_transform_iterator(inputs.end(), getTensorInfoPtr); + auto beginPtr = MakeTransformIterator(inputs.begin(), getTensorInfoPtr); + auto endPtr = MakeTransformIterator(inputs.end(), getTensorInfoPtr); std::vector<const TensorInfo*> inputPtrs(beginPtr, endPtr); const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo(); @@ -1063,12 +1066,12 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, { return OverrideDataType(slot.GetTensorInfo(), dataType); }; - auto beginI = boost::make_transform_iterator(layer.GetInputSlots().begin(), getTensorInfoIn); - auto endI = boost::make_transform_iterator(layer.GetInputSlots().end(), getTensorInfoIn); + auto beginI = MakeTransformIterator(layer.GetInputSlots().begin(), getTensorInfoIn); + auto endI = MakeTransformIterator(layer.GetInputSlots().end(), getTensorInfoIn); std::vector<TensorInfo> inputs(beginI, endI); - auto beginO = boost::make_transform_iterator(layer.GetOutputSlots().begin(), getTensorInfoOut); - auto endO = boost::make_transform_iterator(layer.GetOutputSlots().end(), getTensorInfoOut); + auto beginO = MakeTransformIterator(layer.GetOutputSlots().begin(), getTensorInfoOut); + auto endO = MakeTransformIterator(layer.GetOutputSlots().end(), getTensorInfoOut); std::vector<TensorInfo> outputs(beginO, endO); @@ -1076,12 +1079,12 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, { return &info; }; - auto beginPtrI = boost::make_transform_iterator(inputs.begin(), getTensorInfoPtr); - auto endPtrI = boost::make_transform_iterator(inputs.end(), getTensorInfoPtr); + auto beginPtrI = MakeTransformIterator(inputs.begin(), getTensorInfoPtr); + auto endPtrI = MakeTransformIterator(inputs.end(), getTensorInfoPtr); std::vector<const TensorInfo*> inputPtrs(beginPtrI, endPtrI); - auto beginPtrO = boost::make_transform_iterator(outputs.begin(), getTensorInfoPtr); - auto endPtrO = boost::make_transform_iterator(outputs.end(), getTensorInfoPtr); + auto beginPtrO = MakeTransformIterator(outputs.begin(), getTensorInfoPtr); + auto endPtrO = MakeTransformIterator(outputs.end(), getTensorInfoPtr); std::vector<const TensorInfo*> outputPtrs(beginPtrO, endPtrO); |