Commit 850e22de authored by Edwin Carlinet's avatar Edwin Carlinet Committed by Michaël Roynard
Browse files

Development/rangev3

parent 51d18cf3
......@@ -10,6 +10,7 @@ image: carlinet/buildimage
stage: test
script:
- mkdir build && cd build
- conan install ..
- cmake .. -DCMAKE_BUILD_TYPE=$PYLENE_CONFIGURATION
- cmake --build . --target check
......@@ -46,6 +47,7 @@ build-doc-images:
stage: build
script:
- mkdir build && cd build
- conan install ..
- cmake .. -DCMAKE_BUILD_TYPE=Release
- cmake --build . --target build-images
artifacts:
......
......@@ -2,12 +2,13 @@ cmake_minimum_required(VERSION 3.8.2)
project(MILENA)
# Add FindTBB directory to CMake's module path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" "${CMAKE_CURRENT_BINARY_DIR}")
find_package(Boost 1.42 COMPONENTS program_options REQUIRED)
find_package(FreeImage REQUIRED)
find_package(TBB)
find_package(Qt4)
find_package(range-v3)
# CONFIGURATION OPTIONS
set(MLN_USE_TBB YES CACHE BOOL "Set to NO to disable use of TBB and parallelization")
......@@ -20,13 +21,13 @@ if(MSVC OR APPLE)
file(GLOB_RECURSE MLN_SOURCES "${MLN_INCLUDE_DIR}/*.hpp")
add_library(Mln_srcs EXCLUDE_FROM_ALL STATIC ${MLN_SOURCES})
set_target_properties(Mln_srcs PROPERTIES LINKER_LANGUAGE CXX)
# target_compile_features(Mln_srcs PUBLIC cxx_std_14)
target_include_directories(Mln_srcs PUBLIC ${MLN_INCLUDE_DIR})
source_group(TREE ${MLN_INCLUDE_DIR} FILES ${MLN_SOURCES})
endif()
add_library(Mln INTERFACE)
target_include_directories(Mln INTERFACE ${MLN_INCLUDE_DIR})
target_include_directories(Mln INTERFACE $<TARGET_PROPERTY:range-v3::range-v3,INTERFACE_INCLUDE_DIRECTORIES>)
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
......
[requires]
range-v3/0.3.6@ericniebler/stable
[generators]
cmake_find_package
......@@ -45,7 +45,7 @@ master_doc = 'index'
# General information about the project.
project = u'Pylene'
copyright = u'2013, EC'
copyright = u'2018, LRDE'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
......
Core Module
==============================
.. toctree::
:hidden:
core/ranges
Images
******
:doc:`Ranges <core/ranges>`
***************************
Extensions for ranges with new concepts and helper functions.
Structural Elements
*******************
......
Ranges
######
Collections of elements are designed in accordance with the `Range TS <https://en.cppreference.com/w/cpp/experimental/ranges>`_.
The library extends those concepts with two concepts and helpers functions.
.. contents::
:local:
Concepts
********
Multidimensional Range
======================
.. cpp:concept:: template <typename R> MultidimensionalRange
A multidimentional range is hierarchical and provides a way to iterate over the last level of the hierarchy.
.. list-table:: Normal range vs hierarchical range traversal. Left: a single range (hence iterator) traverses a
non-contiguous range. Right: a hierarchical range, here a range of contiguous range.
* - .. image:: /figures/core/linear_rng.svg
:width: 99%
- .. image:: /figures/core/segmented_rng.svg
:width: 99%
.. rubric:: valid expressions
- :cpp:expr:`r.rows()`, with return type a range of range of `R::value_type`.
Example::
for (auto&& row : rng.rows())
for (auto v : row)
// Usage of v
Reversible Range
================
.. cpp:concept:: template <typename R> ReversibleRange
A reversible range that can be traversed forward and backward. This is not as strict as :cpp:concept:`BidirectionalRange` that require
bidirectional iterators).
Utilities for generic programming
*********************************
.. cpp:function:: auto ranges::rows(Range rng)
:param rng: Input range
Generic util for iterating row-wise over a multidimentional or a non-multidimentional range for performance.
If `rng` is multidimensional, it returns :cpp:expr:`rng.rows()`, otherwise it returns the singleton :cpp:expr:`::ranges::single(rng)`.
**Example**::
for (auto r : ranges::rows(rng))
for (auto v : r)
// Usage of v
.. c:macro:: mln_foreach
This macro eases the usage of multidimensional ranges for generic programming and efficient iteration.
The syntax is :cpp:expr:`mln_foreach(decl_expr, rng_expr)`. If :cpp:expr:`decl_expr` uses commas, it has to be
parenthesized.
.. rubric:: Examples
**Simple usage**::
mln_foreach(auto v, rng)
// Usage of v
**Usage with bind expressions**::
mln_foreach((auto [v1, v2]), mln::ranges::zip(rng1, rng2))
// Usage of v1 and v2
TEXFILES=$(shell find . -name '*.tex')
SVGFILES=$(TEXFILES:%.tex=%.svg)
all: $(SVGFILES)
%.pdf: %.tex
latexmk -cd --pdf $<
latexmk -cd -c $<
%.svg: %.pdf
pdf2svg $< $@
This diff is collapsed.
\documentclass[svgnames,tikz]{standalone}
\begin{document}
\begin{tikzpicture}[scale=.7,yscale=-1]
\tikzset{
bg/.style={fill,gray},
linear/.style={DarkRed,very thick,-latex}
}
\draw[bg] (0,0) rectangle (12,12);
\draw[fill=white] (2,2) rectangle (10,10);
\draw (0,0) grid[] (12,12);
\begin{scope}[shift={(.5,.5)}]
\foreach \y in {2, 3, ..., 8}{
\foreach \x in {2, 3, ..., 8}
\draw[linear] (\x+.1,\y) -- ++(.8,0);
\draw[linear,dotted] (9,\y) -- (2,\y+1);
}
\foreach \x in {2, 3, ..., 8}
\draw[linear] (\x+.1,9) -- ++(.8,0);
\end{scope}
\begin{scope}[shift={(12.5,5)}]
\draw[linear,DarkRed] (0,0) -- ++(1,0) node[right] { Zigzag range };
\end{scope}
\end{tikzpicture}
\end{document}
\ No newline at end of file
This diff is collapsed.
\documentclass[svgnames,tikz]{standalone}
\begin{document}
\begin{tikzpicture}[scale=.7,yscale=-1]
\tikzset{
bg/.style={fill,gray},
linear/.style={red,very thick,-latex}
}
\draw[bg] (0,0) rectangle (12,12);
\draw[fill=white] (2,2) rectangle (10,10);
\draw (0,0) grid[] (12,12);
\begin{scope}[shift={(.5,.5)}]
\foreach \y in {2, 3, ..., 9}{
\foreach \x in {2, 3, ..., 8}
\draw[linear,DarkGreen] (\x+.1,\y) -- ++(.8,0);
}
\foreach \y in {2, 3, ..., 8} {
\draw (1.75,\y-.25) rectangle +(7.5,0.5);
\draw[linear,DarkBlue] (1.75,\y)
-- +(-.5,0) |- +(0,.8);
}
\draw (1.75,9-.25) rectangle +(7.5,0.5);
\end{scope}
\begin{scope}[shift={(12.5,5)}]
\draw[linear,DarkBlue] (0,0) -- ++(1,0) node[right] { Outer range };
\draw[linear,DarkGreen] (0,1) -- ++(1,0) node[right] { Inner range };
\end{scope}
\end{tikzpicture}
\end{document}
\ No newline at end of file
#pragma once
#include <mln/core/rangev3/rows.hpp>
#include <boost/preprocessor/punctuation/remove_parens.hpp>
/// \brief The macro defines mln_foreach(RANGE_DECLARATION, RANGE_EXPRESSION) as equivalent to:
///
/// \code
/// for (auto&& row : mln::ranges::rows(RANGE_EXPRESSION))
/// for (RANGE_DECLARATION : row)
/// \endcode
///
/// with support for *break* statement.
///
/// \note Due to limited support for comma by preprocessor, any RANGE_DECLARATION with comma must be enclosed
/// in parenthesis. For example:
///
/// \code
/// mln_foreach((auto [a,b]), multispan)
/// \endcode
#define mln_foreach_new(PROTECTED_DECL, RNG) \
if (bool __mln_has_been_broken = false; false) \
{ \
} \
else \
for (auto&& __mln_inner_rng : mln::ranges::rows(RNG)) \
if (__mln_has_been_broken) \
break; \
else \
for (BOOST_PP_REMOVE_PARENS(PROTECTED_DECL) : __mln_inner_rng) \
if (__mln_has_been_broken) \
break; \
else \
for (__mln_has_been_broken = true; __mln_has_been_broken; __mln_has_been_broken = false)
#pragma once
#include <mln/core/rangev3/private/multidimensional_range.hpp>
#include <mln/core/rangev3/private/multidimensional_range_facade.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/reverse.hpp>
#include <array>
namespace mln::ranges
{
template <std::size_t Rank, typename T = int>
struct multi_indices;
template <std::size_t Rank, typename T = int>
struct reversed_multi_indices;
/******************************************/
/**** Implementation ****/
/******************************************/
template <typename T>
struct multi_indices<1, T> : public ::ranges::view_facade<multi_indices<1, T>>
{
private:
friend ::ranges::range_access;
using value_t = std::array<T, 1>;
struct cursor
{
value_t read() const { return {x}; }
void next() { ++x; }
void prev() { --x; }
bool equal(const cursor& other) const { return x == other.x; }
T x;
};
public:
cursor begin_cursor() const { return cursor{m_from}; }
cursor end_cursor() const { return cursor{m_to}; }
multi_indices() = default;
multi_indices(value_t from, value_t to) : m_from(from[0]), m_to(to[0]) {}
multi_indices(value_t to) : m_to(to[0]) {}
reversed_multi_indices<1, T> reversed() const { return {{m_from}, {m_to}}; }
private:
T m_from = 0;
T m_to;
};
template <typename T>
struct reversed_multi_indices<1, T> : public ::ranges::reverse_view<multi_indices<1, T>>
{
private:
using adapted = multi_indices<1, T>;
using base = ::ranges::reverse_view<adapted>;
public:
using value_type = std::array<T, 1>;
reversed_multi_indices() = default;
reversed_multi_indices(value_type from, value_type to) : base(adapted(from, to)) {}
reversed_multi_indices(value_type to) : base(adapted(to)) {}
};
/******************************************/
/**** generic multi_indices *****/
/******************************************/
template <std::size_t Rank, typename T /* = int */>
struct multi_indices :
public multidimensional_range_base,
public ::ranges::view_facade<multi_indices<Rank, T>>
{
static_assert(Rank > 1);
using value_type = std::array<T, Rank>;
private:
/******************************************/
/**** multi_indices::cursor *****/
/******************************************/
friend ::ranges::range_access;
struct cursor : mln::ranges::details::forward_multidimensional_cursor_facade<Rank, cursor>
{
using base = mln::ranges::details::forward_multidimensional_cursor_facade<Rank, cursor>;
value_type read() const { return m_current; }
bool __is_at_end(std::size_t k) const { return m_current[k] == m_to[k]; }
void __next(std::size_t k) { m_current[k]++; }
void __reset_to_begin(std::size_t k) { m_current[k] = m_from[k]; }
cursor() = default;
cursor(value_type from, value_type to) : m_from(from), m_to(to), m_current(from) {}
using base::equal;
using base::next;
private:
value_type m_from;
value_type m_to;
value_type m_current;
};
/******************************************/
/**** multi_indices::row_size *****/
/******************************************/
struct row_wise : public ::ranges::view_facade<row_wise>
{
public:
using value_type = std::array<T, Rank>;
row_wise() = default;
row_wise(value_type from, value_type to) : m_from(from), m_to(to) {}
private:
/**************************************************/
/**** multi_indices::row_size::cursor *****/
/**************************************************/
friend ::ranges::range_access;
struct cursor : mln::ranges::details::forward_multidimensional_cursor_facade<Rank - 1, cursor>
{
friend ::ranges::range_access;
private:
/*********************************************************/
/**** multi_indices::row_size::cursor::row_t *****/
/*********************************************************/
struct row_t : public ::ranges::view_facade<row_t>
{
friend ::ranges::range_access;
using value_type = std::array<T, Rank>;
row_t() = default;
row_t(value_type from, std::size_t size) : m_x(from), m_size(size) {}
private:
value_type read() const { return m_x; }
void next()
{
m_size--;
m_x.back()++;
}
bool equal(::ranges::default_sentinel) const { return m_size == 0; }
protected:
value_type m_x;
std::size_t m_size = 0;
};
/**************************************************************/
/**** end of multi_indices::row_size::cursor::row_t *****/
/**************************************************************/
using base = mln::ranges::details::forward_multidimensional_cursor_facade<Rank - 1, cursor>;
row_t read() const { return {m_x, static_cast<std::size_t>(m_to[Rank - 1] - m_from[Rank - 1])}; }
public:
bool __is_at_end(std::size_t k) const { return m_x[k] == m_to[k]; }
void __next(std::size_t k) { m_x[k]++; }
void __reset_to_begin(std::size_t k) { m_x[k] = m_from[k]; }
constexpr cursor() = default;
constexpr cursor(value_type from, value_type to) : m_from(from), m_to(to), m_x(from) {}
using base::equal;
using base::next;
private:
value_type m_from;
value_type m_to;
value_type m_x;
};
/*******************************************************/
/**** end of multi_indices::row_size::cursor *****/
/*******************************************************/
cursor begin_cursor() const { return {m_from, m_to}; }
private:
value_type m_from;
value_type m_to;
};
/*******************************************************/
/**** end of multi_indices::row_size *****/
/*******************************************************/
cursor begin_cursor() const { return cursor(m_from, m_to); }
public:
row_wise rows() const { return {m_from, m_to}; }
reversed_multi_indices<Rank, T> reversed() const { return {m_from, m_to}; }
constexpr multi_indices() = default;
constexpr multi_indices(value_type from, value_type to) : m_from(from), m_to(to) {}
constexpr multi_indices(value_type to) : m_from{{0}}, m_to(to) {}
protected:
value_type m_from;
value_type m_to;
};
/************************************************/
/**** end of multi_indices *****/
/************************************************/
/************************************************/
/**** reversed_multi_indices *****/
/************************************************/
template <std::size_t Rank, typename T /* = int */>
struct reversed_multi_indices :
public multidimensional_range_base,
public ::ranges::view_facade<reversed_multi_indices<Rank, T>>
{
static_assert(Rank > 1);
using value_type = std::array<T, Rank>;
private:
friend ::ranges::range_access;
/***************************************************/
/**** reversed_multi_indices::cursor *****/
/***************************************************/
struct cursor : mln::ranges::details::forward_multidimensional_cursor_facade<Rank, cursor>
{
using base = mln::ranges::details::forward_multidimensional_cursor_facade<Rank, cursor>;
value_type read() const
{
value_type v = m_current;
for (std::size_t k = 0; k < Rank; ++k)
--v[k];
return v;
}
bool __is_at_end(std::size_t k) const { return m_current[k] == m_from[k]; }
void __next(std::size_t k) { --m_current[k]; }
void __reset_to_begin(std::size_t k) { m_current[k] = m_to[k]; }
cursor() = default;
cursor(value_type from, value_type to) : m_from(from), m_to(to), m_current(to) {}
using base::equal;
using base::next;
private:
value_type m_from;
value_type m_to;
value_type m_current;
};
/*****************************************************/
/**** reversed_multi_indices::row_size *****/
/*****************************************************/
struct row_wise : public ::ranges::view_facade<row_wise>
{
public:
using value_type = std::array<T, Rank>;
row_wise() = default;
row_wise(value_type from, value_type to) : m_from(from), m_to(to) {}
private:
friend ::ranges::range_access;
/*************************************************************/
/**** reversed_multi_indices::row_size::cursor *****/
/*************************************************************/
struct cursor : mln::ranges::details::forward_multidimensional_cursor_facade<Rank - 1, cursor>
{
friend ::ranges::range_access;
private:
struct row_t : public ::ranges::view_facade<row_t>
{
friend ::ranges::range_access;
using value_type = std::array<T, Rank>;
row_t() = default;
row_t(value_type from, std::size_t size) : m_x(from), m_size(size) {}
private:
value_type read() const
{
value_type v = m_x;
for (std::size_t k = 0; k < Rank; ++k)
--v[k];
return v;
}
void next()
{
--m_size;
--m_x.back();
}
bool equal(::ranges::default_sentinel) const { return m_size == 0; }
protected:
value_type m_x;
std::size_t m_size = 0;
};
using base = mln::ranges::details