nmatrix 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -8
- data/.rspec +1 -1
- data/.travis.yml +12 -0
- data/CONTRIBUTING.md +27 -12
- data/Gemfile +1 -0
- data/History.txt +38 -0
- data/Manifest.txt +15 -15
- data/README.rdoc +7 -6
- data/Rakefile +40 -5
- data/ext/nmatrix/data/data.cpp +2 -37
- data/ext/nmatrix/data/data.h +19 -121
- data/ext/nmatrix/data/meta.h +70 -0
- data/ext/nmatrix/extconf.rb +40 -12
- data/ext/nmatrix/math/math.h +13 -103
- data/ext/nmatrix/nmatrix.cpp +10 -2018
- data/ext/nmatrix/nmatrix.h +16 -13
- data/ext/nmatrix/ruby_constants.cpp +12 -1
- data/ext/nmatrix/ruby_constants.h +7 -1
- data/ext/nmatrix/ruby_nmatrix.c +2169 -0
- data/ext/nmatrix/storage/dense.cpp +123 -14
- data/ext/nmatrix/storage/dense.h +10 -4
- data/ext/nmatrix/storage/list.cpp +265 -48
- data/ext/nmatrix/storage/list.h +6 -9
- data/ext/nmatrix/storage/storage.cpp +44 -54
- data/ext/nmatrix/storage/storage.h +2 -2
- data/ext/nmatrix/storage/yale/class.h +1070 -0
- data/ext/nmatrix/storage/yale/iterators/base.h +142 -0
- data/ext/nmatrix/storage/yale/iterators/iterator.h +130 -0
- data/ext/nmatrix/storage/yale/iterators/row.h +449 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored.h +139 -0
- data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +167 -0
- data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +123 -0
- data/ext/nmatrix/storage/yale/math/transpose.h +110 -0
- data/ext/nmatrix/storage/yale/yale.cpp +1785 -0
- data/ext/nmatrix/storage/{yale.h → yale/yale.h} +23 -55
- data/ext/nmatrix/types.h +2 -0
- data/ext/nmatrix/util/io.cpp +27 -45
- data/ext/nmatrix/util/io.h +0 -2
- data/ext/nmatrix/util/sl_list.cpp +169 -28
- data/ext/nmatrix/util/sl_list.h +9 -3
- data/lib/nmatrix/blas.rb +20 -20
- data/lib/nmatrix/enumerate.rb +1 -1
- data/lib/nmatrix/io/mat5_reader.rb +8 -14
- data/lib/nmatrix/lapack.rb +3 -3
- data/lib/nmatrix/math.rb +3 -3
- data/lib/nmatrix/nmatrix.rb +19 -5
- data/lib/nmatrix/nvector.rb +2 -0
- data/lib/nmatrix/shortcuts.rb +90 -125
- data/lib/nmatrix/version.rb +1 -1
- data/nmatrix.gemspec +7 -8
- data/spec/{nmatrix_spec.rb → 00_nmatrix_spec.rb} +45 -208
- data/spec/01_enum_spec.rb +184 -0
- data/spec/{slice_spec.rb → 02_slice_spec.rb} +55 -39
- data/spec/blas_spec.rb +22 -54
- data/spec/elementwise_spec.rb +9 -8
- data/spec/io_spec.rb +6 -4
- data/spec/lapack_spec.rb +26 -26
- data/spec/math_spec.rb +9 -5
- data/spec/nmatrix_yale_spec.rb +29 -61
- data/spec/shortcuts_spec.rb +34 -22
- data/spec/slice_set_spec.rb +157 -0
- data/spec/spec_helper.rb +42 -2
- data/spec/stat_spec.rb +192 -0
- metadata +52 -55
- data/ext/nmatrix/storage/yale.cpp +0 -2284
- data/spec/nmatrix_list_spec.rb +0 -113
- data/spec/nvector_spec.rb +0 -112
@@ -43,18 +43,16 @@
|
|
43
43
|
*/
|
44
44
|
|
45
45
|
#include <limits> // for std::numeric_limits<T>::max()
|
46
|
+
#include <stdexcept>
|
46
47
|
|
47
48
|
/*
|
48
49
|
* Project Includes
|
49
50
|
*/
|
50
51
|
|
51
|
-
#include "types.h"
|
52
|
-
|
53
|
-
#include "
|
54
|
-
|
55
|
-
#include "common.h"
|
56
|
-
|
57
|
-
#include "nmatrix.h"
|
52
|
+
#include "../../types.h"
|
53
|
+
#include "../../data/data.h"
|
54
|
+
#include "../common.h"
|
55
|
+
#include "../../nmatrix.h"
|
58
56
|
|
59
57
|
extern "C" {
|
60
58
|
|
@@ -62,8 +60,6 @@ extern "C" {
|
|
62
60
|
* Macros
|
63
61
|
*/
|
64
62
|
|
65
|
-
#define NM_YALE_MINIMUM(sptr) (((YALE_STORAGE*)(sptr))->shape[0]*2 + 1) // arbitrarily defined
|
66
|
-
|
67
63
|
#ifndef NM_CHECK_ALLOC
|
68
64
|
#define NM_CHECK_ALLOC(x) if (!x) rb_raise(rb_eNoMemError, "insufficient memory");
|
69
65
|
#endif
|
@@ -86,13 +82,13 @@ extern "C" {
|
|
86
82
|
// Lifecycle //
|
87
83
|
///////////////
|
88
84
|
|
89
|
-
YALE_STORAGE* nm_yale_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, size_t init_capacity
|
90
|
-
YALE_STORAGE* nm_yale_storage_create_from_old_yale(nm::dtype_t dtype, size_t* shape,
|
85
|
+
YALE_STORAGE* nm_yale_storage_create(nm::dtype_t dtype, size_t* shape, size_t dim, size_t init_capacity);
|
86
|
+
YALE_STORAGE* nm_yale_storage_create_from_old_yale(nm::dtype_t dtype, size_t* shape, char* ia, char* ja, char* a, nm::dtype_t from_dtype);
|
91
87
|
YALE_STORAGE* nm_yale_storage_create_merged(const YALE_STORAGE* merge_template, const YALE_STORAGE* other);
|
92
88
|
void nm_yale_storage_delete(STORAGE* s);
|
93
89
|
void nm_yale_storage_delete_ref(STORAGE* s);
|
94
90
|
void nm_yale_storage_init(YALE_STORAGE* s, void* default_val);
|
95
|
-
void nm_yale_storage_mark(
|
91
|
+
void nm_yale_storage_mark(STORAGE*);
|
96
92
|
|
97
93
|
///////////////
|
98
94
|
// Accessors //
|
@@ -100,9 +96,12 @@ extern "C" {
|
|
100
96
|
|
101
97
|
VALUE nm_yale_each_with_indices(VALUE nmatrix);
|
102
98
|
VALUE nm_yale_each_stored_with_indices(VALUE nmatrix);
|
103
|
-
|
104
|
-
|
105
|
-
|
99
|
+
VALUE nm_yale_stored_diagonal_each_with_indices(VALUE nmatrix);
|
100
|
+
VALUE nm_yale_stored_nondiagonal_each_with_indices(VALUE nmatrix);
|
101
|
+
VALUE nm_yale_each_ordered_stored_with_indices(VALUE nmatrix);
|
102
|
+
void* nm_yale_storage_get(const STORAGE* s, SLICE* slice);
|
103
|
+
void* nm_yale_storage_ref(const STORAGE* s, SLICE* slice);
|
104
|
+
void nm_yale_storage_set(VALUE left, SLICE* slice, VALUE right);
|
106
105
|
|
107
106
|
//char nm_yale_storage_vector_insert(YALE_STORAGE* s, size_t pos, size_t* js, void* vals, size_t n, bool struct_only, nm::dtype_t dtype, nm::itype_t itype);
|
108
107
|
//void nm_yale_storage_increment_ia_after(YALE_STORAGE* s, size_t ija_size, size_t i, size_t n);
|
@@ -128,39 +127,6 @@ extern "C" {
|
|
128
127
|
// Utility //
|
129
128
|
/////////////
|
130
129
|
|
131
|
-
/*
|
132
|
-
* Calculates the itype a YALE_STORAGE object would need without actually needing
|
133
|
-
* to see the YALE_STORAGE object. Does this just by looking at the shape.
|
134
|
-
*
|
135
|
-
* Useful for creating Yale Storage by other means than NMatrix.new(:yale, ...),
|
136
|
-
* e.g., from a MATLAB v5 .mat file.
|
137
|
-
*/
|
138
|
-
inline nm::itype_t nm_yale_storage_itype_by_shape(const size_t* shape) {
|
139
|
-
uint64_t yale_max_size = shape[0] * (shape[1]+1);
|
140
|
-
|
141
|
-
if (yale_max_size < static_cast<uint64_t>(std::numeric_limits<uint8_t>::max()) - 2) {
|
142
|
-
return nm::UINT8;
|
143
|
-
|
144
|
-
} else if (yale_max_size < static_cast<uint64_t>(std::numeric_limits<uint16_t>::max()) - 2) {
|
145
|
-
return nm::UINT16;
|
146
|
-
|
147
|
-
} else if (yale_max_size < std::numeric_limits<uint32_t>::max() - 2) {
|
148
|
-
return nm::UINT32;
|
149
|
-
|
150
|
-
} else {
|
151
|
-
return nm::UINT64;
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
/*
|
156
|
-
* Determine the index dtype (which will be used for the ija vector). This is
|
157
|
-
* determined by matrix shape, not IJA/A vector capacity. Note that it's MAX-2
|
158
|
-
* because UINTX_MAX and UINTX_MAX-1 are both reserved for sparse matrix
|
159
|
-
* multiplication.
|
160
|
-
*/
|
161
|
-
inline nm::itype_t nm_yale_storage_default_itype(const YALE_STORAGE* s) {
|
162
|
-
return nm_yale_storage_itype_by_shape(s->shape);
|
163
|
-
}
|
164
130
|
|
165
131
|
|
166
132
|
/////////////////////////
|
@@ -179,19 +145,21 @@ extern "C" {
|
|
179
145
|
|
180
146
|
} // end of extern "C" block
|
181
147
|
|
182
|
-
namespace nm {
|
148
|
+
namespace nm {
|
149
|
+
|
150
|
+
namespace yale_storage {
|
183
151
|
|
184
152
|
/*
|
185
|
-
*
|
153
|
+
* Typedefs
|
186
154
|
*/
|
187
|
-
|
155
|
+
|
156
|
+
typedef size_t IType;
|
188
157
|
|
189
158
|
|
190
159
|
/*
|
191
160
|
* Templated Functions
|
192
161
|
*/
|
193
162
|
|
194
|
-
template <typename IType>
|
195
163
|
int binary_search(YALE_STORAGE* s, IType left, IType right, IType key);
|
196
164
|
|
197
165
|
/*
|
@@ -217,14 +185,14 @@ namespace nm { namespace yale_storage {
|
|
217
185
|
}
|
218
186
|
}
|
219
187
|
|
220
|
-
template <typename DType
|
188
|
+
template <typename DType>
|
221
189
|
void init(YALE_STORAGE* s, void* init_val);
|
222
190
|
|
223
|
-
template <typename IType>
|
224
191
|
size_t get_size(const YALE_STORAGE* storage);
|
225
192
|
|
226
|
-
template <typename IType>
|
227
193
|
IType binary_search_left_boundary(const YALE_STORAGE* s, IType left, IType right, IType bound);
|
194
|
+
|
195
|
+
|
228
196
|
}} // end of namespace nm::yale_storage
|
229
197
|
|
230
198
|
#endif // YALE_H
|
data/ext/nmatrix/types.h
CHANGED
data/ext/nmatrix/util/io.cpp
CHANGED
@@ -74,8 +74,8 @@ namespace nm { namespace io {
|
|
74
74
|
template <typename DType, typename MDType>
|
75
75
|
char* matlab_cstring_to_dtype_string(size_t& result_len, const char* str, size_t bytes) {
|
76
76
|
|
77
|
-
result_len = bytes / sizeof(
|
78
|
-
char* result = ALLOC_N(char,
|
77
|
+
result_len = sizeof(DType) * bytes / sizeof(MDType);
|
78
|
+
char* result = ALLOC_N(char, result_len);
|
79
79
|
|
80
80
|
if (bytes % sizeof(MDType) != 0) {
|
81
81
|
rb_raise(rb_eArgError, "the given string does not divide evenly for the given MATLAB dtype");
|
@@ -109,7 +109,7 @@ nm::dtype_t nm_dtype_from_rbstring(VALUE str) {
|
|
109
109
|
}
|
110
110
|
}
|
111
111
|
|
112
|
-
rb_raise(rb_eArgError, "
|
112
|
+
rb_raise(rb_eArgError, "invalid data type string (%s) specified", RSTRING_PTR(str));
|
113
113
|
}
|
114
114
|
|
115
115
|
|
@@ -117,31 +117,19 @@ nm::dtype_t nm_dtype_from_rbstring(VALUE str) {
|
|
117
117
|
* Converts a symbol to a data type.
|
118
118
|
*/
|
119
119
|
nm::dtype_t nm_dtype_from_rbsymbol(VALUE sym) {
|
120
|
+
ID sym_id = SYM2ID(sym);
|
120
121
|
|
121
122
|
for (size_t index = 0; index < NM_NUM_DTYPES; ++index) {
|
122
|
-
if (
|
123
|
+
if (sym_id == rb_intern(DTYPE_NAMES[index])) {
|
123
124
|
return static_cast<nm::dtype_t>(index);
|
124
125
|
}
|
125
126
|
}
|
126
127
|
|
127
|
-
|
128
|
+
VALUE str = rb_any_to_s(sym);
|
129
|
+
rb_raise(rb_eArgError, "invalid data type symbol (:%s) specified", RSTRING_PTR(str));
|
128
130
|
}
|
129
131
|
|
130
132
|
|
131
|
-
/*
|
132
|
-
* Converts a symbol to an index type.
|
133
|
-
*/
|
134
|
-
nm::itype_t nm_itype_from_rbsymbol(VALUE sym) {
|
135
|
-
|
136
|
-
for (size_t index = 0; index < NM_NUM_ITYPES; ++index) {
|
137
|
-
if (SYM2ID(sym) == rb_intern(ITYPE_NAMES[index])) {
|
138
|
-
return static_cast<nm::itype_t>(index);
|
139
|
-
}
|
140
|
-
}
|
141
|
-
|
142
|
-
rb_raise(rb_eArgError, "Invalid index type specified.");
|
143
|
-
}
|
144
|
-
|
145
133
|
/*
|
146
134
|
* Converts a string to a storage type. Only looks at the first three
|
147
135
|
* characters.
|
@@ -169,7 +157,8 @@ nm::stype_t nm_stype_from_rbsymbol(VALUE sym) {
|
|
169
157
|
}
|
170
158
|
}
|
171
159
|
|
172
|
-
|
160
|
+
VALUE str = rb_any_to_s(sym);
|
161
|
+
rb_raise(rb_eArgError, "invalid storage type symbol (:%s) specified", RSTRING_PTR(str));
|
173
162
|
return nm::DENSE_STORE;
|
174
163
|
}
|
175
164
|
|
@@ -197,35 +186,28 @@ static nm::io::matlab_dtype_t matlab_dtype_from_rbsymbol(VALUE sym) {
|
|
197
186
|
* Arguments:
|
198
187
|
* * str :: the data
|
199
188
|
* * from :: symbol representing MATLAB data type (e.g., :miINT8)
|
200
|
-
* *
|
201
|
-
* what to give as output.
|
189
|
+
* * type :: either :itype or some dtype symbol (:byte, :uint32, etc)
|
202
190
|
*/
|
203
|
-
static VALUE nm_rbstring_matlab_repack(VALUE self, VALUE str, VALUE from, VALUE
|
191
|
+
static VALUE nm_rbstring_matlab_repack(VALUE self, VALUE str, VALUE from, VALUE type) {
|
204
192
|
nm::io::matlab_dtype_t from_type = matlab_dtype_from_rbsymbol(from);
|
205
193
|
uint8_t to_type;
|
206
194
|
|
207
|
-
if (
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
// is a dtype (both are 0, itype and dtype), or we add 1 to the other itypes and treat them as
|
222
|
-
// signed.
|
223
|
-
to_type = static_cast<uint8_t>(to_itype);
|
224
|
-
if (to_itype != nm::UINT8) to_type += 1;
|
225
|
-
|
226
|
-
|
195
|
+
if (SYMBOL_P(type)) {
|
196
|
+
if (rb_to_id(type) == rb_intern("itype")) {
|
197
|
+
if (sizeof(size_t) == sizeof(int64_t)) {
|
198
|
+
to_type = static_cast<int8_t>(nm::INT64);
|
199
|
+
} else if (sizeof(size_t) == sizeof(int32_t)) {
|
200
|
+
to_type = static_cast<int8_t>(nm::INT32);
|
201
|
+
} else if (sizeof(size_t) == sizeof(int16_t)) {
|
202
|
+
to_type = static_cast<int8_t>(nm::INT16);
|
203
|
+
} else {
|
204
|
+
rb_raise(rb_eStandardError, "unhandled size_t definition");
|
205
|
+
}
|
206
|
+
} else {
|
207
|
+
to_type = static_cast<uint8_t>(nm_dtype_from_rbsymbol(type));
|
208
|
+
}
|
227
209
|
} else {
|
228
|
-
rb_raise(rb_eArgError, "
|
210
|
+
rb_raise(rb_eArgError, "expected symbol for third argument");
|
229
211
|
}
|
230
212
|
|
231
213
|
// For next few lines, see explanation above NM_MATLAB_DTYPE_TEMPLATE_TABLE definition in io.h.
|
@@ -241,7 +223,7 @@ static VALUE nm_rbstring_matlab_repack(VALUE self, VALUE str, VALUE from, VALUE
|
|
241
223
|
|
242
224
|
// Encode as 8-bit ASCII with a length -- don't want to hiccup on \0
|
243
225
|
VALUE result = rb_str_new(repacked_data, repacked_data_length);
|
244
|
-
|
226
|
+
xfree(repacked_data); // Don't forget to free what we allocated!
|
245
227
|
|
246
228
|
return result;
|
247
229
|
}
|
data/ext/nmatrix/util/io.h
CHANGED
@@ -41,7 +41,6 @@
|
|
41
41
|
* Extern Types
|
42
42
|
*/
|
43
43
|
extern const char* const DTYPE_NAMES[nm::NUM_DTYPES];
|
44
|
-
extern const char* const ITYPE_NAMES[nm::NUM_ITYPES];
|
45
44
|
|
46
45
|
namespace nm { namespace io {
|
47
46
|
/*
|
@@ -77,7 +76,6 @@ extern "C" {
|
|
77
76
|
nm::dtype_t nm_dtype_from_rbstring(VALUE str);
|
78
77
|
nm::stype_t nm_stype_from_rbsymbol(VALUE sym);
|
79
78
|
nm::stype_t nm_stype_from_rbstring(VALUE str);
|
80
|
-
nm::itype_t nm_itype_from_rbsymbol(VALUE sym);
|
81
79
|
|
82
80
|
void nm_init_io(void);
|
83
81
|
|
@@ -77,18 +77,18 @@ void del(LIST* list, size_t recursions) {
|
|
77
77
|
|
78
78
|
if (recursions == 0) {
|
79
79
|
//fprintf(stderr, " free_val: %p\n", curr->val);
|
80
|
-
|
80
|
+
xfree(curr->val);
|
81
81
|
|
82
82
|
} else {
|
83
83
|
//fprintf(stderr, " free_list: %p\n", list);
|
84
84
|
del((LIST*)curr->val, recursions - 1);
|
85
85
|
}
|
86
86
|
|
87
|
-
|
87
|
+
xfree(curr);
|
88
88
|
curr = next;
|
89
89
|
}
|
90
90
|
//fprintf(stderr, " free_list: %p\n", list);
|
91
|
-
|
91
|
+
xfree(list);
|
92
92
|
}
|
93
93
|
|
94
94
|
/*
|
@@ -116,6 +116,37 @@ void mark(LIST* list, size_t recursions) {
|
|
116
116
|
// Accessors //
|
117
117
|
///////////////
|
118
118
|
|
119
|
+
|
120
|
+
/*
|
121
|
+
* Given a list, insert key/val as the first entry in the list. Does not do any
|
122
|
+
* checks, just inserts.
|
123
|
+
*/
|
124
|
+
NODE* insert_first_node(LIST* list, size_t key, void* val, size_t val_size) {
|
125
|
+
NODE* ins = ALLOC(NODE);
|
126
|
+
ins->next = list->first;
|
127
|
+
|
128
|
+
void* val_copy = ALLOC_N(char, val_size);
|
129
|
+
memcpy(val_copy, val, val_size);
|
130
|
+
|
131
|
+
ins->val = reinterpret_cast<void*>(val_copy);
|
132
|
+
ins->key = key;
|
133
|
+
list->first = ins;
|
134
|
+
|
135
|
+
return ins;
|
136
|
+
}
|
137
|
+
|
138
|
+
NODE* insert_first_list(LIST* list, size_t key, LIST* l) {
|
139
|
+
NODE* ins = ALLOC(NODE);
|
140
|
+
ins->next = list->first;
|
141
|
+
|
142
|
+
ins->val = reinterpret_cast<void*>(l);
|
143
|
+
ins->key = key;
|
144
|
+
list->first = ins;
|
145
|
+
|
146
|
+
return ins;
|
147
|
+
}
|
148
|
+
|
149
|
+
|
119
150
|
/*
|
120
151
|
* Given a list and a key/value-ptr pair, create a node (and return that node).
|
121
152
|
* If NULL is returned, it means insertion failed.
|
@@ -156,11 +187,11 @@ NODE* insert(LIST* list, bool replace, size_t key, void* val) {
|
|
156
187
|
if (ins->key == key) {
|
157
188
|
// key already exists
|
158
189
|
if (replace) {
|
159
|
-
|
190
|
+
xfree(ins->val);
|
160
191
|
ins->val = val;
|
161
192
|
|
162
193
|
} else {
|
163
|
-
|
194
|
+
xfree(val);
|
164
195
|
}
|
165
196
|
|
166
197
|
return ins;
|
@@ -170,14 +201,14 @@ NODE* insert(LIST* list, bool replace, size_t key, void* val) {
|
|
170
201
|
}
|
171
202
|
}
|
172
203
|
|
204
|
+
|
205
|
+
|
173
206
|
/*
|
174
207
|
* Documentation goes here.
|
175
208
|
*/
|
176
209
|
NODE* insert_after(NODE* node, size_t key, void* val) {
|
177
|
-
NODE* ins;
|
178
|
-
|
179
210
|
//if (!(ins = malloc(sizeof(NODE)))) return NULL;
|
180
|
-
ins = ALLOC(NODE);
|
211
|
+
NODE* ins = ALLOC(NODE);
|
181
212
|
|
182
213
|
// insert 'ins' between 'node' and 'node->next'
|
183
214
|
ins->next = node->next;
|
@@ -190,22 +221,69 @@ NODE* insert_after(NODE* node, size_t key, void* val) {
|
|
190
221
|
return ins;
|
191
222
|
}
|
192
223
|
|
224
|
+
|
193
225
|
/*
|
194
|
-
*
|
226
|
+
* Insert a new node immediately after +node+, or replace the existing one if its key is a match.
|
195
227
|
*/
|
196
|
-
NODE*
|
228
|
+
NODE* replace_insert_after(NODE* node, size_t key, void* val, bool copy, size_t copy_size) {
|
229
|
+
if (node->next && node->next->key == key) {
|
230
|
+
|
231
|
+
// Should we copy into the current one or free and insert?
|
232
|
+
if (copy) memcpy(node->next->val, val, copy_size);
|
233
|
+
else {
|
234
|
+
xfree(node->next->val);
|
235
|
+
node->next->val = val;
|
236
|
+
}
|
237
|
+
|
238
|
+
return node->next;
|
239
|
+
|
240
|
+
} else { // no next node, or if there is one, it's greater than the current key
|
241
|
+
|
242
|
+
if (copy) {
|
243
|
+
void* val_copy = ALLOC_N(char, copy_size);
|
244
|
+
memcpy(val_copy, val, copy_size);
|
245
|
+
return insert_after(node, key, val_copy);
|
246
|
+
} else {
|
247
|
+
return insert_after(node, key, val);
|
248
|
+
}
|
249
|
+
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
|
255
|
+
/*
|
256
|
+
* Functions analogously to list::insert but this inserts a copy of the value instead of the original.
|
257
|
+
*/
|
258
|
+
NODE* insert_copy(LIST *list, bool replace, size_t key, void *val, size_t size) {
|
197
259
|
void *copy_val = ALLOC_N(char, size);
|
198
260
|
memcpy(copy_val, val, size);
|
199
261
|
|
262
|
+
return insert(list, replace, key, copy_val);
|
263
|
+
}
|
264
|
+
|
200
265
|
|
201
|
-
|
266
|
+
/*
|
267
|
+
* Returns the value pointer for some key. Doesn't free the memory for that value. Doesn't require a find operation,
|
268
|
+
* assumes finding has already been done. If rm is the first item in the list, prev should be NULL.
|
269
|
+
*/
|
270
|
+
void* remove_by_node(LIST* list, NODE* prev, NODE* rm) {
|
271
|
+
if (!prev) list->first = rm->next;
|
272
|
+
else prev->next = rm->next;
|
273
|
+
|
274
|
+
void* val = rm->val;
|
275
|
+
xfree(rm);
|
276
|
+
|
277
|
+
return val;
|
202
278
|
}
|
279
|
+
|
280
|
+
|
203
281
|
/*
|
204
282
|
* Returns the value pointer (not the node) for some key. Note that it doesn't
|
205
283
|
* free the memory for the value stored in the node -- that pointer gets
|
206
284
|
* returned! Only the node is destroyed.
|
207
285
|
*/
|
208
|
-
void*
|
286
|
+
void* remove_by_key(LIST* list, size_t key) {
|
209
287
|
NODE *f, *rm;
|
210
288
|
void* val;
|
211
289
|
|
@@ -218,12 +296,12 @@ void* remove(LIST* list, size_t key) {
|
|
218
296
|
rm = list->first;
|
219
297
|
|
220
298
|
list->first = rm->next;
|
221
|
-
|
299
|
+
xfree(rm);
|
222
300
|
|
223
301
|
return val;
|
224
302
|
}
|
225
303
|
|
226
|
-
f =
|
304
|
+
f = find_preceding_from_node(list->first, key);
|
227
305
|
if (!f || !f->next) { // not found, end of list
|
228
306
|
return NULL;
|
229
307
|
}
|
@@ -235,7 +313,7 @@ void* remove(LIST* list, size_t key) {
|
|
235
313
|
|
236
314
|
// get the value and free the memory for the node
|
237
315
|
val = rm->val;
|
238
|
-
|
316
|
+
xfree(rm);
|
239
317
|
|
240
318
|
return val;
|
241
319
|
}
|
@@ -244,29 +322,56 @@ void* remove(LIST* list, size_t key) {
|
|
244
322
|
}
|
245
323
|
|
246
324
|
|
325
|
+
bool node_is_within_slice(NODE* n, size_t coord, size_t len) {
|
326
|
+
if (!n) return false;
|
327
|
+
if (n->key >= coord && n->key < coord + len) return true;
|
328
|
+
else return false;
|
329
|
+
}
|
330
|
+
|
331
|
+
|
247
332
|
/*
|
248
333
|
* Recursive removal of lists that may contain sub-lists. Stores the value ultimately removed in rm.
|
249
|
-
*
|
250
|
-
* FIXME: Could be made slightly faster by using a variety of find which also returns the previous node. This way,
|
251
|
-
* FIXME: we can remove directly instead of calling remove() and doing the search over again.
|
252
334
|
*/
|
253
|
-
bool remove_recursive(LIST* list, const size_t* coords, const size_t*
|
335
|
+
bool remove_recursive(LIST* list, const size_t* coords, const size_t* offsets, const size_t* lengths, size_t r, const size_t& dim) {
|
336
|
+
// std::cerr << "remove_recursive: " << r << std::endl;
|
337
|
+
// find the current coordinates in the list
|
338
|
+
NODE* prev = find_preceding_from_list(list, coords[r] + offsets[r]);
|
339
|
+
NODE* n;
|
340
|
+
if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
|
341
|
+
else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
|
254
342
|
|
255
343
|
if (r < dim-1) { // nodes here are lists
|
256
|
-
// find the current coordinates in the list
|
257
|
-
NODE* n = find(list, coords[r] + offset[r]);
|
258
344
|
|
259
|
-
|
345
|
+
while (n) {
|
260
346
|
// from that sub-list, call remove_recursive.
|
261
|
-
bool remove_parent = remove_recursive(reinterpret_cast<LIST*>(n->val), coords,
|
347
|
+
bool remove_parent = remove_recursive(reinterpret_cast<LIST*>(n->val), coords, offsets, lengths, r+1, dim);
|
262
348
|
|
263
349
|
if (remove_parent) { // now empty -- so remove the sub-list
|
264
|
-
|
350
|
+
// std::cerr << r << ": removing parent list at " << n->key << std::endl;
|
351
|
+
xfree(remove_by_node(list, prev, n));
|
352
|
+
|
353
|
+
if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
|
354
|
+
else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
|
355
|
+
} else {
|
356
|
+
// Move forward to next node (list at n still exists)
|
357
|
+
prev = n;
|
358
|
+
n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
|
265
359
|
}
|
360
|
+
|
361
|
+
// Iterate to next one.
|
362
|
+
if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
|
363
|
+
else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
|
266
364
|
}
|
267
365
|
|
268
366
|
} else { // nodes here are not lists, but actual values
|
269
|
-
|
367
|
+
|
368
|
+
while (n) {
|
369
|
+
// std::cerr << r << ": removing node at " << n->key << std::endl;
|
370
|
+
xfree(remove_by_node(list, prev, n));
|
371
|
+
|
372
|
+
if (prev) n = prev->next && node_is_within_slice(prev->next, coords[r] + offsets[r], lengths[r]) ? prev->next : NULL;
|
373
|
+
else n = node_is_within_slice(list->first, coords[r] + offsets[r], lengths[r]) ? list->first : NULL;
|
374
|
+
}
|
270
375
|
}
|
271
376
|
|
272
377
|
if (!list->first) return true; // if current list is now empty, signal its removal
|
@@ -303,21 +408,57 @@ NODE* find(LIST* list, size_t key) {
|
|
303
408
|
return NULL;
|
304
409
|
}
|
305
410
|
|
411
|
+
|
412
|
+
|
413
|
+
/*
|
414
|
+
* Find some element in the list and return the node ptr for that key.
|
415
|
+
*/
|
416
|
+
NODE* find_with_preceding(LIST* list, size_t key, NODE*& prev) {
|
417
|
+
if (!prev) prev = list->first;
|
418
|
+
if (!prev) return NULL; // empty list, does not exist
|
419
|
+
|
420
|
+
if (prev->key == key) {
|
421
|
+
NODE* n = prev;
|
422
|
+
prev = NULL;
|
423
|
+
return n;
|
424
|
+
}
|
425
|
+
|
426
|
+
while (prev->next && prev->next->key < key) {
|
427
|
+
prev = prev->next;
|
428
|
+
}
|
429
|
+
|
430
|
+
return prev->next;
|
431
|
+
}
|
432
|
+
|
433
|
+
|
434
|
+
|
435
|
+
|
306
436
|
/*
|
307
437
|
* Finds the node that should go before whatever key we request, whether or not
|
308
438
|
* that key is present.
|
309
439
|
*/
|
310
|
-
NODE*
|
440
|
+
NODE* find_preceding_from_node(NODE* prev, size_t key) {
|
311
441
|
NODE* curr = prev->next;
|
312
442
|
|
313
443
|
if (!curr || key <= curr->key) {
|
314
444
|
return prev;
|
315
445
|
|
316
446
|
} else {
|
317
|
-
return
|
447
|
+
return find_preceding_from_node(curr, key);
|
318
448
|
}
|
319
449
|
}
|
320
450
|
|
451
|
+
|
452
|
+
/*
|
453
|
+
* Returns NULL if the key being sought is first in the list or *should* be first in the list but is absent. Otherwise
|
454
|
+
* returns the previous node to where that key is or should be.
|
455
|
+
*/
|
456
|
+
NODE* find_preceding_from_list(LIST* l, size_t key) {
|
457
|
+
NODE* n = l->first;
|
458
|
+
if (!n || n->key >= key) return NULL;
|
459
|
+
else return find_preceding_from_node(n, key);
|
460
|
+
}
|
461
|
+
|
321
462
|
/*
|
322
463
|
* Finds the node or, if not present, the node that it should follow. NULL
|
323
464
|
* indicates no preceding node.
|
@@ -336,7 +477,7 @@ NODE* find_nearest_from(NODE* prev, size_t key) {
|
|
336
477
|
return prev;
|
337
478
|
}
|
338
479
|
|
339
|
-
f =
|
480
|
+
f = find_preceding_from_node(prev, key);
|
340
481
|
|
341
482
|
if (!f->next) { // key exceeds final node; return final node.
|
342
483
|
return f;
|