Skip to content
Permalink
Browse files

Merge pull request #13126 from permcody/enumerate

Enumerate syntactic sugar!
  • Loading branch information...
moosebuild committed Mar 27, 2019
2 parents c298d06 + b9e66d6 commit be4f69d299bed7c7622af5ddfdac3801380840c1
Showing with 215 additions and 7 deletions.
  1. +147 −0 framework/include/utils/Enumerate.h
  2. +6 −7 framework/include/utils/JvarMapInterface.h
  3. +62 −0 unit/src/EnumerateTest.C
@@ -0,0 +1,147 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#ifndef ENUMERATE_H
#define ENUMERATE_H

#include <iterator>
#include <iostream>

namespace Moose
{
// Forward Declarations of helper objects
template <class Iterator>
struct _enumerate_struct;

template <class Iterator>
struct _enumerate_iterator;

template <class Iterator>
struct _enumerate_range;

/**
* Enumerate function for iterating over a range and obtaining both a reference to the underlying
* type and an index simultaneously. This method is forward-compatible with the C++17 structured
* bindings capability.
*
* C++11 compatible usage:
*
* for (auto it : Moose::enumerate(values))
* _console << it.index() << ": " << it.value() << '\n';
*
* // Here the third argument is the starting index value
* for (auto it : Moose::enumerate(values.begin(), values.end(), 0))
* _console << it.index() << ": " << it.value() << '\n';
*
* C++17 usage (DO NOT USE IN MOOSE):
*
* for (auto [index, value] : Moose::enumerate(values))
* _console << index << ": " << value << '\n';
*
* // Here the third argument is the starting index value
* for (auto [index, value] : Moose::enumerate(values.begin(), values.end(), 0))
* _console << index << ": " << value << '\n';
*/
template <class Iterator>
_enumerate_range<Iterator>
enumerate(Iterator first,
Iterator last,
typename std::iterator_traits<Iterator>::difference_type initial)
{
return _enumerate_range<Iterator>(first, last, initial);
}

template <class Container>
_enumerate_range<typename Container::iterator>
enumerate(Container & content)
{
return _enumerate_range<typename Container::iterator>(std::begin(content), std::end(content), 0);
}

template <class Container>
_enumerate_range<typename Container::const_iterator>
enumerate(const Container & content)
{
return _enumerate_range<typename Container::const_iterator>(
std::begin(content), std::end(content), 0);
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// Helper object
template <class Iterator>
struct _enumerate_struct
{
using iterator = Iterator;
using index_type = typename std::iterator_traits<iterator>::difference_type;
using reference = typename std::iterator_traits<iterator>::reference;

_enumerate_struct(index_type index, iterator iterator) : l_index(index), l_iter(iterator) {}

index_type index() { return l_index; }

reference value() { return *l_iter; }

private:
index_type l_index;
iterator l_iter;
};

// Helper object
template <class Iterator>
struct _enumerate_iterator
{
using iterator = Iterator;
using index_type = typename std::iterator_traits<iterator>::difference_type;
using reference = typename std::iterator_traits<iterator>::reference;

_enumerate_iterator(index_type index, iterator iterator) : index(index), iter(iterator) {}

_enumerate_iterator & operator++()
{
++index;
++iter;
return *this;
}

bool operator!=(const _enumerate_iterator & other) const { return iter != other.iter; }

#if __cplusplus > 201402L
std::pair<index_type &, reference> operator*() { return {index, *iter}; }
#else
_enumerate_struct<iterator> operator*() { return _enumerate_struct<iterator>(index, iter); }
#endif

private:
index_type index;
iterator iter;
};

template <class Iterator>
struct _enumerate_range
{
using index_type = typename std::iterator_traits<Iterator>::difference_type;
using iterator = _enumerate_iterator<Iterator>;

_enumerate_range(Iterator first, Iterator last, index_type initial)
: first(first), last(last), initial(initial)
{
}

iterator begin() const { return iterator(initial, first); }

iterator end() const { return iterator(0, last); }

private:
Iterator first;
Iterator last;
index_type initial;
};
}

#endif // ENUMERATE_H
@@ -12,6 +12,7 @@

#include "MooseVariableFE.h"
#include "NonlinearSystemBase.h"
#include "Enumerate.h"

template <class T>
class JvarMapInterfaceBase;
@@ -21,7 +22,7 @@ class JvarMapInterfaceBase;
* computeQpOffDiagJacobian into the _coupled_moose_vars array.
*
* This class is useful in conjunction with DerivativeMaterialInterface,
* where vectors of material property derviatives with respect to all coupled
* where vectors of material property derivatives with respect to all coupled
* variables (iterating over _coupled_moose_vars array) are generated.
* The mapping enabled the look up of the correct material property derivatives
* for the current jvar.
@@ -40,7 +41,7 @@ class JvarMapKernelInterface : public JvarMapInterfaceBase<T>
* computeJacobianBlock into the _coupled_moose_vars array.
*
* This class is useful in conjunction with DerivativeMaterialInterface,
* where vectors of material property derviatives with respect to all coupled
* where vectors of material property derivatives with respect to all coupled
* variables (iterating over _coupled_moose_vars array) are generated.
* The mapping enabled the look up of the correct material property derivatives
* for the current jvar.
@@ -88,16 +89,14 @@ template <class T>
JvarMapInterfaceBase<T>::JvarMapInterfaceBase(const InputParameters & parameters)
: T(parameters), _jvar_map(this->_fe_problem.getNonlinearSystemBase().nVariables(), -1)
{
auto nvar = this->_coupled_moose_vars.size();

// populate map;
for (auto i = beginIndex(this->_coupled_moose_vars); i < nvar; ++i)
for (auto it : Moose::enumerate(this->_coupled_moose_vars))
{
auto number = this->_coupled_moose_vars[i]->number();
auto number = it.value()->number();

// skip AuxVars as off-diagonal jacobian entries are not calculated for them
if (number < _jvar_map.size())
_jvar_map[number] = i;
_jvar_map[number] = it.index();
}

// mark the kernel variable for the check in computeOffDiagJacobian
@@ -0,0 +1,62 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include <vector>
#include <numeric>

#include "gtest/gtest.h"

#include "Enumerate.h"

void
const_container(const std::vector<int> & v, int value, int counter)
{
for (auto it : Moose::enumerate(v))
{
EXPECT_EQ(it.value(), value++);
EXPECT_EQ(it.index(), counter++);
}
}

TEST(Enumerate, container)
{
std::vector<int> v(10);

int value = -4;
std::iota(v.begin(), v.end(), value);

int counter = 0;
for (auto it : Moose::enumerate(v))
{
EXPECT_EQ(it.value(), value++);
EXPECT_EQ(it.index(), counter++);
}

// Test in const context
const_container(v, -4, 0);

// Test modification of values
value = -3;
for (auto it : Moose::enumerate(v))
{
it.value()++;
EXPECT_EQ(it.value(), value++);
}
}

TEST(Enumerate, range)
{
std::vector<unsigned int> v(10);

int value = 1;
std::iota(v.begin(), v.end(), value);

for (auto it : Moose::enumerate(v.begin(), v.end(), 1))
EXPECT_EQ(it.value(), it.index());
}

0 comments on commit be4f69d

Please sign in to comment.
You can’t perform that action at this time.