Merge branch 'range_respect_indextype' into 'master'

Range(obj) does respect index type now. If obj has a function Range it

See merge request jschoeberl/netgen!207
This commit is contained in:
Joachim Schöberl 2019-08-21 11:22:03 +00:00
commit 0c31102638
7 changed files with 155 additions and 37 deletions

View File

@ -59,7 +59,6 @@ namespace ngcore
}
template <typename AO>
class AOWrapperIterator
{
@ -210,7 +209,7 @@ namespace ngcore
template <typename T>
constexpr size_t IndexBASE () { return 0; }
constexpr T IndexBASE () { return T(0); }
template <class T, class IndexType = size_t> class FlatArray;
@ -293,21 +292,39 @@ namespace ngcore
return T_Range<T>(a,b);
}
template<typename T>
NETGEN_INLINE auto Range (const T& ao)
-> typename std::enable_if<has_range<T>, decltype(std::declval<T>().Range())>::type
{ return ao.Range(); }
template <typename T>
NETGEN_INLINE T_Range<T> Range_impl (T n, std::true_type)
{
return T_Range<T> (0, n);
}
template <typename T>
NETGEN_INLINE auto Range_impl (const T & ao, std::false_type)
-> T_Range<decltype(ao.Size())>
template <typename TA>
NETGEN_INLINE auto Range_impl (const TA & ao, std::false_type)
-> T_Range<index_type<TA>>
{
return T_Range<decltype(ao.Size())> (0, ao.Size());
return T_Range<index_type<TA>> (IndexBASE<index_type<TA>>(),
IndexBASE<index_type<TA>>() + index_type<TA>(ao.Size()));
}
/*
Range(obj) will create a range in using the following steps:
* if obj is an integral type it will create T_Range<type(obj)>(0, obj)
* if obj has a function Range() it will return obj.Range()
* if obj has a typedef index_type it will return
T_Range<index_type>(IndexBASE<index_type>(), IndexBASE<index_type>() + index_type(obj.Size()))
* else it will return T_Range<size_t> (0, obj.Size())
*/
template <typename T>
auto Range(const T & x) -> decltype(Range_impl(x, std::is_integral<T>())) {
auto Range(const T & x)
-> typename std::enable_if<std::is_integral_v<T> || !has_range<T>,
decltype(Range_impl(x, std::is_integral<T>()))>::type {
return Range_impl(x, std::is_integral<T>());
}
@ -402,7 +419,7 @@ namespace ngcore
class FlatArray : public BaseArrayObject<FlatArray<T,IndexType> >
{
protected:
static constexpr size_t BASE = IndexBASE<IndexType>();
static constexpr IndexType BASE = IndexBASE<IndexType>();
/// the size
size_t size;
/// the data
@ -500,9 +517,9 @@ namespace ngcore
return data[i-BASE];
}
NETGEN_INLINE T_Range<size_t> Range () const
NETGEN_INLINE T_Range<index_type> Range () const
{
return T_Range<size_t> (BASE, Size()+BASE);
return T_Range<index_type> (BASE, size+BASE);
}
NETGEN_INLINE const CArray<T> Addr (size_t pos) const
@ -623,6 +640,7 @@ namespace ngcore
using FlatArray<T,IndexType>::BASE;
public:
using index_type = typename FlatArray<T, IndexType>::index_type;
/// Generate array of logical and physical size asize
NETGEN_INLINE explicit Array()
: FlatArray<T,IndexType> (0, nullptr)
@ -788,42 +806,42 @@ namespace ngcore
}
/// Add element at end of array. reallocation if necessary.
NETGEN_INLINE size_t Append (const T & el)
/// Returns index of new element.
NETGEN_INLINE index_type Append (const T & el)
{
if (size == allocsize)
ReSize (size+1);
data[size] = el;
size++;
return size;
return BASE + size++;
}
/// Add element at end of array. reallocation not necessary.
NETGEN_INLINE size_t AppendHaveMem (const T & el)
/// Returns index of new element.
NETGEN_INLINE index_type AppendHaveMem (const T & el)
{
NETGEN_CHECK_RANGE(size, 0, allocsize);
data[size] = el;
size++;
return size;
return BASE + size++;
}
/// Add element at end of array. reallocation if necessary.
NETGEN_INLINE size_t Append (T && el)
/// Returns index of new element.
NETGEN_INLINE index_type Append (T && el)
{
if (size == allocsize)
ReSize (size+1);
data[size] = std::move(el);
size++;
return size;
return BASE + size++;
}
// Add elements of initializer list to end of array. Reallocation if necessary.
NETGEN_INLINE size_t Append(std::initializer_list<T> lst)
NETGEN_INLINE void Append(std::initializer_list<T> lst)
{
if(allocsize < size + lst.size())
ReSize(size+lst.size());
for(auto val : lst)
data[size++] = val;
return size;
}
/// Add element at end of array. reallocation if necessary.
@ -845,8 +863,7 @@ namespace ngcore
/// Append array at end of array. reallocation if necessary.
// int Append (const Array<T> & source)
NETGEN_INLINE size_t Append (FlatArray<T> source)
NETGEN_INLINE void Append (FlatArray<T> source)
{
if(size + source.Size() >= allocsize)
ReSize (size + source.Size() + 1);
@ -855,7 +872,6 @@ namespace ngcore
data[i] = source[j];
size += source.Size();
return size;
}
@ -872,6 +888,7 @@ namespace ngcore
/// Delete element i. Move all remaining elements forward
NETGEN_INLINE void RemoveElement (size_t i)
{
NETGEN_CHECK_RANGE(i, BASE, BASE+size);
for(size_t j = i; j < this->size-1; j++)
this->data[j] = this->data[j+1];
this->size--;

View File

@ -28,6 +28,29 @@ namespace ngcore
template<typename T>
constexpr bool is_any_pointer = is_any_pointer_impl<T>::value;
} // namespace detail
// Type trait to check if a class implements a 'range_type Range()' function
namespace detail
{
template<typename T>
struct has_Range
{
private:
template<typename T2>
static constexpr auto check(T2*) ->
std::enable_if_t<!std::is_same_v<decltype(std::declval<T2>().Range()), void>, std::true_type>
{ std::true_type(); }
template<typename>
static constexpr std::false_type check(...);
using type = decltype(check<T>(nullptr)); // NOLINT
public:
NGCORE_API static constexpr bool value = type::value;
};
}
template<typename T>
constexpr bool has_range = detail::has_Range<T>::value;
} // namespace ngcore
#endif // NETGEN_CORE_TYPE_TRAITS_HPP

View File

@ -126,6 +126,26 @@ namespace ngcore
return current;
}
namespace detail
{
template<typename T>
struct IndexTypeHelper
{
private:
template<typename T2>
static constexpr auto check(T2* t) -> typename T2::index_type { return *t; }
static constexpr size_t check(...);
public:
using type = decltype(check((T*) nullptr)); // NOLINT
};
} // namespace detail
// Get index type of object. If object has a typedef index_type it is this type, else size_t
template<typename T>
using index_type = typename detail::IndexTypeHelper<T>::type;
} // namespace ngcore
#endif // NETGEN_CORE_UTILS_HPP

View File

@ -84,6 +84,7 @@ namespace netgen
T * data;
public:
typedef T TELEM;
using index_type = TIND;
/// provide size and memory
NgFlatArray (size_t asize, T * adata)

View File

@ -162,7 +162,7 @@ namespace netgen
PointIndex & operator= (const PointIndex&) = default;
PointIndex & operator= (PointIndex&&) = default;
PointIndex (int ai) : i(ai)
constexpr PointIndex (int ai) : i(ai)
{
#ifdef DEBUG
if (ai < PointIndex::BASE)
@ -172,7 +172,7 @@ namespace netgen
}
constexpr PointIndex (t_invalid inv) : i(PointIndex::BASE-1) { ; }
// PointIndex & operator= (const PointIndex &ai) { i = ai.i; return *this; }
operator int () const { return i; }
constexpr operator int () const { return i; }
PointIndex operator++ (int) { PointIndex hi(*this); i++; return hi; }
PointIndex operator-- (int) { PointIndex hi(*this); i--; return hi; }
PointIndex operator++ () { i++; return *this; }
@ -180,9 +180,9 @@ namespace netgen
void Invalidate() { i = PointIndex::BASE-1; }
bool IsValid() const { return i != PointIndex::BASE-1; }
#ifdef BASE0
enum { BASE = 0 };
static constexpr size_t BASE = 0;
#else
enum { BASE = 1 };
static constexpr size_t BASE = 1;
#endif
void DoArchive (Archive & ar) { ar & i; }
@ -193,7 +193,7 @@ namespace netgen
namespace ngcore
{
template<>
constexpr size_t IndexBASE<netgen::PointIndex> () { return netgen::PointIndex::BASE; }
constexpr netgen::PointIndex IndexBASE<netgen::PointIndex> () { return netgen::PointIndex(netgen::PointIndex::BASE); }
}
namespace netgen
@ -255,14 +255,14 @@ namespace netgen
int i;
public:
SurfaceElementIndex () = default;
SurfaceElementIndex (int ai) : i(ai) { ; }
constexpr SurfaceElementIndex (int ai) : i(ai) { ; }
/*
SurfaceElementIndex & operator= (const SurfaceElementIndex & ai)
{ i = ai.i; return *this; }
*/
SurfaceElementIndex & operator= (const SurfaceElementIndex & ai) = default;
SurfaceElementIndex & operator= (int ai) { i = ai; return *this; }
operator int () const { return i; }
constexpr operator int () const { return i; }
SurfaceElementIndex operator++ (int) { SurfaceElementIndex hi(*this); i++; return hi; }
SurfaceElementIndex operator-- (int) { SurfaceElementIndex hi(*this); i--; return hi; }
SurfaceElementIndex & operator++ () { ++i; return *this; }

View File

@ -26,6 +26,7 @@ macro(add_unit_test name sources)
endmacro()
add_unit_test(archive archive.cpp)
add_unit_test(array array.cpp)
add_unit_test(symboltable symboltable.cpp)
add_unit_test(utils utils.cpp)
add_unit_test(version version.cpp)

View File

@ -1,9 +1,29 @@
#include "catch.hpp"
#include <array.hpp>
#include <core/array.hpp>
using namespace ngcore;
using namespace std;
#include "meshing.hpp"
template<typename TIND>
class ClsWithIndexType
{
size_t size;
public:
ClsWithIndexType(size_t asize) : size(asize) {}
using index_type = TIND;
size_t Size() const { return size; }
};
template<typename TIND>
class ClsWithRange : public ClsWithIndexType<TIND>
{
public:
ClsWithRange(size_t size) : ClsWithIndexType<TIND>(size) {}
T_Range<size_t> Range() const { return {1, 1+this->Size()}; }
};
TEST_CASE("Array")
{
@ -15,13 +35,14 @@ TEST_CASE("Array")
#endif // DEBUG
Array<double> a_initlst = { 1., 2., 3.};
CHECK(a_initlst[1] == 2.);
CHECK(a_initlst.size() == 3);
CHECK(a_initlst.Size() == 3);
FlatArray fa_a = a_initlst;
CHECK(typeid(fa_a) == typeid(FlatArray<double>));
CHECK(fa_a.size() == 3);
CHECK(a.Last() == 3.);
a.DeleteLast();
CHECK(a.Last() == 2. && a.Size() == 2);
CHECK(fa_a.Size() == 3);
CHECK(fa_a.Last() == 3.);
a_initlst.DeleteLast();
CHECK(a_initlst.Last() == 2.);
CHECK(a_initlst.Size() == 2);
#ifdef DEBUG
CHECK_THROWS_AS(fa_a[5], RangeException);
#endif // DEBUG
@ -34,4 +55,39 @@ TEST_CASE("Array")
CHECK(val == 2);
}
CHECK(count == 4);
// range tests
CHECK(typeid(array.Range()) == typeid(T_Range<size_t>));
Array<int, int> intarray;
CHECK(typeid(intarray.Range()) == typeid(T_Range<int>));
CHECK(typeid(Range(intarray)) == typeid(T_Range<int>));
int i = 0;
for(auto j : Range(b))
CHECK(j == i++);
i = 0;
for(auto j : b.Range())
CHECK(j == i++);
// pointindex is still 1 based
Array<double, netgen::PointIndex> piarray(2);
i = 1;
for(auto j : Range(piarray))
CHECK(j == i++);
i = 1;
for(auto j : piarray.Range())
CHECK(j == i++);
// a class can implement index_type and Size as well.
ClsWithIndexType<int> clsi(3);
CHECK(typeid(Range(clsi)) == typeid(T_Range<int>));
i = 0;
for(auto j : Range(clsi))
CHECK(j == i++);
// if the class has a Range function prefer that one
ClsWithRange<int> clsr(3);
CHECK(typeid(Range(clsr)) == typeid(T_Range<size_t>));
i=1;
for(auto j : Range(clsr))
CHECK(j == i++);
CHECK(typeid(Range(size_t(4))) == typeid(T_Range<size_t>));
CHECK(typeid(Range(4)) == typeid(T_Range<int>));
}