/* * Copyright (c) 2016, 2017 ARM Limited. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * 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. */ #ifndef __ARM_COMPUTE_WINDOW_H__ #define __ARM_COMPUTE_WINDOW_H__ #include #include #include #include "arm_compute/core/Coordinates.h" #include "arm_compute/core/Error.h" #include "arm_compute/core/ITensorInfo.h" #include "arm_compute/core/Utils.h" namespace arm_compute { /** Describe a multidimensional execution window. */ class Window { public: /** Alias for dimension 0 also known as X dimension */ static constexpr size_t DimX = 0; /** Alias for dimension 1 also known as Y dimension */ static constexpr size_t DimY = 1; /** Alias for dimension 2 also known as Z dimension */ static constexpr size_t DimZ = 2; /** Default constructor: create a window containing a single element. */ constexpr Window() : _dims() { } /** Copy constructor * * @param[in] src Copy the values from src to a new object */ Window(const Window &src); /** Describe one of the image's dimensions with a start, end and step. * * Iteration through the elements of the dimension is done like this: * for(int v = start(); v < end(); v += step()) * { * ... * } */ class Dimension { public: /** Constructor, by default creates a dimension of 1. * * @param[in] start Start of the dimension * @param[in] end End of the dimension * @param[in] step Step between two elements of the dimension when iterating. * */ constexpr Dimension(int start = 0, int end = 1, int step = 1) : _start(start), _end(end), _step(step) { } /** Default assignment operator to allow dimensions to be copied */ Dimension &operator=(const Dimension &d) = default; /** Return the start of the dimension */ constexpr int start() const { return _start; } /** Return the end of the dimension */ constexpr int end() const { return _end; } /** Return the step of the dimension */ constexpr int step() const { return _step; } /** Set the dimension's step * * @param[in] step The new step */ void set_step(int step) { _step = step; } private: int _start; /**< Start of the dimension */ int _end; /**< End of the dimension */ int _step; }; /** Read only access to a given dimension of the window * * @note Precondition: dimension < Coordinates::num_max_dimensions * * @param[in] dimension The dimension to access * * @return The requested dimension */ constexpr const Dimension &operator[](size_t dimension) const; /** Alias to access the first dimension of the window * * @return First dimension of the window */ constexpr const Dimension &x() const { return _dims.at(Window::DimX); } /** Alias to access the second dimension of the window * * @return Second dimension of the window */ constexpr const Dimension &y() const { return _dims.at(Window::DimY); } /** Alias to access the third dimension of the window * * @return Third dimension of the window */ constexpr const Dimension &z() const { return _dims.at(Window::DimZ); } /** Set the values of a given dimension * * @param[in] dimension The dimension to set * @param[in] dim The values to set the dimension to */ void set(size_t dimension, const Dimension &dim); /** Use the tensor's dimensions to fill the window dimensions. * * @param[in] shape @ref TensorShape to copy the dimensions from. * @param[in] first_dimension Only copy dimensions which are greater or equal to this value. */ void use_tensor_dimensions(const TensorShape &shape, size_t first_dimension = Window::DimX); /** Shift the values of a given dimension by the given shift_value * * @param[in] dimension The dimension to shift * @param[in] shift_value Value to shift the start and end values of. */ void shift(size_t dimension, int shift_value); /** Adjust the start or end of a given dimension by the given value * * @param[in] dimension The dimension to adjust * @param[in] adjust_value The adjusted value. * @param[in] is_at_start The flag to indicate whether adjust the start or end of the dimension. */ void adjust(size_t dimension, int adjust_value, bool is_at_start); /** Scale the values of a given dimension by the given scale_value * * @note The end of the window is rounded up to be a multiple of step after the scaling. * * @param[in] dimension The dimension to scale * @param[in] scale_value Value to scale the start, end and step values of. */ void scale(size_t dimension, float scale_value); /** Set the step of a given dimension. * * @param[in] dimension Dimension to update * @param[in] step The new dimension's step value */ void set_dimension_step(size_t dimension, int step); /** Will validate all the window's dimensions' values when asserts are enabled * * No-op when asserts are disabled */ void validate() const; /** Return the number of iterations needed to iterate through a given dimension * * @param[in] dimension The requested dimension * * @return The number of iterations */ constexpr size_t num_iterations(size_t dimension) const; /** Split a window into a set of sub windows along a given dimension * * For example to split a window into 3 sub-windows along the Y axis, you would have to do:
* Window sub0 = window.split_window( 1, 0, 3);
* Window sub1 = window.split_window( 1, 1, 3);
* Window sub2 = window.split_window( 1, 2, 3);
* * @param[in] dimension Dimension along which the split will be performed * @param[in] id Id of the sub-window to return. Must be in the range (0, total-1) * @param[in] total Total number of sub-windows the window will be split into. * * @return The subwindow "id" out of "total" */ Window split_window(size_t dimension, size_t id, size_t total) const; /** First 1D slice of the window * * @return The first slice of the window. */ Window first_slice_window_1D() const { return first_slice_window<1>(); }; /** First 2D slice of the window * * @return The first slice of the window. */ Window first_slice_window_2D() const { return first_slice_window<2>(); }; /** First 3D slice of the window * * @return The first slice of the window. */ Window first_slice_window_3D() const { return first_slice_window<3>(); }; /** Slide the passed 1D window slice. * * If slice contains the last slice then it will remain unchanged and false will be returned. * * @param[in,out] slice Current slice, to be updated to the next slice. * * @return true if slice contains a new slice, false if slice already contained the last slice */ bool slide_window_slice_1D(Window &slice) const { return slide_window_slice<1>(slice); } /** Slide the passed 2D window slice. * * If slice contains the last slice then it will remain unchanged and false will be returned. * * @param[in,out] slice Current slice, to be updated to the next slice. * * @return true if slice contains a new slice, false if slice already contained the last slice */ bool slide_window_slice_2D(Window &slice) const { return slide_window_slice<2>(slice); } /** Slide the passed 3D window slice. * * If slice contains the last slice then it will remain unchanged and false will be returned. * * @param[in,out] slice Current slice, to be updated to the next slice. * * @return true if slice contains a new slice, false if slice already contained the last slice */ bool slide_window_slice_3D(Window &slice) const { return slide_window_slice<3>(slice); } /** Slide the passed 4D window slice. * * If slice contains the last slice then it will remain unchanged and false will be returned. * * @param[in,out] slice Current slice, to be updated to the next slice. * * @return true if slice contains a new slice, false if slice already contained the last slice */ bool slide_window_slice_4D(Window &slice) const { return slide_window_slice<4>(slice); } /* Collapse the dimensions higher than @p first if possible. * * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window * * @param[in] full_window Full window @p window has been created from. * @param[in] first Dimensions into which the following are collapsed. * * @return Collapsed window. */ Window collapse_if_possible(const Window &full_window, size_t first) const; private: /** First slice of the window * * @return The first slice of the window. */ template Window first_slice_window() const; /** Slide the passed window slice. * * If slice contains the last slice then it will remain unchanged and false will be returned. * * @param[in,out] slice Current slice, to be updated to the next slice. * * @return true if slice contains a new slice, false if slice already contained the last slice */ template bool slide_window_slice(Window &slice) const; private: std::array _dims; }; } #include "Window.inl" #endif /*__ARM_COMPUTE_WINDOW_H__ */