Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
U
usadelndsoc
Manage
Activity
Members
Labels
Plan
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
JYU Condensed Matter Theory
usadelndsoc
Commits
fbb0d4e6
Commit
fbb0d4e6
authored
2 years ago
by
patavirt
Browse files
Options
Downloads
Patches
Plain Diff
array: boundscheck as template param + add some doc
parent
205aca8f
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/array.hpp
+87
-47
87 additions, 47 deletions
src/array.hpp
with
87 additions
and
47 deletions
src/array.hpp
+
87
−
47
View file @
fbb0d4e6
/* usadelndsoc
*
* Copyright © 2022 Pauli Virtanen
* @author Pauli Virtanen <pauli.t.virtanen@jyu.fi>
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef ARRAY_HPP_
#define ARRAY_HPP_
...
...
@@ -11,7 +18,14 @@ namespace array {
constexpr
size_t
Dynamic
=
SIZE_MAX
;
/*! Array dimensions and strides: known at compile-time & dynamic
/**
* \class Shape
*
* \brief Array dimensions and strides. Either known at compile-time or dynamic.
*
* The Shape template keeps track of the dimensions and strides of a
* N-dimensional row-major array, with the shape given in its template argument
* pack.
*/
template
<
size_t
...>
struct
Shape
;
...
...
@@ -70,7 +84,12 @@ struct Shape<Dim0,Dims...>
namespace
detail
{
/*! Extract Nth tail shape
/** \class TailNth
*
* \brief Extract Nth tail shape.
*
* Helper template class to convert e.g. Shape<1,2,3,4,5>
* to its 2-nd tail Shape<3,4,5>.
*/
template
<
size_t
I
,
typename
Shape
>
struct
TailNth
;
...
...
@@ -87,18 +106,24 @@ namespace detail
using
type
=
typename
TailNth
<
I
-
1
,
typename
Shape
::
Tail
>::
type
;
};
/*! Base class for compile-time fixed size arrays
/**
* \class fixed_base
*
* \brief Base class for compile-time fixed size arrays
*
* The shape and stride information for arrays with known size. It is kept
* fully in compile-time quantities.
*/
template
<
typename
Shape
>
template
<
typename
Shape
,
bool
BoundsCheck
=
true
>
class
fixed_base
{
protected:
void
data_bounds_check
(
size_t
size
)
const
{
#ifndef NO_BOUNDS_CHECK
if
(
Shape
::
size
>
size
)
throw
std
::
out_of_range
(
"data array too small"
);
#endif
if
constexpr
(
BoundsCheck
)
{
if
(
Shape
::
size
>
size
)
throw
std
::
out_of_range
(
"data array too small"
);
}
}
public
:
...
...
@@ -112,28 +137,35 @@ namespace detail
constexpr
size_t
size
()
const
{
return
Shape
::
size
;
}
};
/*! Base class for compile-time dynamic size arrays
/**
* \class dynamic_base
*
* \brief Base class for compile-time dynamic size arrays
*
* Shape and stride information for dynamic arrays, stored in member
* variables.
*/
template
<
typename
Shape
>
template
<
typename
Shape
,
bool
BoundsCheck
=
true
>
class
dynamic_base
{
pr
otec
te
d
:
pr
iva
te:
std
::
array
<
size_t
,
Shape
::
ndim
>
shape_
;
std
::
array
<
size_t
,
Shape
::
ndim
>
strides_
;
protected:
void
data_bounds_check
(
size_t
size
)
const
{
#ifndef NO_BOUNDS_CHECK
size_t
total
=
1
;
for
(
size_t
i
=
0
;
i
<
Shape
::
ndim
;
++
i
)
{
total
*=
dim
(
i
);
if
(
shape_
[
i
]
!=
dim
(
i
))
throw
std
::
out_of_range
(
"mismatch with fixed shape"
);
if
constexpr
(
BoundsCheck
)
{
size_t
total
=
1
;
for
(
size_t
i
=
0
;
i
<
Shape
::
ndim
;
++
i
)
{
total
*=
dim
(
i
);
if
(
shape_
[
i
]
!=
dim
(
i
))
throw
std
::
out_of_range
(
"mismatch with fixed shape"
);
}
if
(
total
>
size
)
throw
std
::
out_of_range
(
"data array too small"
);
}
if
(
total
>
size
)
throw
std
::
out_of_range
(
"data array too small"
);
#endif
}
public
:
...
...
@@ -152,20 +184,20 @@ namespace detail
size_t
dim
(
size_t
axis
)
const
{
#ifndef NO_BOUNDS_CHECK
if
(
axis
>=
Shape
::
ndim
)
throw
std
::
out_of_range
(
"array axis must be < ndim"
);
#endif
if
constexpr
(
BoundsCheck
)
{
if
(
axis
>=
Shape
::
ndim
)
throw
std
::
out_of_range
(
"array axis must be < ndim"
);
}
size_t
n
=
Shape
::
dim
(
axis
);
return
n
==
Dynamic
?
shape_
[
axis
]
:
n
;
}
size_t
stride
(
size_t
axis
)
const
{
#ifndef NO_BOUNDS_CHECK
if
(
axis
>=
Shape
::
ndim
)
throw
std
::
out_of_range
(
"array axis must be < ndim"
);
#endif
if
constexpr
(
BoundsCheck
)
{
if
(
axis
>=
Shape
::
ndim
)
throw
std
::
out_of_range
(
"array axis must be < ndim"
);
}
size_t
n
=
Shape
::
stride
(
axis
);
return
n
==
Dynamic
?
strides_
[
axis
]
:
n
;
}
...
...
@@ -180,15 +212,23 @@ namespace detail
return
size
;
}
};
template
<
typename
Shape
,
bool
BoundsCheck
>
using
Base
=
std
::
conditional_t
<
Shape
::
fixed
,
detail
::
fixed_base
<
Shape
,
BoundsCheck
>
,
detail
::
dynamic_base
<
Shape
,
BoundsCheck
>
>
;
}
/*! Simple data-by-reference strided array class a la Fortran
/**
* \class Array
*
* \brief N-dimensional view to 1-dimensional array data
*
* Array view for index mapping to 1-dim array.
*/
template
<
typename
Scalar
,
typename
Shape
,
size_t
Alignment
=
0
>
class
Array
:
public
std
::
conditional_t
<
Shape
::
fixed
,
detail
::
fixed_b
ase
<
Shape
>
,
detail
::
dynamic_base
<
Shape
>
>
template
<
typename
Scalar
,
typename
Shape
,
size_t
Alignment
=
0
,
bool
BoundsCheck
=
true
>
class
Array
:
public
detail
::
B
ase
<
Shape
,
BoundsCheck
>
{
private:
typedef
std
::
conditional_t
<
Shape
::
fixed
,
detail
::
fixed_b
ase
<
Shape
>
,
detail
::
dynamic_base
<
Shape
>
>
Base
;
typedef
detail
::
B
ase
<
Shape
,
BoundsCheck
>
Base
;
Scalar
*
data_
;
...
...
@@ -218,10 +258,10 @@ public:
{
static_assert
(
!
Shape
::
fixed
,
"array shape must not be compile-time fixed"
);
Base
::
data_bounds_check
(
size
);
#ifndef NO_BOUNDS_CHECK
if
(
reinterpret_cast
<
intptr_t
>
(
data
)
%
alignment
()
!=
0
)
throw
std
::
runtime_error
(
"data is not aligned"
);
#endif
if
constexpr
(
BoundsCheck
)
{
if
(
reinterpret_cast
<
intptr_t
>
(
data
)
%
alignment
()
!=
0
)
throw
std
::
runtime_error
(
"data is not aligned"
);
}
}
Array
(
Scalar
*
data
,
size_t
size
)
...
...
@@ -229,10 +269,10 @@ public:
{
static_assert
(
Shape
::
fixed
,
"array shape must be compile-time fixed"
);
Base
::
data_bounds_check
(
size
);
#ifndef NO_BOUNDS_CHECK
if
(
reinterpret_cast
<
intptr_t
>
(
data
)
%
alignment
()
!=
0
)
throw
std
::
runtime_error
(
"data is not aligned"
);
#endif
if
constexpr
(
BoundsCheck
)
{
if
(
reinterpret_cast
<
intptr_t
>
(
data
)
%
alignment
()
!=
0
)
throw
std
::
runtime_error
(
"data is not aligned"
);
}
}
template
<
typename
...
Idx
>
...
...
@@ -276,16 +316,16 @@ public:
for
(
size_t
i
=
0
;
i
<
sizeof
...(
idxs
);
++
i
)
{
idx
+=
Base
::
stride
(
i
)
*
m
[
i
];
#ifndef NO_BOUNDS_CHECK
if
(
m
[
i
]
>=
Base
::
dim
(
i
))
throw
std
::
out_of_range
(
"index out of bounds"
);
#endif
if
constexpr
(
BoundsCheck
)
{
if
(
m
[
i
]
>=
Base
::
dim
(
i
))
throw
std
::
out_of_range
(
"index out of bounds"
);
}
}
return
idx
;
}
/*
!
Extract partial matrix (compile-time fixed size) */
/*
*
Extract partial matrix (compile-time fixed size) */
template
<
typename
...
Idx
>
typename
std
::
enable_if
<
detail
::
TailNth
<
sizeof
...(
Idx
),
Shape
>::
type
::
fixed
,
Array
<
Scalar
,
typename
detail
::
TailNth
<
sizeof
...(
Idx
),
Shape
>::
type
>
>::
type
...
...
@@ -299,7 +339,7 @@ public:
return
{
data_
+
offset
,
Base
::
size
()
-
offset
};
}
/*
!
Extract partial matrix (compile-time dynamic size) */
/*
*
Extract partial matrix (compile-time dynamic size) */
template
<
typename
...
Idx
>
typename
std
::
enable_if
<!
detail
::
TailNth
<
sizeof
...(
Idx
),
Shape
>::
type
::
fixed
,
Array
<
Scalar
,
typename
detail
::
TailNth
<
sizeof
...(
Idx
),
Shape
>::
type
>
>::
type
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment