Bladeren bron

Implements mmap.mmap usage in RPNIterExpr

Preparing serialization
Yann Weber 8 maanden geleden
bovenliggende
commit
059550df46
6 gewijzigde bestanden met toevoegingen van 489 en 185 verwijderingen
  1. 5
    0
      python_const.c
  2. 340
    185
      python_if.c
  3. 41
    0
      python_if.h
  4. 24
    0
      python_pyrpn.c
  5. 5
    0
      python_pyrpn.h
  6. 74
    0
      tests/tests_rpniter.py

+ 5
- 0
python_const.c Bestand weergeven

@@ -40,6 +40,11 @@ on pos_flag",
40 40
 		.name = "const_values",
41 41
 		.doc = "Constant values to use when setting value in space \
42 42
 (expr gives the position, and we set this value",
43
+	},
44
+	{
45
+		.name = "memory_size",
46
+		.doc = "The size of the underlying memory map data are \
47
+readed/written to",
43 48
 	},
44 49
 	{ NULL, NULL },
45 50
 };

+ 340
- 185
python_if.c Bestand weergeven

@@ -8,10 +8,20 @@
8 8
 /**@brief @ref pymod_pyrpn_RPNExprIter methods definition
9 9
  * @ingroup pymod_pyrpn_RPNExprIter */
10 10
 static PyMethodDef RPNIterExpr_methods[] = {
11
+	PYRPN_method("params", rpnif_params,
12
+			METH_VARARGS | METH_KEYWORDS | METH_CLASS,
13
+			/**@todo add default values */
14
+			"cls, pos_flag, res_flag, size_lim, const_values, stack_size",
15
+			"Get a name tuple with parameters given a position \
16
+flag, a result flag and size limits"),
11 17
 	PYRPN_method("get_params", rpnif_get_params,
12 18
 			METH_NOARGS,
13 19
 			"self, /",
14 20
 			"Get a name tuple with parameters"),
21
+	PYRPN_method("set_mmap", rpnif_set_mmap,
22
+			METH_O,
23
+			"self, mmap, /",
24
+			"Set the mmap that stores data"),
15 25
 	PYRPN_method("shape", rpnif_shape,
16 26
 			METH_NOARGS,
17 27
 			"self, /",
@@ -58,6 +68,8 @@ static PyMethodDef RPNIterExpr_methods[] = {
58 68
 static PyMemberDef RPNIterExpr_members[] = {
59 69
 	{"expressions", T_OBJECT, offsetof(PyRPNIterExpr_t, expr), READONLY,
60 70
 		"The tuple of expressions"},
71
+	{"mmap", T_OBJECT, offsetof(PyRPNIterExpr_t, mmap), READONLY,
72
+		"The mmap storing data"},
61 73
 	{NULL}
62 74
 };
63 75
 
@@ -110,6 +122,44 @@ PyTypeObject RPNIterExprType = {
110 122
 	.tp_new = rpnif_new,
111 123
 };
112 124
 
125
+PyObject* rpnif_params(PyObject *cls, PyObject *args, PyObject *kwds)
126
+{
127
+	char *names[] = {"pos_flag", "res_flag", "size_lim", "const_values", "stack_size", NULL};
128
+
129
+	unsigned short pos_flag, res_flag, stack_size;
130
+	PyObject *lim_obj, *const_values_obj;
131
+
132
+	stack_size = 16;
133
+	const_values_obj = lim_obj = NULL;
134
+	
135
+	if(!PyArg_ParseTupleAndKeywords(args, kwds,
136
+			"HHO|OH:RPNIterExppr.get_params", names,
137
+			&pos_flag, &res_flag, &lim_obj, &const_values_obj,
138
+			&stack_size))
139
+	{
140
+		return NULL;
141
+	}
142
+
143
+	rpn_if_param_t *rif_params = _rpnif_get_params(pos_flag, res_flag,
144
+			lim_obj, const_values_obj, stack_size);
145
+	if(!rif_params)
146
+	{
147
+		return NULL;
148
+	}
149
+
150
+	PyObject *res = _rpnif_params_to_tuple(rif_params);
151
+	if(!res)
152
+	{
153
+		goto err;
154
+	}
155
+	free(rif_params);
156
+	return res;
157
+
158
+err:
159
+	free(rif_params);
160
+	return NULL;
161
+}
162
+
113 163
 PyObject* rpnif_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
114 164
 {
115 165
 	PyObject *ret, *err;
@@ -130,175 +180,72 @@ PyObject* rpnif_new(PyTypeObject *subtype, PyObject *args, PyObject* kwds)
130 180
 int rpnif_init(PyObject *self, PyObject *args, PyObject *kwds)
131 181
 {
132 182
 	PyRPNIterExpr_t *expr_self;
133
-	char *names[] = {"pos_flag", "res_flag", "size_lim", "const_values", "stack_size", NULL};
183
+	char *names[] = {"pos_flag", "res_flag", "size_lim", "const_values", "stack_size", "mmap", NULL};
134 184
 	unsigned short pos_flag, res_flag, stack_size;
135
-	PyObject *lim_obj, *const_values_obj;
136
-	int ndim;
185
+	PyObject *lim_obj, *const_values_obj, *mmap_obj;
137 186
 
138
-	char err_str[256];
139 187
 
140 188
 	expr_self = (PyRPNIterExpr_t*)self;
141 189
 
142 190
 	stack_size = 16;
143
-	const_values_obj = lim_obj = NULL;
191
+	const_values_obj = lim_obj = mmap_obj = NULL;
144 192
 	expr_self->rif = NULL;
193
+	expr_self->mmap = NULL;
145 194
 
146
-	if(!PyArg_ParseTupleAndKeywords(args, kwds, "HHO|OH:RPNIterExpr.__init__", names,
147
-		&pos_flag, &res_flag, &lim_obj, &const_values_obj, &stack_size))
195
+	if(!PyArg_ParseTupleAndKeywords(args, kwds, "HHO|OHO:RPNIterExpr.__init__", names,
196
+		&pos_flag, &res_flag, &lim_obj, &const_values_obj, &stack_size,
197
+		&mmap_obj))
148 198
 	{
149 199
 		return -1;
150 200
 	}
151 201
 
152
-	// Args checking
153
-	if(stack_size < 4 || stack_size > 255)
154
-	{
155
-		snprintf(err_str, 128,
156
-			"Stack size should be in [0..255] but %u given",
157
-			stack_size);
158
-		PyErr_SetString(PyExc_ValueError, err_str);
159
-		return -1;
160
-	}
202
+	rpn_if_param_t *rif_params = _rpnif_get_params(pos_flag, res_flag,
203
+			lim_obj, const_values_obj, stack_size);
161 204
 
162
-	// Checks flags & fetch expected sizes for size_lim & const_values
163
-	short expt_sizes[2];
164
-	if(rpn_if_sizes_from_flag(pos_flag, res_flag, expt_sizes) < 0)
205
+	if(!rif_params)
165 206
 	{
166
-		if(expt_sizes[0] < 0)
167
-		{
168
-			PyErr_SetString(PyExc_ValueError,
169
-				"Invalid position flag given");
170
-		}
171
-		else
172
-		{
173
-			PyErr_SetString(PyExc_ValueError,
174
-				"Invalid result flag given");
175
-		}
176 207
 		return -1;
177 208
 	}
178 209
 
179
-	//Check & convert lim
180
-	PyObject *tmp;
181
-	tmp = PySequence_Fast(lim_obj, "Sequence expected for size_lim argument");
182
-	if(PyErr_Occurred())
183
-	{
184
-		return -1;
185
-	}
186
-	Py_ssize_t lim_obj_sz = PySequence_Fast_GET_SIZE(tmp);
187
-	ndim = lim_obj_sz;
188
-	if(PyErr_Occurred())
189
-	{
190
-		Py_DECREF(tmp);
191
-		return -1;
192
-	}
193
-	if(lim_obj_sz < 1)
194
-	{
195
-		Py_DECREF(tmp);
196
-		PyErr_SetString(PyExc_ValueError,
197
-			"Size limits cannot be empty");
198
-		return -1;
199
-	}
210
+	expr_self->ndim = ((rpn_if_default_data_t*)(rif_params->data))->ndim;
200 211
 
201
-	if(pos_flag == RPN_IF_POSITION_XDIM)
212
+	const Py_ssize_t expt_sz = rif_params->mem_sz * rif_params->value_sz;
213
+	if(!mmap_obj)
202 214
 	{
203
-		PyObject *item = PySequence_Fast_GET_ITEM(tmp, 0);
204
-		Py_ssize_t tmp = PyLong_AsSsize_t(item);
205
-		if(PyErr_Occurred())
206
-		{
207
-			PyErr_SetString(PyExc_ValueError,
208
-				"Unable to convert size_lim[0] to int");
209
-			Py_DECREF(tmp);
210
-			return -1;
211
-		}
212
-		if(lim_obj_sz != tmp + 1)
213
-		{
214
-			PyErr_Format(PyExc_ValueError,
215
-				"Xdim indicate %d size_lim but len(size_lim)=%d",
216
-				tmp+1, lim_obj_sz);
217
-			Py_DECREF(tmp);
218
-			return -1;
219
-		}
220
-		expt_sizes[0] = ndim = tmp;
215
+		PyObject *fileno = PyLong_FromLong(-1);
216
+		PyObject *length = PyLong_FromSize_t(expt_sz);
217
+		mmap_obj = PyObject_CallFunctionObjArgs(mmap_cls, fileno, length, NULL);
221 218
 	}
222 219
 	else
223 220
 	{
224
-		if(lim_obj_sz != expt_sizes[0])
225
-		{
226
-			PyErr_Format(PyExc_ValueError,
227
-				"Expected %d size_lim but len(size_lim)=%d",
228
-				expt_sizes[0], lim_obj_sz);
229
-			Py_DECREF(tmp);
230
-			return -1;
231
-		}
232
-	}
233
-
234
-	size_t sz_limits[lim_obj_sz];
235
-	for(Py_ssize_t i = 0; i<lim_obj_sz; i++)
236
-	{
237
-		PyObject *item = PySequence_Fast_GET_ITEM(tmp, i);
238
-		sz_limits[i] = PyLong_AsSize_t(item);
239
-		if(PyErr_Occurred())
240
-		{
241
-			PyErr_Format(PyExc_ValueError,
242
-				"Unable to convert size_lim[%d] to unsigned int",
243
-				i);
244
-			Py_DECREF(tmp);
245
-			return -1;
246
-		}
247
-	}
248
-	Py_DECREF(tmp);
249
-	tmp = NULL;
250
-
251
-	expr_self->ndim = ndim;
252
-
253
-	//Check & convert const values
254
-	Py_ssize_t values_obj_sz = 0;
255
-	if(expt_sizes[1] > 0)
256
-	{
257
-		tmp = const_values_obj;
258
-		if(!PyTuple_Check(tmp))
221
+		if(!PyObject_TypeCheck(mmap_obj, (PyTypeObject*)mmap_cls))
259 222
 		{
260
-			PyErr_SetString(PyExc_ValueError,
261
-				"Invalid type for const_values argument");
223
+			PyErr_Format(PyExc_TypeError,
224
+					"The mmap argument MUST be an instance \
225
+of mmap.mmap");
262 226
 			return -1;
263 227
 		}
264
-		values_obj_sz = PyTuple_Size(tmp);
265
-		if(values_obj_sz != expt_sizes[1])
228
+		/**@todo check if mmap is shared & writable ? */
229
+		if(PyObject_Length(mmap_obj) != (Py_ssize_t) expt_sz)
266 230
 		{
267 231
 			PyErr_Format(PyExc_ValueError,
268
-				"Expected %d const_values but len(const_values)=%d",
269
-				expt_sizes[1], values_obj_sz);
232
+				"Expected mmap length is %ld but mmap with length  %ld provided",
233
+				rif_params->mem_sz, PyObject_Length(mmap_obj));
270 234
 			return -1;
271 235
 		}
272 236
 	}
273 237
 
274
-	rpn_value_t const_values[values_obj_sz];
275
-	for(Py_ssize_t i = 0; i<values_obj_sz; i++)
276
-	{
277
-		PyObject *item = PyTuple_GET_ITEM(tmp, i);
278
-		const_values[i] = PyLong_AsRpnValue_t(item);
279
-		if(PyErr_Occurred())
280
-		{
281
-			PyErr_Format(PyExc_ValueError,
282
-				"Unable to convert size_lim[%d] to unsigned int",
283
-				i);
284
-			return -1;
285
-		}
286
-	}
287
-
288
-
289
-	// Creating rif params
290
-	rpn_if_param_t *rif_params;
291 238
 
292
-	if(!(rif_params = rpn_if_default_params(pos_flag, res_flag,
293
-		sz_limits, const_values, stack_size)))
239
+	if(PyObject_GetBuffer(mmap_obj, &expr_self->mm_buff,
240
+				PyBUF_CONTIG) == -1)
294 241
 	{
295
-		PyErr_SetString(PyExc_ValueError, "Unable to create parameters \
296
-with given arguments");
297 242
 		return -1;
298 243
 	}
299 244
 
245
+	expr_self->mmap = mmap_obj;
246
+
300 247
 	// Creating rif with a new memory map
301
-	expr_self->rif = rpn_if_new(rif_params, NULL);
248
+	expr_self->rif = rpn_if_new(rif_params, expr_self->mm_buff.buf);
302 249
 	if(!expr_self->rif)
303 250
 	{
304 251
 		PyErr_Format(PyExc_RuntimeError,
@@ -326,75 +273,48 @@ with given arguments");
326 273
 PyObject *rpnif_get_params(PyObject *self)
327 274
 {
328 275
 	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
329
-	PyObject *res, *val;
330
-	rpn_if_default_data_t *params;
331
-
332
-	params = (rpn_if_default_data_t*)(expr_self->rif->params->data);
276
+	return _rpnif_params_to_tuple(expr_self->rif->params);
277
+}
333 278
 
334
-	short expt_sizes[2];
335
-	if(rpn_if_sizes_from_flag(params->pos_flag, params->res_flag, expt_sizes) < 0)
279
+PyObject *rpnif_set_mmap(PyObject *self, PyObject *mm_obj)
280
+{
281
+	if(!PyObject_TypeCheck(mm_obj, (PyTypeObject*)mmap_cls))
336 282
 	{
337
-		PyErr_SetString(PyExc_RuntimeError, "Invalid internal state");
283
+		PyErr_Format(PyExc_TypeError,
284
+				"Excpected instance of mmap.mmap");
338 285
 		return NULL;
339 286
 	}
287
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
340 288
 
341
-	res = PyStructSequence_New(&rpnif_params_SeqDesc);
342
-	if(!res)
289
+	Py_buffer buff;
290
+
291
+	/**@todo check mm size &writable ? */
292
+	if(PyObject_GetBuffer(mm_obj, &buff, PyBUF_CONTIG) == -1)
343 293
 	{
344 294
 		return NULL;
345 295
 	}
346
-	val = PyLong_FromLong(expr_self->rif->params->rpn_argc);
347
-	PyStructSequence_SET_ITEM(res, 0, val);
348
-
349
-	val = PyLong_FromLong(params->pos_flag);
350
-	PyStructSequence_SET_ITEM(res, 1, val);
351 296
 
352
-	val = PyLong_FromLong(params->res_flag);
353
-	PyStructSequence_SET_ITEM(res, 2, val);
297
+	// Release old mmap
298
+	PyBuffer_Release(&expr_self->mm_buff);
299
+	Py_DECREF(expr_self->mmap);
354 300
 
355
-	if(params->pos_flag == RPN_IF_POSITION_XDIM)
301
+	if(expr_self->rif->self_mem)
356 302
 	{
357
-		expt_sizes[0] = params->size_lim[0] + 1;
303
+		const size_t mm_sz = expr_self->rif->params->mem_sz *\
304
+				     expr_self->rif->params->value_sz;
305
+		munmap(expr_self->rif->mem, mm_sz);
358 306
 	}
359 307
 
360
-	PyObject *lim  = PyTuple_New(expt_sizes[0]);
361
-	if(!lim)
362
-	{
363
-		Py_DECREF(res);
364
-		return NULL;
365
-	}
366
-	PyStructSequence_SET_ITEM(res, 3, lim);
308
+	// Set new mmap in python struct & rif struct
309
+	expr_self->mm_buff = buff;
310
+	expr_self->mmap = mm_obj;
367 311
 
368
-	for(Py_ssize_t i=0; i<expt_sizes[0]; i++)
369
-	{
370
-		val = PyLong_FromSize_t(params->size_lim[i]);
371
-		PyTuple_SET_ITEM(lim, i, val);
372
-	}
312
+	expr_self->rif->mem = buff.buf;
313
+	expr_self->rif->self_mem = 0;
373 314
 
374
-	if(!params->const_val)
375
-	{
376
-		Py_INCREF(Py_None);
377
-		PyTuple_SET_ITEM(res, 4, Py_None);
378
-	}
379
-	else
380
-	{
381
-		PyObject *values = PyTuple_New(expt_sizes[1]);
382
-		if(!values)
383
-		{
384
-			Py_DECREF(res);
385
-			return NULL;
386
-		}
387
-		PyStructSequence_SET_ITEM(res, 4, values);
388
-		for(Py_ssize_t i=0; i<expt_sizes[1]; i++)
389
-		{
390
-			val = PyLong_FromRpnValue_t(params->const_val[i]);
391
-			PyTuple_SET_ITEM(values, i, val);
392
-		}
393
-	}
394
-	return res;
315
+	Py_RETURN_NONE;
395 316
 }
396 317
 
397
-
398 318
 PyObject *rpnif_shape(PyObject *self)
399 319
 {
400 320
 	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
@@ -705,6 +625,11 @@ void rpnif_del(PyObject *self)
705 625
 		rpn_if_free(expr_self->rif);
706 626
 		expr_self->rif = NULL;
707 627
 	}
628
+	if(expr_self->mm_buff.buf)
629
+	{
630
+		PyBuffer_Release(&expr_self->mm_buff);
631
+	}
632
+	Py_DECREF(expr_self->mmap);
708 633
 }
709 634
 
710 635
 
@@ -912,9 +837,12 @@ int rpnif_getbuffer(PyObject *self, Py_buffer *view, int flags)
912 837
 	PyRPNIterExpr_t *expr_self;
913 838
 	expr_self = (PyRPNIterExpr_t*)self;
914 839
 
840
+	return PyObject_GetBuffer(expr_self->mmap, view, flags);
841
+
915 842
 	rpn_if_default_data_t *data = (rpn_if_default_data_t*)expr_self->rif->params->data;
916 843
 
917 844
 	view->buf = expr_self->rif->mem;
845
+dprintf(2, "buffer addr %p\n", expr_self->mm_buff.buf);
918 846
 	view->obj = self;
919 847
 	view->len = expr_self->rif->params->mem_sz * expr_self->rif->params->value_sz;
920 848
 	view->readonly = 0;
@@ -1186,7 +1114,7 @@ PyObject* rpnif_getstate(PyObject *self, PyObject *noargs)
1186 1114
 	PyErr_SetString(PyExc_NotImplementedError,
1187 1115
 		"getstate Not implemented");
1188 1116
 	return NULL;
1189
-	/**@todo TODO write the function */
1117
+
1190 1118
 	Py_RETURN_NONE;
1191 1119
 }
1192 1120
 
@@ -1199,6 +1127,233 @@ PyObject* rpnif_setstate(PyObject *self, PyObject *state_bytes)
1199 1127
 	Py_RETURN_NONE;
1200 1128
 }
1201 1129
 
1130
+rpn_if_param_t *_rpnif_get_params(unsigned short pos_flag, unsigned short res_flag,
1131
+		PyObject *lim_obj, PyObject *const_values_obj,
1132
+		unsigned short stack_size)
1133
+{
1134
+	char err_str[256];
1135
+	int ndim;
1136
+
1137
+	// Args checking
1138
+	if(stack_size < 4 || stack_size > 255)
1139
+	{
1140
+		snprintf(err_str, 128,
1141
+			"Stack size should be in [0..255] but %u given",
1142
+			stack_size);
1143
+		PyErr_SetString(PyExc_ValueError, err_str);
1144
+		return NULL;
1145
+	}
1146
+
1147
+	// Checks flags & fetch expected sizes for size_lim & const_values
1148
+	short expt_sizes[2];
1149
+	if(rpn_if_sizes_from_flag(pos_flag, res_flag, expt_sizes) < 0)
1150
+	{
1151
+		if(expt_sizes[0] < 0)
1152
+		{
1153
+			PyErr_SetString(PyExc_ValueError,
1154
+				"Invalid position flag given");
1155
+		}
1156
+		else
1157
+		{
1158
+			PyErr_SetString(PyExc_ValueError,
1159
+				"Invalid result flag given");
1160
+		}
1161
+		return NULL;
1162
+	}
1163
+
1164
+	//Check & convert lim
1165
+	PyObject *tmp;
1166
+	tmp = PySequence_Fast(lim_obj, "Sequence expected for size_lim argument");
1167
+	if(PyErr_Occurred())
1168
+	{
1169
+		return NULL;
1170
+	}
1171
+	Py_ssize_t lim_obj_sz = PySequence_Fast_GET_SIZE(tmp);
1172
+	ndim = lim_obj_sz;
1173
+	if(PyErr_Occurred())
1174
+	{
1175
+		Py_DECREF(tmp);
1176
+		return NULL;
1177
+	}
1178
+	if(lim_obj_sz < 1)
1179
+	{
1180
+		Py_DECREF(tmp);
1181
+		PyErr_SetString(PyExc_ValueError,
1182
+			"Size limits cannot be empty");
1183
+		return NULL;
1184
+	}
1185
+
1186
+	if(pos_flag == RPN_IF_POSITION_XDIM)
1187
+	{
1188
+		PyObject *item = PySequence_Fast_GET_ITEM(tmp, 0);
1189
+		Py_ssize_t tmp = PyLong_AsSsize_t(item);
1190
+		if(PyErr_Occurred())
1191
+		{
1192
+			PyErr_SetString(PyExc_ValueError,
1193
+				"Unable to convert size_lim[0] to int");
1194
+			Py_DECREF(tmp);
1195
+			return NULL;
1196
+		}
1197
+		if(lim_obj_sz != tmp + 1)
1198
+		{
1199
+			PyErr_Format(PyExc_ValueError,
1200
+				"Xdim indicate %d size_lim but len(size_lim)=%d",
1201
+				tmp+1, lim_obj_sz);
1202
+			Py_DECREF(tmp);
1203
+			return NULL;
1204
+		}
1205
+		expt_sizes[0] = ndim = tmp;
1206
+	}
1207
+	else
1208
+	{
1209
+		if(lim_obj_sz != expt_sizes[0])
1210
+		{
1211
+			PyErr_Format(PyExc_ValueError,
1212
+				"Expected %d size_lim but len(size_lim)=%d",
1213
+				expt_sizes[0], lim_obj_sz);
1214
+			Py_DECREF(tmp);
1215
+			return NULL;
1216
+		}
1217
+	}
1218
+
1219
+	size_t sz_limits[lim_obj_sz];
1220
+	for(Py_ssize_t i = 0; i<lim_obj_sz; i++)
1221
+	{
1222
+		PyObject *item = PySequence_Fast_GET_ITEM(tmp, i);
1223
+		sz_limits[i] = PyLong_AsSize_t(item);
1224
+		if(PyErr_Occurred())
1225
+		{
1226
+			PyErr_Format(PyExc_ValueError,
1227
+				"Unable to convert size_lim[%d] to unsigned int",
1228
+				i);
1229
+			Py_DECREF(tmp);
1230
+			return NULL;
1231
+		}
1232
+	}
1233
+	Py_DECREF(tmp);
1234
+	tmp = NULL;
1235
+
1236
+	//Check & convert const values
1237
+	Py_ssize_t values_obj_sz = 0;
1238
+	if(expt_sizes[1] > 0)
1239
+	{
1240
+		tmp = const_values_obj;
1241
+		if(!PyTuple_Check(tmp))
1242
+		{
1243
+			PyErr_SetString(PyExc_ValueError,
1244
+				"Invalid type for const_values argument");
1245
+			return NULL;
1246
+		}
1247
+		values_obj_sz = PyTuple_Size(tmp);
1248
+		if(values_obj_sz != expt_sizes[1])
1249
+		{
1250
+			PyErr_Format(PyExc_ValueError,
1251
+				"Expected %d const_values but len(const_values)=%d",
1252
+				expt_sizes[1], values_obj_sz);
1253
+			return NULL;
1254
+		}
1255
+	}
1256
+
1257
+	rpn_value_t const_values[values_obj_sz];
1258
+	for(Py_ssize_t i = 0; i<values_obj_sz; i++)
1259
+	{
1260
+		PyObject *item = PyTuple_GET_ITEM(tmp, i);
1261
+		const_values[i] = PyLong_AsRpnValue_t(item);
1262
+		if(PyErr_Occurred())
1263
+		{
1264
+			PyErr_Format(PyExc_ValueError,
1265
+				"Unable to convert size_lim[%d] to unsigned int",
1266
+				i);
1267
+			return NULL;
1268
+		}
1269
+	}
1270
+
1271
+
1272
+	// Creating rif params
1273
+	rpn_if_param_t *rif_params;
1274
+
1275
+	if(!(rif_params = rpn_if_default_params(pos_flag, res_flag,
1276
+		sz_limits, const_values, stack_size)))
1277
+	{
1278
+		PyErr_SetString(PyExc_ValueError, "Unable to create parameters \
1279
+with given arguments");
1280
+		return NULL;
1281
+	}
1282
+
1283
+	return rif_params;
1284
+}
1285
+
1286
+PyObject *_rpnif_params_to_tuple(const rpn_if_param_t *_params)
1287
+{
1288
+	PyObject *res, *val;
1289
+	short expt_sizes[2];
1290
+	rpn_if_default_data_t *params;
1291
+	params = (rpn_if_default_data_t*)(_params->data);
1292
+
1293
+	if(rpn_if_sizes_from_flag(params->pos_flag, params->res_flag, expt_sizes) < 0)
1294
+	{
1295
+		PyErr_SetString(PyExc_RuntimeError, "Invalid internal state");
1296
+		return NULL;
1297
+	}
1298
+
1299
+	res = PyStructSequence_New(&rpnif_params_SeqDesc);
1300
+	if(!res)
1301
+	{
1302
+		return NULL;
1303
+	}
1304
+	val = PyLong_FromLong(_params->rpn_argc);
1305
+	PyStructSequence_SET_ITEM(res, 0, val);
1306
+
1307
+	val = PyLong_FromLong(params->pos_flag);
1308
+	PyStructSequence_SET_ITEM(res, 1, val);
1309
+
1310
+	val = PyLong_FromLong(params->res_flag);
1311
+	PyStructSequence_SET_ITEM(res, 2, val);
1312
+
1313
+	if(params->pos_flag == RPN_IF_POSITION_XDIM)
1314
+	{
1315
+		expt_sizes[0] = params->size_lim[0] + 1;
1316
+	}
1317
+
1318
+	PyObject *lim  = PyTuple_New(expt_sizes[0]);
1319
+	if(!lim)
1320
+	{
1321
+		Py_DECREF(res);
1322
+		return NULL;
1323
+	}
1324
+	PyStructSequence_SET_ITEM(res, 3, lim);
1325
+
1326
+	for(Py_ssize_t i=0; i<expt_sizes[0]; i++)
1327
+	{
1328
+		val = PyLong_FromSize_t(params->size_lim[i]);
1329
+		PyTuple_SET_ITEM(lim, i, val);
1330
+	}
1331
+
1332
+	if(!params->const_val)
1333
+	{
1334
+		Py_INCREF(Py_None);
1335
+		PyTuple_SET_ITEM(res, 4, Py_None);
1336
+	}
1337
+	else
1338
+	{
1339
+		PyObject *values = PyTuple_New(expt_sizes[1]);
1340
+		if(!values)
1341
+		{
1342
+			Py_DECREF(res);
1343
+			return NULL;
1344
+		}
1345
+		PyStructSequence_SET_ITEM(res, 4, values);
1346
+		for(Py_ssize_t i=0; i<expt_sizes[1]; i++)
1347
+		{
1348
+			val = PyLong_FromRpnValue_t(params->const_val[i]);
1349
+			PyTuple_SET_ITEM(values, i, val);
1350
+		}
1351
+	}
1352
+	val = PyLong_FromUnsignedLong(_params->mem_sz * _params->value_sz);
1353
+	PyStructSequence_SET_ITEM(res, 5, val);
1354
+	return res;
1355
+}
1356
+
1202 1357
 /**@def _ret_append(key) 
1203 1358
  * @hiderefs
1204 1359
  * local macro */

+ 41
- 0
python_if.h Bestand weergeven

@@ -55,6 +55,11 @@
55 55
  * @ingroup pymod_pyrpn_RPNExprIter */
56 56
 extern PyTypeObject RPNIterExprType;
57 57
 
58
+/**@brief Points on Python's std mmap module */
59
+extern PyObject *mmap_module;
60
+/**@brief Python's mmap.mmap class */
61
+extern PyObject *mmap_cls;
62
+
58 63
 /**@brief Structure holding RPNIterExpr objects
59 64
  * @ingroup pymod_pyrpn_RPNExprIter */
60 65
 typedef struct
@@ -71,8 +76,21 @@ typedef struct
71 76
 	/**@brief Python tuple with instances of RPNExpr */
72 77
 	PyObject *expr;
73 78
 
79
+	/**@brief Python mmap.mmap instance representing rif memory map */
80
+	PyObject *mmap;
81
+
82
+	/**@brief Memory map buffer allowing acces to underlying pointer */
83
+	Py_buffer mm_buff;
84
+
74 85
 } PyRPNIterExpr_t;
75 86
 
87
+/**@brief RPNIterExpr.params static method
88
+ * @param args Position arguments
89
+ * @param kwds Keyword arguments
90
+ * @return A new rpnif_params_SeqDesc instance
91
+ */
92
+PyObject* rpnif_params(PyObject *cls, PyObject *args, PyObject *kwds);
93
+
76 94
 /**@brief RpnIterExpr __new__ method
77 95
  * @param subtype Type of object being created (pyrpn.RPNIterExpr)
78 96
  * @param args positional arguments for subtype
@@ -124,6 +142,13 @@ void rpnif_releasebuffer(PyObject *self, Py_buffer *view);
124 142
  */
125 143
 PyObject *rpnif_get_params(PyObject *self);
126 144
 
145
+/**@brief Set the mmap object used for data storage
146
+ * @param self RPNIterExpr instance
147
+ * @return None
148
+ * @ingroup pymod_pyrpn_RPNExprIter
149
+ */
150
+PyObject *rpnif_set_mmap(PyObject *self, PyObject *mm_obj);
151
+
127 152
 /**@brief Return a tuple with data buffer's shape
128 153
  * @param self RPNIterExpr instance
129 154
  * @return A new ref on a tuple
@@ -250,6 +275,22 @@ PyObject *rpnif_values(PyObject *self);
250 275
  * @ingroup pymod_pyrpn_RPNExprIter */
251 276
 PyObject *rpnif_items(PyObject *self);
252 277
 
278
+/**@brief Returns rpn_if_params given arguments
279
+ * @param pos_flag a position flag
280
+ * @param res_flag a result flag
281
+ * @param size_lim a tuple with size limits
282
+ * @param const_values a tuple wiith constant values
283
+ * @param stack_size a stack size
284
+ */
285
+rpn_if_param_t *_rpnif_get_params(unsigned short pos_flag, unsigned short res_flag,
286
+		PyObject *size_lim, PyObject *const_values,
287
+		unsigned short stack_size);
288
+
289
+/**@brief Converts rpn_if_params to named tuple
290
+ * @param params The rpnif params
291
+ * @return A named tuple
292
+ */
293
+PyObject *_rpnif_params_to_tuple(const rpn_if_param_t *params);
253 294
 
254 295
 #endif
255 296
 

+ 24
- 0
python_pyrpn.c Bestand weergeven

@@ -51,9 +51,33 @@ PyModuleDef rpnmodule = {
51 51
 	NULL	// m_free
52 52
 };
53 53
 
54
+PyObject *mmap_module = NULL;
55
+PyObject *mmap_cls = NULL;
56
+
54 57
 PyMODINIT_FUNC
55 58
 PyInit_pyrpn(void)
56 59
 {
60
+	if(mmap_module == NULL)
61
+	{
62
+		mmap_module = PyImport_ImportModule("mmap");
63
+		if(PyErr_Occurred()) { return NULL; }
64
+		else if(!mmap_module)
65
+		{
66
+			PyErr_Format(PyExc_ImportError, "Unable to import mmap module");
67
+			return NULL;
68
+		}
69
+	}
70
+	if(mmap_cls == NULL)
71
+	{
72
+		mmap_cls = PyObject_GetAttrString(mmap_module, "mmap");
73
+		if(PyErr_Occurred()) { return NULL; }
74
+		else if (!mmap_cls)
75
+		{
76
+			PyErr_Format(PyExc_ImportError, "Unable to import mmap.mmap");
77
+			return NULL;
78
+		}
79
+	}
80
+	
57 81
 
58 82
 	PyObject *mod, *const_mod, *tokens_mod;
59 83
 	// init module & globals

+ 5
- 0
python_pyrpn.h Bestand weergeven

@@ -77,6 +77,11 @@ PyMODINIT_FUNC PyInit_pyrpn(void);
77 77
  * @ingroup pymod_pyrpn */
78 78
 extern PyModuleDef rpnmodule;
79 79
 
80
+/**@brief Points on Python's std mmap module */
81
+extern PyObject *mmap_module;
82
+/**@brief Python's mmap.mmap class */
83
+extern PyObject *mmap_cls;
84
+
80 85
 /**@brief Return a dict with valid operations (short keys and long values)
81 86
  * @param mod pyrpn module object
82 87
  * @param noargs Dummy argument for METH_NOARG

+ 74
- 0
tests/tests_rpniter.py Bestand weergeven

@@ -18,6 +18,7 @@
18 18
 #
19 19
 
20 20
 import copy
21
+import mmap
21 22
 import pickle
22 23
 import random
23 24
 import sys
@@ -87,6 +88,7 @@ class TestRPNIterInit(unittest.TestCase):
87 88
                 self.assertEqual(params.size_lim, arg[2])
88 89
                 self.assertIsNone(params.const_values)
89 90
     
91
+
90 92
     def test_params_const(self):
91 93
         """ Test parameters from instanciation when const values used as result """
92 94
         args = [(pyrpn.const.POS_XY,
@@ -171,6 +173,78 @@ class TestRPNIterInit(unittest.TestCase):
171 173
                     self.assertEqual(len(arr), expt_sz)
172 174
                     arr += 0x11111111 # check writing to all bytes
173 175
 
176
+    @skipIfNoNumpy()
177
+    def test_mmap_accessor(self):
178
+        """ Testing mmap access """
179
+        args = (pyrpn.const.POS_XY,
180
+                  pyrpn.const.RESULT_COUNT,
181
+                  (640,480))
182
+        rif = pyrpn.RPNIterExpr(*args)
183
+        arr = np.frombuffer(rif, dtype=np.uint64)
184
+        arr[42] = 1312
185
+        arr2 = np.frombuffer(rif.mmap, dtype=np.uint64)
186
+        self.assertTrue((arr == arr2).all())
187
+
188
+        rif.mmap.write(b'hello world !')
189
+        arr = np.frombuffer(rif, dtype=np.uint64)
190
+        arr2 = np.frombuffer(rif.mmap, dtype=np.uint64)
191
+        self.assertTrue((arr == arr2).all())
192
+
193
+    @skipIfNoNumpy()
194
+    def test_mmap_argument(self):
195
+        """ Testing mmap argument """
196
+        args = (pyrpn.const.POS_XY,
197
+                  pyrpn.const.RESULT_COUNT,
198
+                  (640,480))
199
+        params = pyrpn.RPNIterExpr.params(*args)
200
+        mm = mmap.mmap(-1, params.memory_size)
201
+        mm.write(b'Hello world !')
202
+        rif = pyrpn.RPNIterExpr(*args, mmap=mm)
203
+        self.assertEqual(mm, rif.mmap)
204
+        arr = np.frombuffer(rif, dtype=np.uint64)
205
+        arr2 = np.frombuffer(mm, dtype=np.uint64)
206
+        self.assertTrue((arr == arr2).all())
207
+
208
+    @skipIfNoNumpy()
209
+    def test_mmap_update(self):
210
+        """ Testing mmap update """
211
+        args = (pyrpn.const.POS_XY, pyrpn.const.RESULT_RGB,
212
+                (640,480))
213
+        params = pyrpn.RPNIterExpr.params(*args)
214
+        mm1 = mmap.mmap(-1, params.memory_size)
215
+        arr = np.frombuffer(mm1, dtype=np.uint64)
216
+        for _ in range(1024):
217
+            idx = random.randint(0, params.memory_size // 8)
218
+            val = random.randint(0, 0xFFFFFFFF)
219
+            arr[idx] = val
220
+
221
+        rif = pyrpn.RPNIterExpr(*args)
222
+        pos = 0
223
+        while pos == 0:
224
+            for exp in rif.expressions:
225
+                exp.mutate(n_mutations=15)
226
+            pos = rif.step(pos)
227
+
228
+        for _ in range(4096):
229
+            pos = rif.step(pos)
230
+
231
+        arr2 = arrorig = np.frombuffer(rif, dtype=np.uint64)
232
+        self.assertFalse((arr == arr2).all())
233
+
234
+        rif.set_mmap(mm1)
235
+        arr2 = np.frombuffer(rif, dtype=np.uint64)
236
+        self.assertTrue((arr == arr2).all())
237
+        del(arr)
238
+        del(arr2)
239
+
240
+        mm1.write(b'Hello world !')
241
+        arr2 = np.frombuffer(rif, dtype=np.uint64)
242
+        arr = np.frombuffer(mm1, dtype=np.uint64)
243
+        self.assertTrue((arr == arr2).all())
244
+
245
+        arr = np.frombuffer(mm1, dtype=np.uint64)
246
+        self.assertFalse((arr == arrorig).all())
247
+
174 248
     def test_str(self):
175 249
         """ Test string representation of rif """
176 250
 

Loading…
Annuleren
Opslaan