mirror of
https://github.com/NGSolve/netgen.git
synced 2025-01-12 22:20:35 +05:00
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:
commit
0c31102638
@ -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--;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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; }
|
||||
|
@ -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)
|
||||
|
@ -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>));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user