Browse Source

Implement RPNIterExpr.shape() method + test + todo done

Yann Weber 1 year ago
parent
commit
3eed2b7f3e
11 changed files with 186 additions and 33 deletions
  1. 1
    1
      Makefile
  2. 2
    4
      python_const.c
  3. 1
    1
      python_const.h
  4. 80
    5
      python_if.c
  5. 7
    0
      python_if.h
  6. 1
    1
      python_pyrpn.c
  7. 3
    4
      python_rpnexpr.c
  8. 1
    1
      python_rpntoken.c
  9. 10
    10
      rpn_if_default.c
  10. 3
    6
      rpn_if_default.h
  11. 77
    0
      tests/tests_rpniter.py

+ 1
- 1
Makefile View File

@@ -3,7 +3,7 @@ NASM=nasm
3 3
 LD=ld
4 4
 
5 5
 ifeq ($(DEBUG), 1)
6
-	CFLAGS=-ggdb -fPIC -Wall -DDEBUG
6
+	CFLAGS=-ggdb -fPIC -Wall -DDEBUG -Wsign-compare
7 7
 	LDFLAGS=-g
8 8
 	NASMCFLAGS=-g -f elf64
9 9
 	#PYTHON=python3dm

+ 2
- 4
python_const.c View File

@@ -7,7 +7,6 @@
7 7
  * @ingroup pymod_pyrpn_RPNMutationParams
8 8
  */
9 9
 
10
-/** @todo implement GC with m_clear */
11 10
 PyModuleDef rpnconstmodule = {
12 11
 	PyModuleDef_HEAD_INIT,
13 12
 	"pyrpn.const",
@@ -138,10 +137,9 @@ int Py_rpnconst_add(PyObject* mod, const char* name, int value)
138 137
 	return 0;
139 138
 }
140 139
 
141
-/**@todo rename this function ! (bad prefix)
142
- * @brief Module initialisation function
140
+/**@brief Module initialisation function
143 141
  * @return The initialized module */
144
-PyObject *Py_rpnconst_init(void)
142
+PyObject *rpnconst_init(void)
145 143
 {
146 144
 	PyObject *mod;
147 145
 	mod = PyModule_Create(&rpnconstmodule);

+ 1
- 1
python_const.h View File

@@ -80,6 +80,6 @@ extern rpn_mutation_params_t rpn_mutation_params_default;
80 80
 /**@brief pyrpn.const module initialisation function
81 81
  * @return The initialized module
82 82
  * @ingroup pymod_pyrpn */
83
-PyObject *Py_rpnconst_init(void);
83
+PyObject *rpnconst_init(void);
84 84
 
85 85
 #endif

+ 80
- 5
python_if.c View File

@@ -12,6 +12,10 @@ static PyMethodDef RPNIterExpr_methods[] = {
12 12
 			METH_NOARGS,
13 13
 			"self, /",
14 14
 			"Get a name tuple with parameters"),
15
+	PYRPN_method("shape", rpnif_shape,
16
+			METH_NOARGS,
17
+			"self, /",
18
+			"Get the shape of the data buffer"),
15 19
 	PYRPN_method("keys", rpnif_keys,
16 20
 			METH_NOARGS,
17 21
 			"self, /",
@@ -390,6 +394,64 @@ PyObject *rpnif_get_params(PyObject *self)
390 394
 	return res;
391 395
 }
392 396
 
397
+
398
+PyObject *rpnif_shape(PyObject *self)
399
+{
400
+	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
401
+	rpn_if_default_data_t *params;
402
+	params = (rpn_if_default_data_t*)(expr_self->rif->params->data);
403
+
404
+	size_t res_sz;
405
+
406
+	switch(params->res_flag)
407
+	{
408
+		case RPN_IF_RES_RGB:
409
+			res_sz = 3;
410
+			break;
411
+		case RPN_IF_RES_RGBA:
412
+			res_sz = 4;
413
+			break;
414
+		default:
415
+			res_sz = 1;
416
+			break;
417
+	}
418
+
419
+	const size_t shape_sz = params->ndim + (res_sz > 1 ?1:0);
420
+
421
+	PyObject *ret = PyTuple_New(shape_sz);
422
+	if(!ret)
423
+	{
424
+		return NULL;
425
+	}
426
+
427
+	size_t i;
428
+	for(i = 0; i < params->ndim; i++)
429
+	{
430
+		size_t idx = params->pos_flag == RPN_IF_POSITION_XDIM ? i+1:i;
431
+		PyObject *d = PyLong_FromLong(params->size_lim[idx]);
432
+		if(!d)
433
+		{
434
+			goto item_err;
435
+		}
436
+		PyTuple_SET_ITEM(ret, i, d);
437
+	}
438
+	if(res_sz > 1)
439
+	{
440
+		PyObject *d = PyLong_FromLong(res_sz);
441
+		if(!d)
442
+		{
443
+			goto item_err;
444
+		}
445
+		PyTuple_SET_ITEM(ret, i, d);
446
+	}
447
+	return ret;
448
+
449
+item_err:
450
+	Py_DECREF(ret);
451
+	return NULL;
452
+}
453
+
454
+
393 455
 PyObject *rpnif_step(PyObject *self, PyObject* opos)
394 456
 {
395 457
 	PyRPNIterExpr_t *expr_self = (PyRPNIterExpr_t*)self;
@@ -418,7 +480,7 @@ PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
418 480
 	const short idx_off = rif_data->pos_flag == RPN_IF_POSITION_XDIM?1:0;
419 481
 	long long value;
420 482
 	
421
-	if(argc != rif_data->ndim)
483
+	if((size_t)argc != rif_data->ndim)
422 484
 	{
423 485
 		PyErr_Format(PyExc_IndexError,
424 486
 				"Expression expect %lu dimentions coordinates,"
@@ -430,7 +492,7 @@ PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
430 492
 	rpn_value_t result=0;
431 493
 	size_t cur_dim_sz = 1;
432 494
 
433
-	for(Py_ssize_t i=0; i<rif_data->ndim; i++)
495
+	for(size_t i=0; i<rif_data->ndim; i++)
434 496
 	{
435 497
 		if(!PyLong_Check(argv[i]))
436 498
 		{
@@ -439,8 +501,11 @@ PyObject *rpnif_to_pos(PyObject *self, PyObject** argv, Py_ssize_t argc)
439 501
 			return NULL;
440 502
 		}
441 503
 		value = PyLong_AsLongLong(argv[i]);
442
-		value = value >= 0?value:(-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
443
-		if(value >= rif_data->size_lim[i+idx_off])
504
+		if(value < 0)
505
+		{
506
+			value = (-(rpn_value_t)-value)%rif_data->size_lim[i+idx_off];
507
+		}
508
+		if((size_t)value >= rif_data->size_lim[i+idx_off])
444 509
 		{
445 510
 			PyErr_Format(PyExc_IndexError,
446 511
 					"Coordinate %ld overflows : %R/%lu",
@@ -875,7 +940,11 @@ int rpnif_getbuffer(PyObject *self, Py_buffer *view, int flags)
875 940
 		{
876 941
 			view->ndim++;
877 942
 		}
878
-		view->shape = malloc(sizeof(Py_ssize_t) * view->ndim); /**@todo check error*/
943
+		view->shape = malloc(sizeof(Py_ssize_t) * view->ndim);
944
+		if(!view->shape)
945
+		{
946
+			goto buff_error;
947
+		}
879 948
 		for(size_t i=0; i<expr_self->ndim; i++)
880 949
 		{
881 950
 			int idx = i;
@@ -895,6 +964,12 @@ int rpnif_getbuffer(PyObject *self, Py_buffer *view, int flags)
895 964
 
896 965
 	Py_INCREF(self);
897 966
 	return 0;
967
+
968
+buff_error:
969
+	PyErr_Format(PyExc_BufferError,
970
+			"Unable to provide buffer : %s", strerror(errno));
971
+	view->obj = NULL;
972
+	return -1;
898 973
 }
899 974
 
900 975
 void rpnif_releasebuffer(PyObject *self, Py_buffer *view)

+ 7
- 0
python_if.h View File

@@ -124,6 +124,13 @@ void rpnif_releasebuffer(PyObject *self, Py_buffer *view);
124 124
  */
125 125
 PyObject *rpnif_get_params(PyObject *self);
126 126
 
127
+/**@brief Return a tuple with data buffer's shape
128
+ * @param self RPNIterExpr instance
129
+ * @return A new ref on a tuple
130
+ * @ingroup pymod_pyrpn_RPNExprIter
131
+ */
132
+PyObject *rpnif_shape(PyObject *self);
133
+
127 134
 /**@brief Runs an IF on given position
128 135
  * @param self RPNInterExpr instance
129 136
  * @param pos The start position

+ 1
- 1
python_pyrpn.c View File

@@ -61,7 +61,7 @@ PyInit_pyrpn(void)
61 61
 	if(mod == NULL) { return NULL; }
62 62
 	
63 63
 	//init constants module
64
-	const_mod = Py_rpnconst_init();
64
+	const_mod = rpnconst_init();
65 65
 	if(const_mod == NULL)
66 66
 	{
67 67
 		goto fail_init;

+ 3
- 4
python_rpnexpr.c View File

@@ -332,7 +332,6 @@ PyObject* rpnexpr_getstate(PyObject *self, PyObject *noargs)
332 332
 	}
333 333
 	if(resbuf.token_sz)
334 334
 	{
335
-		/**@todo can lead to stack overflow on huge expressions ? */
336 335
 		rpn_token_t tokens[resbuf.token_sz];
337 336
 		bzero(tokens, sizeof(rpn_token_t) * resbuf.token_sz);
338 337
 
@@ -576,7 +575,7 @@ PyObject* rpnexpr_token_item(PyObject *self, Py_ssize_t idx)
576 575
 	{
577 576
 		idx = expr_self->rpn->toks.tokens_sz - 1 + idx;
578 577
 	}
579
-	if(idx < 0 || idx >= expr_self->rpn->toks.tokens_sz)
578
+	if(idx < 0 || (size_t)idx >= expr_self->rpn->toks.tokens_sz)
580 579
 	{
581 580
 		PyErr_Format(PyExc_IndexError,
582 581
 			"No token %ld in expression of size %ld",
@@ -596,7 +595,7 @@ int rpnexpr_token_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
596 595
 	{
597 596
 		idx = expr_self->rpn->toks.tokens_sz - 1 + idx;
598 597
 	}
599
-	if(idx < 0 || idx > expr_self->rpn->toks.tokens_sz)
598
+	if(idx < 0 || (size_t)idx > expr_self->rpn->toks.tokens_sz)
600 599
 	{
601 600
 		PyErr_Format(PyExc_IndexError,
602 601
 			"Cannot set token %ld in expression of size %ld",
@@ -612,7 +611,7 @@ int rpnexpr_token_ass_item(PyObject *self, Py_ssize_t idx, PyObject* elt)
612 611
 	}
613 612
 
614 613
 	short new_elt = 0;
615
-	if(idx == expr_self->rpn->toks.tokens_sz)
614
+	if((size_t)idx == expr_self->rpn->toks.tokens_sz)
616 615
 	{
617 616
 		new_elt = 1;
618 617
 		expr_self->rpn->toks.tokens_sz++;

+ 1
- 1
python_rpntoken.c View File

@@ -368,7 +368,7 @@ int rpntokenop_init(PyObject *_self, PyObject *args, PyObject *kwds)
368 368
 			PyErr_SetString(PyExc_ValueError, "Opcode cannot be negative");
369 369
 			return -1;
370 370
 		}
371
-		else if (opcode >= rpn_op_sz())
371
+		else if ((size_t)opcode >= rpn_op_sz())
372 372
 		{
373 373
 			PyErr_Format(PyExc_ValueError,
374 374
 					"Maximum opcode is %ld but %ld given",

+ 10
- 10
rpn_if_default.c View File

@@ -255,22 +255,21 @@ int rpn_if_setres_default(rpn_if_t *rif, size_t *pos)
255 255
 	rpn_if_default_data_t *data;
256 256
 	size_t cur_arg, i, rgb_imax;
257 257
 	rpn_value_t *values;
258
-	rpn_value_t *res = rif->rpn_res;
259 258
 
260 259
 	data = (rpn_if_default_data_t*)rif->params->data;
261 260
 
262 261
 	switch(data->pos_flag)
263 262
 	{
264 263
 		case RPN_IF_POSITION_LINEAR:
265
-			rpn_if_resf_linear(rif, pos, res);
264
+			rpn_if_resf_linear(rif, pos);
266 265
 			cur_arg = 1;
267 266
 			break;
268 267
 		case RPN_IF_POSITION_XY:
269
-			rpn_if_resf_xy(rif, pos, res);
268
+			rpn_if_resf_xy(rif, pos);
270 269
 			cur_arg = 2;
271 270
 			break;
272 271
 		case RPN_IF_POSITION_XDIM:
273
-			rpn_if_resf_xdim(rif, pos, res);
272
+			rpn_if_resf_xdim(rif, pos);
274 273
 			cur_arg = *(data->size_lim);
275 274
 			break;
276 275
 		default:
@@ -283,19 +282,21 @@ int rpn_if_setres_default(rpn_if_t *rif, size_t *pos)
283 282
 	}
284 283
 	rgb_imax = 3; /* rgb */
285 284
 	values = rpn_if_getitem(rif, *pos);
286
-	/**@todo if(res) set the values in res too ! */
287 285
 	switch(data->res_flag)
288 286
 	{
289 287
 		case RPN_IF_RES_BOOL:
290 288
 			*values = 1;
289
+			*rif->rpn_res = *values;
291 290
 			break;
292 291
 
293 292
 		case RPN_IF_RES_CONST:
294 293
 			*values = *(data->const_val);
294
+			*rif->rpn_res = *values;
295 295
 			break;
296 296
 
297 297
 		case RPN_IF_RES_COUNT:
298 298
 			(*values)++;
299
+			*rif->rpn_res = *values;
299 300
 			break;
300 301
 
301 302
 		case RPN_IF_RES_CONST_RGBA:
@@ -304,6 +305,7 @@ int rpn_if_setres_default(rpn_if_t *rif, size_t *pos)
304 305
 			for(i=0;i<rgb_imax;i++)
305 306
 			{
306 307
 				values[i] = data->const_val[i];
308
+				rif->rpn_res[i] = values[i];
307 309
 			}
308 310
 			break;
309 311
 
@@ -346,7 +348,7 @@ int rpn_if_argf_linear(rpn_if_t *rif, size_t pos, rpn_value_t *args)
346 348
 	return 0;
347 349
 }
348 350
 
349
-int rpn_if_resf_linear(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
351
+int rpn_if_resf_linear(rpn_if_t *rif, size_t *pos)
350 352
 {
351 353
 	rpn_if_default_data_t *data;
352 354
 	size_t res;
@@ -386,7 +388,7 @@ int rpn_if_argf_xy(rpn_if_t *rif, size_t pos, rpn_value_t *args)
386 388
 	return 0;
387 389
 }
388 390
 
389
-int rpn_if_resf_xy(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
391
+int rpn_if_resf_xy(rpn_if_t *rif, size_t *pos)
390 392
 {
391 393
 	rpn_if_default_data_t *data;
392 394
 	size_t xy[2];
@@ -429,7 +431,6 @@ int rpn_if_argf_xdim(rpn_if_t *rif, size_t pos, rpn_value_t *args)
429 431
 	{
430 432
 		return -1;
431 433
 	}
432
-	/**@todo check if *(data->size_lim) overflow rif->params->rpn_argc */
433 434
 
434 435
 	curdim_sz = 1;
435 436
 	curpos = pos;
@@ -451,7 +452,7 @@ int rpn_if_argf_xdim(rpn_if_t *rif, size_t pos, rpn_value_t *args)
451 452
 	return 0;
452 453
 }
453 454
 
454
-int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
455
+int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos)
455 456
 {
456 457
 	rpn_if_default_data_t *data;
457 458
 	size_t i, res, cur, curlim, dim_sz;
@@ -467,7 +468,6 @@ int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos, rpn_value_t *_data)
467 468
 	{
468 469
 		return -1;
469 470
 	}
470
-	/**@todo check if *(data->size_lim) overflow rif->params->rpn_argc */
471 471
 
472 472
 	dim_sz = 1;
473 473
 	for(i=0;  i < *(data->size_lim); i++)

+ 3
- 6
rpn_if_default.h View File

@@ -166,12 +166,11 @@ int rpn_if_argf_linear(rpn_if_t *rif, size_t pos, rpn_value_t *args);
166 166
 /**@brief Transform 1st expression result to position 
167 167
  * @param rif Expressions
168 168
  * @param pos Pointer on resulting position in memory map
169
- * @param data Pointer on resulting data
170 169
  * @return 0 or -1 on error
171 170
  * @note Data from position fecth is done by generic @ref rpn_if_setres_default
172 171
  * function
173 172
  */
174
-int rpn_if_resf_linear(rpn_if_t *rif, size_t *pos, rpn_value_t *data);
173
+int rpn_if_resf_linear(rpn_if_t *rif, size_t *pos);
175 174
 
176 175
 /**@brief Set the 1st & 2nd argument from position
177 176
  * @param rif Expressions
@@ -185,12 +184,11 @@ int rpn_if_argf_xy(rpn_if_t *rif, size_t pos, rpn_value_t *args);
185 184
 /**@brief Transform 1st and 2nd result into a memory map's offset
186 185
  * @param rif Expressions
187 186
  * @param pos Memory map offset pointer
188
- * @param data Pointer on resulting data
189 187
  * @return 0 or -1 on error
190 188
  * @note Data from position fetch is done by generic @ref rpn_if_setres_default
191 189
  * function
192 190
  */
193
-int rpn_if_resf_xy(rpn_if_t *rif, size_t *pos, rpn_value_t *data);
191
+int rpn_if_resf_xy(rpn_if_t *rif, size_t *pos);
194 192
 
195 193
 /**@brief Set X first arguments from position
196 194
  * @param rif Expressions
@@ -204,11 +202,10 @@ int rpn_if_argf_xdim(rpn_if_t *rif, size_t pos, rpn_value_t *args);
204 202
 /**@brief Transform X arguments into a memory map's offset
205 203
  * @param rif Expressions
206 204
  * @param pos Memory map offset pointer
207
- * @param data Pointer on resulting data
208 205
  * @return 0 or -1 on error
209 206
  * @note Data from position fetch is done by generic @ref rpn_if_setres_default
210 207
  * function
211 208
  */
212
-int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos, rpn_value_t *data);
209
+int rpn_if_resf_xdim(rpn_if_t *rif, size_t *pos);
213 210
 
214 211
 #endif

+ 77
- 0
tests/tests_rpniter.py View File

@@ -124,6 +124,29 @@ class TestRPNIterInit(unittest.TestCase):
124 124
                 self.assertEqual(params.size_lim, arg[2])
125 125
                 self.assertIsNone(params.const_values)
126 126
     
127
+    def test_shape(self):
128
+        """ Test the shape method """
129
+        tests = [((pyrpn.const.POS_XY,
130
+                          pyrpn.const.RESULT_COUNT,
131
+                          (640,480)), (640,480)),
132
+                        ((pyrpn.const.POS_LINEAR,
133
+                          pyrpn.const.RESULT_BOOL,
134
+                          (1024,)), (1024,)),
135
+                        ((pyrpn.const.POS_LINEAR,
136
+                          pyrpn.const.RESULT_RGBA,
137
+                          (1024,)), (1024,4)),
138
+                        ((pyrpn.const.POS_XDIM,
139
+                          pyrpn.const.RESULT_BOOL,
140
+                          (2,640,480)),  (640,480)),
141
+                        ((pyrpn.const.POS_XDIM,
142
+                          pyrpn.const.RESULT_RGB,
143
+                          (5,13,37,13,12,42)), (13,37,13,12,42,3)),
144
+                ]
145
+        for args, expt in tests:
146
+            with self.subTest(args=args, expt_shape=expt):
147
+                rif = pyrpn.RPNIterExpr(*args)
148
+                self.assertEqual(rif.shape(), expt)
149
+
127 150
     @skipIfNoNumpy()
128 151
     def test_buffer(self):
129 152
         """ Test the len on buffer interface using numpy """
@@ -445,6 +468,60 @@ class TestRPNIterConst(unittest.TestCase):
445 468
         expt_pos = rif.to_pos(*expt)
446 469
         self.assertEqual(pos, expt_pos)
447 470
 
471
+    def test_linear_rgb(self):
472
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_LINEAR,
473
+                                pyrpn.const.RESULT_RGB,
474
+                                (512,))
475
+        rif['X'] = 'A0 2 +'
476
+        rif['R'] = 'A0 1 +'
477
+        rif['G'] = 'A1 A2 + 255 %'
478
+        rif['B'] = 'A2 2 * A3 +'
479
+        
480
+        pos = rif.step(0)
481
+        self.assertEqual(pos, 2)
482
+        data = np.frombuffer(rif, dtype=np.uint64).reshape(rif.shape())
483
+        colors = list(data[2])
484
+        self.assertEqual(colors, [1,0,0])
485
+
486
+        pos = rif.step(2)
487
+        self.assertEqual(pos, 4)
488
+        data = np.frombuffer(rif, dtype=np.uint64).reshape(rif.shape())
489
+        colors = list(data[4])
490
+        self.assertEqual(colors, [3, 1, 0])
491
+
492
+    def test_linear_rgba(self):
493
+        rif = pyrpn.RPNIterExpr(pyrpn.const.POS_LINEAR,
494
+                                pyrpn.const.RESULT_RGBA,
495
+                                (512,))
496
+        rif['X'] = 'A0 2 +'
497
+        rif['R'] = 'A0 1 +'
498
+        rif['G'] = 'A1 A2 + 255 %'
499
+        rif['B'] = 'A2 2 * A3 +'
500
+        rif['A'] = 'A1 A2 A3 + +'
501
+        
502
+        pos = rif.step(0)
503
+        self.assertEqual(pos, 2)
504
+        data = np.frombuffer(rif, dtype=np.uint64).reshape(rif.shape())
505
+        colors = list(data[2])
506
+        self.assertEqual(colors, [1,0,0,0])
507
+
508
+        pos = rif.step(2)
509
+        self.assertEqual(pos, 4)
510
+        data = np.frombuffer(rif, dtype=np.uint64).reshape(rif.shape())
511
+        colors = list(data[4])
512
+        self.assertEqual(colors, [3, 1, 0, 1])
513
+
514
+        pos = rif.step(4)
515
+        self.assertEqual(pos, 6)
516
+        data = np.frombuffer(rif, dtype=np.uint64).reshape(rif.shape())
517
+        colors = list(data[6])
518
+        self.assertEqual(colors, [5, 4, 2, 4])
519
+
520
+        pos = rif.step(6)
521
+        self.assertEqual(pos, 8)
522
+        data = np.frombuffer(rif, dtype=np.uint64).reshape(rif.shape())
523
+        colors = list(data[8])
524
+        self.assertEqual(colors, [7, 9, 10, 11])
448 525
 
449 526
 
450 527
 if __name__ == '__main__':

Loading…
Cancel
Save