forked from DlangScience/scid
-
Notifications
You must be signed in to change notification settings - Fork 8
/
assertmessages.d
173 lines (149 loc) · 5.57 KB
/
assertmessages.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/** Common error messages to use with assertions.
Authors: Cristian Cobzarenco
Copyright: Copyright (c) 2011, Cristian Cobzarenco. All rights reserved.
License: Boost License 1.0
*/
module scid.internal.assertmessages;
import std.string;
import std.range, std.conv;
package alias to!string tos;
/** Checks and error messages for array-like structs. */
mixin template ArrayChecks() {
/** Check that an index is within the bounds. */
void checkBounds_( size_t i ) const {
auto len = this.length;
assert( i < len, "Out of bounds: i = " ~ tos( i ) ~ ", length = " ~ tos( len ) );
}
/** Check that slice indices are valid. */
void checkSliceIndices_( size_t start, size_t end ) const {
auto len = this.length;
assert( start <= end && end <= len,
"Invalid slicing indices: start = " ~ tos( start ) ~ ", end = " ~ tos( end ) );
}
/** Check that the lengths in a slice assignment match. */
void checkSliceAssignLength_( size_t start, size_t end, size_t rhsLength ) const {
auto sliceLength = end - start;
auto len = this.length;
assert( start <= end && end <= len && sliceLength == rhsLength,
"Length mismatch in slice assignment: start = " ~ tos( start ) ~
", end = " ~ tos( end ) ~
", rhsLength = " ~ tos( rhsLength )
);
}
/** Check that the lengths in an assignment match. */
void checkAssignLength_( size_t rhsLength ) const {
auto len = this.length;
assert( len == rhsLength,
"Length mismatch in assignment: length = " ~ tos( len ) ~ ", rhsLength = " ~ tos( rhsLength ) ~ "."
);
}
/** Check that the range is not empty. */
void checkNotEmpty_( string op = "function" )() const {
assert( !this.empty,
"Invalid " ~ op ~ " call on empty range." );
}
}
/** Checks and error messages for matrix-like structs (matrix literal, storages and containers). */
mixin template MatrixChecks() {
/** Check that an index is within the bounds. */
void checkBounds_( size_t i, size_t j ) const {
auto r = this.rows, c = this.columns;
assert( i < r && j < c, "Out of bounds: (i,j) = (" ~ tos( i ) ~ ", " ~ tos( j ) ~ "), dimensions = (" ~ tos( r ) ~ ", " ~ tos( c ) ~ ")" );
}
/** Check that slice indices are valid. */
void checkSliceIndices_( size_t rowStart, size_t rowEnd, size_t colStart, size_t colEnd ) const {
auto r = this.rows, c = this.columns;
assert( rowStart <= rowEnd && rowEnd <= r && colStart <= colEnd && colEnd <= c,
"Invalid slicing indices [ " ~ tos( rowStart ) ~ " .. " ~ tos( rowEnd ) ~ " ][ "
~ tos( colStart ) ~ " .. " ~ tos( colEnd ) ~ "], dimensions = (" ~ tos( r ) ~ ", " ~ tos( c ) ~ ")"
);
}
/** Check that a built-in array of arrays is a valid general matrix. */
static void checkGeneralInitializer_( E )( E[][] mat ) {
debug {
if( !mat.length )
return;
size_t cols = mat[ 0 ].length;
foreach( i, row ; mat )
assert( row.length == cols,
"Inconsistent number of columns in general matrix initializer: row(0).length = " ~ tos( cols ) ~
", row(" ~ tos( i ) ~ ").length = " ~ tos( row.length )
);
}
}
/** Check that a major dimension and an array form a valid general matrix initializer. */
static void checkGeneralInitializer_( E )( size_t majorDimension, E[] initializer ) {
assert( ( (majorDimension != 0) ^ initializer.empty) && initializer.length % majorDimension == 0,
"Invalid initializer for general matrix: majorDimension = " ~ tos( majorDimension ) ~
", initializer.length = " ~ tos( initializer.length )
);
}
/** Check triangular initializer. */
static void checkTriangularInitializer_( E )( E[] initializer ) {
debug {
import std.math;
auto tri = (sqrt( initializer.length * 8.0 + 1.0 ) - 1.0 ) / 2.0;
assert( tri - cast(int) tri <= 0,
"Initializer length is not triangular number: initializer.length = " ~ tos( initializer.length )
);
}
}
/** Check that dimensions passed to a square matrix type are equal. */
static void checkSquareDims_( string matrixType = "square" )( size_t newRows, size_t newCols ) {
assert( newRows == newCols,
"Non-square dimensions for " ~ matrixType ~ " matrix (" ~ tos( newRows ) ~ ", " ~ tos( newCols ) ~ ")"
);
}
/** Check that the range is not empty. */
void checkNotEmpty_( string op = "function" )() const {
assert( !this.empty,
"Invalid " ~ op ~ " call on empty range." );
}
/** Check that dimensions match in assignment. */
void checkAssignDims_( size_t rhsRows, size_t rhsColumns ) const {
auto r = this.rows, c = this.columns;
assert( r == rhsRows && c == rhsColumns,
"Dimension mismatch in matrix assignment: lhsDims = (" ~ tos( r ) ~ ", " ~ tos( c ) ~ "), rhsDims = (" ~
tos( rhsRows ) ~ ", " ~ tos( rhsColumns ) ~ ")"
);
}
}
string stridedToString( S )( const(S)* ptr, size_t len, size_t stride ) {
if( len == 0 )
return "[]";
auto app = appender!string("[");
app.put( to!string(*ptr) );
auto e = ptr + len * stride;
for( ptr += stride; ptr < e ; ptr += stride ) {
app.put( ", " );
app.put( to!string( *ptr ) );
}
app.put(']');
return app.data();
}
string matrixToString( S )( char trans, size_t m, size_t n, const(S)* a, size_t lda )
in {
assert( a || (!m || !n) );
} body {
if( m == 0 || n == 0 )
return "[]";
auto app = appender!string("[");
if( trans == 'n' ) {
app.put( stridedToString( a, n, lda ) );
auto e = a + m;
for( ++ a; a < e ; ++a ) {
app.put( ", " );
app.put( stridedToString( a, n, lda ) );
}
app.put(']');
} else {
app.put( stridedToString(a, m, 1) );
auto e = a + n * lda;
for( a += lda ; a < e ; a += lda ) {
app.put( ", " );
app.put( stridedToString( a, m, 1 ) );
}
app.put(']');
}
return app.data();
}