libsmatrix 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Makefile +52 -0
- data/README.md +188 -0
- data/examples/.gitignore +2 -0
- data/examples/CFRecommender.java +24 -0
- data/examples/cf_recommender.c +87 -0
- data/examples/smatrix_example.c +75 -0
- data/src/Makefile +28 -0
- data/src/Makefile.in +22 -0
- data/src/java/Makefile +35 -0
- data/src/java/com/paulasmuth/libsmatrix/SparseMatrix.java +146 -0
- data/src/java/pom.xml +68 -0
- data/src/java/test/TestSparseMatrix.java +207 -0
- data/src/ruby/.gitignore +1 -0
- data/src/ruby/Makefile +21 -0
- data/src/ruby/extconf.rb +18 -0
- data/src/ruby/libsmatrix.gemspec +20 -0
- data/src/ruby/libsmatrix.rb +6 -0
- data/src/smatrix.c +960 -0
- data/src/smatrix.h +96 -0
- data/src/smatrix_benchmark.c +236 -0
- data/src/smatrix_jni.c +161 -0
- data/src/smatrix_jni.h +77 -0
- data/src/smatrix_private.h +51 -0
- data/src/smatrix_ruby.c +178 -0
- data/src/smatrix_ruby.h +29 -0
- metadata +90 -0
data/src/smatrix.h
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
// This file is part of the "libsmatrix" project
|
2
|
+
// (c) 2011-2013 Paul Asmuth <paul@paulasmuth.com>
|
3
|
+
//
|
4
|
+
// Licensed under the MIT License (the "License"); you may not use this
|
5
|
+
// file except in compliance with the License. You may obtain a copy of
|
6
|
+
// the License at: http://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
#include <stdint.h>
|
9
|
+
#include <pthread.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
|
12
|
+
#ifndef SMATRIX_H
|
13
|
+
#define SMATRIX_H
|
14
|
+
|
15
|
+
#define SMATRIX_META_SIZE 512
|
16
|
+
#define SMATRIX_RMAP_FLAG_LOADED 4
|
17
|
+
#define SMATRIX_RMAP_FLAG_DIRTY 8
|
18
|
+
#define SMATRIX_RMAP_FLAG_RESIZED 16
|
19
|
+
#define SMATRIX_RMAP_MAGIC "\x23\x23\x23\x23\x23\x23\x23\x23"
|
20
|
+
#define SMATRIX_RMAP_MAGIC_SIZE 8
|
21
|
+
#define SMATRIX_RMAP_INITIAL_SIZE 16
|
22
|
+
#define SMATRIX_RMAP_SLOT_SIZE 8
|
23
|
+
#define SMATRIX_RMAP_HEAD_SIZE 16
|
24
|
+
#define SMATRIX_CMAP_INITIAL_SIZE 65536
|
25
|
+
#define SMATRIX_CMAP_SLOT_SIZE 12
|
26
|
+
#define SMATRIX_CMAP_HEAD_SIZE 16
|
27
|
+
#define SMATRIX_CMAP_BLOCK_SIZE 4194304
|
28
|
+
#define SMATRIX_CMAP_SLOT_USED 1
|
29
|
+
|
30
|
+
typedef struct {
|
31
|
+
volatile uint16_t count;
|
32
|
+
volatile uint16_t mutex;
|
33
|
+
} smatrix_lock_t;
|
34
|
+
|
35
|
+
typedef struct {
|
36
|
+
uint32_t key;
|
37
|
+
uint32_t value;
|
38
|
+
} smatrix_rmap_slot_t;
|
39
|
+
|
40
|
+
typedef struct {
|
41
|
+
uint64_t fpos;
|
42
|
+
uint64_t meta_fpos;
|
43
|
+
uint32_t size;
|
44
|
+
uint32_t used;
|
45
|
+
uint32_t key;
|
46
|
+
uint32_t flags;
|
47
|
+
smatrix_rmap_slot_t* data;
|
48
|
+
smatrix_lock_t lock;
|
49
|
+
} smatrix_rmap_t;
|
50
|
+
|
51
|
+
typedef struct {
|
52
|
+
uint32_t flags;
|
53
|
+
uint32_t key;
|
54
|
+
smatrix_rmap_t* rmap;
|
55
|
+
} smatrix_cmap_slot_t;
|
56
|
+
|
57
|
+
typedef struct {
|
58
|
+
uint64_t size;
|
59
|
+
uint64_t used;
|
60
|
+
uint64_t block_fpos;
|
61
|
+
uint64_t block_used;
|
62
|
+
uint64_t block_size;
|
63
|
+
smatrix_cmap_slot_t* data;
|
64
|
+
smatrix_lock_t lock;
|
65
|
+
} smatrix_cmap_t;
|
66
|
+
|
67
|
+
typedef struct smatrix_ref_s smatrix_ref_t;
|
68
|
+
|
69
|
+
struct smatrix_ref_s {
|
70
|
+
int write;
|
71
|
+
smatrix_rmap_t* rmap;
|
72
|
+
smatrix_rmap_slot_t* slot;
|
73
|
+
smatrix_ref_t* next;
|
74
|
+
};
|
75
|
+
|
76
|
+
typedef struct {
|
77
|
+
int fd;
|
78
|
+
int shutdown;
|
79
|
+
uint64_t fpos;
|
80
|
+
uint64_t mem;
|
81
|
+
smatrix_ref_t* ioqueue;
|
82
|
+
pthread_t iothread;
|
83
|
+
smatrix_cmap_t cmap;
|
84
|
+
smatrix_lock_t lock;
|
85
|
+
} smatrix_t;
|
86
|
+
|
87
|
+
smatrix_t* smatrix_open(const char* fname);
|
88
|
+
uint32_t smatrix_get(smatrix_t* self, uint32_t x, uint32_t y);
|
89
|
+
uint32_t smatrix_set(smatrix_t* self, uint32_t x, uint32_t y, uint32_t value);
|
90
|
+
uint32_t smatrix_incr(smatrix_t* self, uint32_t x, uint32_t y, uint32_t value);
|
91
|
+
uint32_t smatrix_decr(smatrix_t* self, uint32_t x, uint32_t y, uint32_t value);
|
92
|
+
uint32_t smatrix_rowlen(smatrix_t* self, uint32_t x);
|
93
|
+
uint32_t smatrix_getrow(smatrix_t* self, uint32_t x, uint32_t* ret, size_t ret_len);
|
94
|
+
void smatrix_close(smatrix_t* self);
|
95
|
+
|
96
|
+
#endif
|
@@ -0,0 +1,236 @@
|
|
1
|
+
// This file is part of the "libsmatrix" project
|
2
|
+
// (c) 2011-2013 Paul Asmuth <paul@paulasmuth.com>
|
3
|
+
//
|
4
|
+
// Licensed under the MIT License (the "License"); you may not use this
|
5
|
+
// file except in compliance with the License. You may obtain a copy of
|
6
|
+
// the License at: http://opensource.org/licenses/MIT
|
7
|
+
|
8
|
+
#include <stdio.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <string.h>
|
11
|
+
#include <sys/types.h>
|
12
|
+
#include <sys/stat.h>
|
13
|
+
#include <sys/time.h>
|
14
|
+
#include <fcntl.h>
|
15
|
+
#include <unistd.h>
|
16
|
+
#include <assert.h>
|
17
|
+
#include <pthread.h>
|
18
|
+
|
19
|
+
#include "smatrix.h"
|
20
|
+
|
21
|
+
typedef struct {
|
22
|
+
smatrix_t* smx;
|
23
|
+
int threadn;
|
24
|
+
int user1;
|
25
|
+
} args_t;
|
26
|
+
|
27
|
+
smatrix_t* smx_mem;
|
28
|
+
|
29
|
+
void* benchmark_incr_mixed(void* args_) {
|
30
|
+
args_t* args = (args_t*) args_;
|
31
|
+
int i, n, r, o;
|
32
|
+
|
33
|
+
o = 42 + args->threadn;
|
34
|
+
smatrix_t* smx = args->smx;
|
35
|
+
|
36
|
+
for (r = 0; r < args->user1; r++) {
|
37
|
+
for (n = 0; n < 23; n++) {
|
38
|
+
for (i = 0; i < 22; i++) {
|
39
|
+
smatrix_incr(smx, n + o, i + o, 1);
|
40
|
+
smatrix_incr(smx, i + o, n + o, 1);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
return NULL;
|
46
|
+
}
|
47
|
+
|
48
|
+
void* benchmark_get_mixed(void* args_) {
|
49
|
+
args_t* args = (args_t*) args_;
|
50
|
+
int i, n, r, o;
|
51
|
+
|
52
|
+
o = 42 + args->threadn;
|
53
|
+
smatrix_t* smx = args->smx;
|
54
|
+
|
55
|
+
for (r = 0; r < args->user1; r++) {
|
56
|
+
for (n = 0; n < 23; n++) {
|
57
|
+
for (i = 0; i < 22; i++) {
|
58
|
+
smatrix_get(smx, n + o, i + o);
|
59
|
+
smatrix_get(smx, i + o, n + o);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
return NULL;
|
65
|
+
}
|
66
|
+
|
67
|
+
void* benchmark_incr_independent(void* args_) {
|
68
|
+
args_t* args = (args_t*) args_;
|
69
|
+
int i, r, o;
|
70
|
+
|
71
|
+
smatrix_t* smx = args->smx;
|
72
|
+
o = 123 + args->threadn;
|
73
|
+
|
74
|
+
for (r = 0; r < args->user1; r++) {
|
75
|
+
for (i = 0; i < 1000; i++) {
|
76
|
+
smatrix_incr(smx, o, 1, 1);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
return NULL;
|
81
|
+
}
|
82
|
+
|
83
|
+
void* benchmark_incr_compete(void* args_) {
|
84
|
+
args_t* args = (args_t*) args_;
|
85
|
+
int i, r;
|
86
|
+
|
87
|
+
smatrix_t* smx = args->smx;
|
88
|
+
|
89
|
+
for (r = 0; r < args->user1; r++) {
|
90
|
+
for (i = 0; i < 1000; i++) {
|
91
|
+
smatrix_incr(smx, 23, 1, 1);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
return NULL;
|
96
|
+
}
|
97
|
+
|
98
|
+
void measure(void* (*cb)(void*), int nthreads, smatrix_t* smx, int user1) {
|
99
|
+
char str[20] = " ";
|
100
|
+
int n;
|
101
|
+
pthread_t* threads;
|
102
|
+
double elapsed;
|
103
|
+
struct timeval t0, t1;
|
104
|
+
void* retval;
|
105
|
+
|
106
|
+
args_t* args = malloc(sizeof(args_t) * nthreads);
|
107
|
+
threads = malloc(sizeof(pthread_t) * nthreads);
|
108
|
+
|
109
|
+
gettimeofday(&t0, NULL);
|
110
|
+
|
111
|
+
for (n = 0; n < nthreads; n++) {
|
112
|
+
args[n].smx = smx;
|
113
|
+
args[n].threadn = n;
|
114
|
+
args[n].user1 = user1;
|
115
|
+
pthread_create(threads + n, NULL, cb, &args[n]);
|
116
|
+
}
|
117
|
+
|
118
|
+
for (n = 0; n < nthreads; n++) {
|
119
|
+
pthread_join(threads[n], &retval);
|
120
|
+
}
|
121
|
+
|
122
|
+
gettimeofday(&t1, NULL);
|
123
|
+
|
124
|
+
elapsed = (double) (t1.tv_sec - t0.tv_sec) * 1000;
|
125
|
+
elapsed += (double) (t1.tv_usec - t0.tv_usec) / 1000;
|
126
|
+
|
127
|
+
str[snprintf(str, 20, "%.1fms", elapsed)] = ' ';
|
128
|
+
|
129
|
+
free(threads);
|
130
|
+
free(args);
|
131
|
+
printf("%s", str);
|
132
|
+
}
|
133
|
+
|
134
|
+
void print_header(const char* title) {
|
135
|
+
printf("TEST: %s\n", title);
|
136
|
+
printf("---------------------------------------------------------------\n");
|
137
|
+
printf("T=1 T=2 T=4 T=8 T=16 T=32 \n");
|
138
|
+
}
|
139
|
+
|
140
|
+
void test_incr(smatrix_t* smx_mem) {
|
141
|
+
int n, max = 10;
|
142
|
+
|
143
|
+
for (n = 0; n < max; n++) {
|
144
|
+
measure(&benchmark_incr_mixed, 1, smx_mem, 1024);
|
145
|
+
measure(&benchmark_incr_mixed, 2, smx_mem, 512);
|
146
|
+
measure(&benchmark_incr_mixed, 4, smx_mem, 256);
|
147
|
+
measure(&benchmark_incr_mixed, 8, smx_mem, 128);
|
148
|
+
measure(&benchmark_incr_mixed, 16, smx_mem, 64);
|
149
|
+
measure(&benchmark_incr_mixed, 32, smx_mem, 32);
|
150
|
+
|
151
|
+
if (n < max - 1) {
|
152
|
+
printf("\n");
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
printf("\n\n");
|
157
|
+
}
|
158
|
+
|
159
|
+
void test_get(smatrix_t* smx_mem) {
|
160
|
+
int n, max = 10;
|
161
|
+
|
162
|
+
for (n = 0; n < max; n++) {
|
163
|
+
measure(&benchmark_get_mixed, 1, smx_mem, 1024);
|
164
|
+
measure(&benchmark_get_mixed, 2, smx_mem, 512);
|
165
|
+
measure(&benchmark_get_mixed, 4, smx_mem, 256);
|
166
|
+
measure(&benchmark_get_mixed, 8, smx_mem, 128);
|
167
|
+
measure(&benchmark_get_mixed, 16, smx_mem, 64);
|
168
|
+
measure(&benchmark_get_mixed, 32, smx_mem, 32);
|
169
|
+
|
170
|
+
if (n < max - 1) {
|
171
|
+
printf("\n");
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
printf("\n\n");
|
176
|
+
}
|
177
|
+
|
178
|
+
int main(int argc, char** argv) {
|
179
|
+
int num = 1024, threads = 4;
|
180
|
+
smatrix_t* smx = NULL;
|
181
|
+
|
182
|
+
if (argc < 2) {
|
183
|
+
printf("usage: smatrix_benchmark [test] [times] [threads] [file]\n\n");
|
184
|
+
printf(" Available Tests:\n");
|
185
|
+
printf(" full test all methods\n");
|
186
|
+
printf(" incr test the incr method\n");
|
187
|
+
printf(" get test the get method\n\n");
|
188
|
+
printf(" Examples:\n");
|
189
|
+
printf(" $ smatrix_benchmark incr 1024 4\n");
|
190
|
+
printf(" $ smatrix_benchmark incr 1024 4 /tmp/test.smx\n");
|
191
|
+
printf(" $ smatrix_benchmark get 10000 2 /tmp/text.smx\n");
|
192
|
+
printf(" $ smatrix_benchmark full\n\n");
|
193
|
+
return 1;
|
194
|
+
}
|
195
|
+
|
196
|
+
if (argc > 2) {
|
197
|
+
num = atoi(argv[2]);
|
198
|
+
}
|
199
|
+
|
200
|
+
if (argc > 3) {
|
201
|
+
threads = atoi(argv[3]);
|
202
|
+
}
|
203
|
+
|
204
|
+
if (argc > 4) {
|
205
|
+
smx = smatrix_open(argv[4]);
|
206
|
+
} else {
|
207
|
+
smx = smatrix_open(NULL);
|
208
|
+
}
|
209
|
+
|
210
|
+
if (!strcmp(argv[1], "incr")) {
|
211
|
+
printf("testing: %ik x incr @ %i threads: ", num, threads);
|
212
|
+
measure(&benchmark_incr_mixed, threads, smx, num / threads);
|
213
|
+
printf("\n");
|
214
|
+
goto exit;
|
215
|
+
}
|
216
|
+
|
217
|
+
if (!strcmp(argv[1], "get")) {
|
218
|
+
printf("testing: %ik x get @ %i threads: ", num, threads);
|
219
|
+
measure(&benchmark_get_mixed, threads, smx, num / threads);
|
220
|
+
printf("\n");
|
221
|
+
goto exit;
|
222
|
+
}
|
223
|
+
|
224
|
+
printf("libsmatrix benchmark [date]\n\n");
|
225
|
+
|
226
|
+
print_header("1 million x incr (memory)");
|
227
|
+
test_incr(smx);
|
228
|
+
|
229
|
+
print_header("1 million x get (memory)");
|
230
|
+
test_get(smx);
|
231
|
+
|
232
|
+
exit:
|
233
|
+
smatrix_close(smx);
|
234
|
+
|
235
|
+
return 0;
|
236
|
+
}
|
data/src/smatrix_jni.c
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
/**
|
2
|
+
* This file is part of the "libsmatrix" project
|
3
|
+
* (c) 2011-2013 Paul Asmuth <paul@paulasmuth.com>
|
4
|
+
*
|
5
|
+
* Licensed under the MIT License (the "License"); you may not use this
|
6
|
+
* file except in compliance with the License. You may obtain a copy of
|
7
|
+
* the License at: http://opensource.org/licenses/MIT
|
8
|
+
*/
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include "smatrix_jni.h"
|
11
|
+
#include "smatrix.h"
|
12
|
+
|
13
|
+
#define _JM(X) Java_com_paulasmuth_libsmatrix_SparseMatrix_##X
|
14
|
+
#define ERR_PTRNOTFOUND "can't find native object. maybe close() was already called"
|
15
|
+
|
16
|
+
void throw_exception(JNIEnv* env, const char* error) {
|
17
|
+
jclass exception = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
|
18
|
+
(*env)->ThrowNew(env, exception, error);
|
19
|
+
}
|
20
|
+
|
21
|
+
void set_ptr(JNIEnv* env, jobject self, void* ptr_) {
|
22
|
+
jclass cls;
|
23
|
+
jfieldID fid;
|
24
|
+
long ptr = (long) ptr_;
|
25
|
+
|
26
|
+
cls = (*env)->FindClass(env, "com/paulasmuth/libsmatrix/SparseMatrix");
|
27
|
+
fid = (*env)->GetFieldID(env, cls, "ptr", "J");
|
28
|
+
|
29
|
+
(*env)->SetLongField(env, self, fid, ptr);
|
30
|
+
}
|
31
|
+
|
32
|
+
int get_ptr(JNIEnv* env, jobject self, void** ptr) {
|
33
|
+
jclass cls;
|
34
|
+
jfieldID fid;
|
35
|
+
jlong ptr_;
|
36
|
+
|
37
|
+
cls = (*env)->FindClass(env, "com/paulasmuth/libsmatrix/SparseMatrix");
|
38
|
+
fid = (*env)->GetFieldID(env, cls, "ptr", "J");
|
39
|
+
ptr_ = (*env)->GetLongField(env, self, fid);
|
40
|
+
|
41
|
+
if (ptr_ > 0) {
|
42
|
+
*ptr = (void *) ptr_;
|
43
|
+
return 0;
|
44
|
+
} else {
|
45
|
+
throw_exception(env, ERR_PTRNOTFOUND);
|
46
|
+
|
47
|
+
return 1;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
JNIEXPORT void JNICALL _JM(init) (JNIEnv* env, jobject self, jstring file_) {
|
52
|
+
void* ptr;
|
53
|
+
char* file = NULL;
|
54
|
+
|
55
|
+
if (file_ != NULL) {
|
56
|
+
file = (char *) (*env)->GetStringUTFChars(env, file_, 0);
|
57
|
+
}
|
58
|
+
|
59
|
+
ptr = smatrix_open(file);
|
60
|
+
|
61
|
+
if (ptr == NULL) {
|
62
|
+
throw_exception(env, "smatrix_open() failed");
|
63
|
+
} else {
|
64
|
+
set_ptr(env, self, ptr);
|
65
|
+
}
|
66
|
+
|
67
|
+
if (file != NULL) {
|
68
|
+
(*env)->ReleaseStringUTFChars(env, file_, file);
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
JNIEXPORT void JNICALL _JM(close) (JNIEnv* env, jobject self) {
|
73
|
+
void* ptr = NULL;
|
74
|
+
|
75
|
+
if (!get_ptr(env, self, &ptr)) {
|
76
|
+
smatrix_close(ptr);
|
77
|
+
set_ptr(env, self, NULL);
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
JNIEXPORT jint _JM(get) (JNIEnv* env, jobject self, jint x, jint y) {
|
82
|
+
void* ptr = NULL;
|
83
|
+
|
84
|
+
if (get_ptr(env, self, &ptr)) {
|
85
|
+
return 0;
|
86
|
+
} else {
|
87
|
+
return (jint) smatrix_get(ptr, x, y);
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
JNIEXPORT void JNICALL _JM(set) (JNIEnv* env, jobject self, jint x, jint y, jint v) {
|
92
|
+
void* ptr = NULL;
|
93
|
+
|
94
|
+
if (!get_ptr(env, self, &ptr)) {
|
95
|
+
smatrix_set(ptr, (uint32_t) x, (uint32_t) y, (uint32_t) v);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
JNIEXPORT void JNICALL _JM(incr) (JNIEnv* env, jobject self, jint x, jint y, jint v) {
|
100
|
+
void* ptr = NULL;
|
101
|
+
|
102
|
+
if (!get_ptr(env, self, &ptr)) {
|
103
|
+
smatrix_incr(ptr, (uint32_t) x, (uint32_t) y, (uint32_t) v);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
JNIEXPORT void JNICALL _JM(decr) (JNIEnv* env, jobject self, jint x, jint y, jint v) {
|
108
|
+
void* ptr = NULL;
|
109
|
+
|
110
|
+
if (!get_ptr(env, self, &ptr)) {
|
111
|
+
smatrix_decr(ptr, (uint32_t) x, (uint32_t) y, (uint32_t) v);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
JNIEXPORT void JNICALL _JM(getRowNative) (JNIEnv* env, jobject self, jint x, jobject map, jint maxlen) {
|
116
|
+
jclass cls;
|
117
|
+
jint i, len;
|
118
|
+
jmethodID mid;
|
119
|
+
uint32_t *data;
|
120
|
+
void* ptr = NULL;
|
121
|
+
size_t bytes;
|
122
|
+
|
123
|
+
cls = (*env)->GetObjectClass(env, map);
|
124
|
+
mid = (*env)->GetMethodID(env, cls, "putIntTuple", "(II)V");
|
125
|
+
|
126
|
+
if (mid == NULL || get_ptr(env, self, &ptr)) {
|
127
|
+
return;
|
128
|
+
}
|
129
|
+
|
130
|
+
len = smatrix_rowlen(ptr, x);
|
131
|
+
bytes = len * 8;
|
132
|
+
data = malloc(bytes);
|
133
|
+
|
134
|
+
if (data == NULL) {
|
135
|
+
throw_exception(env, "malloc() failed");
|
136
|
+
return;
|
137
|
+
}
|
138
|
+
|
139
|
+
len = smatrix_getrow(ptr, (uint32_t) x, data, bytes);
|
140
|
+
|
141
|
+
for (i = 0; i < len; i++) {
|
142
|
+
if (maxlen > 0 && i >= maxlen) {
|
143
|
+
break;
|
144
|
+
}
|
145
|
+
|
146
|
+
(*env)->CallVoidMethod(env, map, mid, data[i * 2], data[i * 2 + 1]);
|
147
|
+
}
|
148
|
+
|
149
|
+
free(data);
|
150
|
+
}
|
151
|
+
|
152
|
+
JNIEXPORT jint JNICALL _JM(getRowLength) (JNIEnv* env, jobject self, jint x) {
|
153
|
+
void* ptr = NULL;
|
154
|
+
|
155
|
+
if (get_ptr(env, self, &ptr)) {
|
156
|
+
return 0;
|
157
|
+
} else {
|
158
|
+
return (jint) smatrix_rowlen(ptr, x);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|