File: bittools.c

package info (click to toggle)
pylibtiff 0.3.0~svn78-3.1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 560 kB
  • ctags: 2,766
  • sloc: python: 5,227; ansic: 1,011; sh: 16; makefile: 8
file content (181 lines) | stat: -rw-r--r-- 5,874 bytes parent folder | download
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
174
175
176
177
178
179
180
181
#include <Python.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#define PY_ARRAY_UNIQUE_SYMBOL PyArray_API
#include "numpy/arrayobject.h"

#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif

#define CHAR_BITS 8
#define CHAR_BITS_EXP 3

/* i/8 == i>>3 */
#define BITS(bytes)  (((unsigned long)(bytes)) << CHAR_BITS_EXP)
#define BYTES(bits)  (((bits) == 0) ? 0 : ((((bits) - 1) >> CHAR_BITS_EXP) + 1))
#define NBYTES(bits)  ((bits) >> CHAR_BITS_EXP)
#define BITMASK(i,width)  (((unsigned long) 1) << (((i))%(width)))
#define DATAPTR(data, i) ((char*)(data) + ((i)>>CHAR_BITS_EXP))
#define DATA(data, i) (*DATAPTR((data),(i)))
#define GETBIT(value, i, width) ((value & BITMASK((i),(width))) ? 1 : 0)
#define ARRGETBIT(arr, i) ((DATA(PyArray_DATA((PyArrayObject*)arr), (i)) & BITMASK((i),CHAR_BITS)) ? 1 : 0)

static PyObject *getbit(PyObject *self, PyObject *args, PyObject *kwds)
{
  PyObject* arr = NULL;
  char bit = 0;
  Py_ssize_t index = 0;
  static char* kwlist[] = {"array", "index", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|On:getbit", 
				   kwlist, &arr, &index))
    return NULL;

  if (!PyArray_Check(arr))
    {
      PyErr_SetString(PyExc_TypeError,"first argument must be array object");
      return NULL;
    }
  if (index >= BITS(PyArray_NBYTES((PyArrayObject*)arr)))
    {
      PyErr_SetString(PyExc_IndexError,"bit index out of range");
      return NULL;
    }
  bit = ARRGETBIT(arr, index);
  return Py_BuildValue("b",bit);
}

static PyObject *setbit(PyObject *self, PyObject *args, PyObject *kwds)
{
  PyObject* arr = NULL;
  char bit = 0, opt=0;
  Py_ssize_t index = 0;
  static char* kwlist[] = {"array", "index", "bit", "opt", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Onbb:setbit", 
				   kwlist, &arr, &index, &bit, &opt))
    return NULL;
  if (!opt)
    {
      if (!PyArray_Check(arr))
	{
	  PyErr_SetString(PyExc_TypeError,"first argument must be array object");
	  return NULL;
	}
      if (NBYTES(index) >= PyArray_NBYTES((PyArrayObject*)arr))
	{
	  PyErr_SetString(PyExc_IndexError,"bit index out of range");
	  return NULL;
	}
    }
  if (bit)
    DATA(PyArray_DATA((PyArrayObject*)arr), index) |= BITMASK(index, CHAR_BITS);
  else
    DATA(PyArray_DATA((PyArrayObject*)arr), index) &= ~BITMASK(index, CHAR_BITS);
  Py_INCREF(Py_None);
  return Py_None;
}

static PyObject *getword(PyObject *self, PyObject *args, PyObject *kwds)
{
  PyObject* arr = NULL;
  Py_ssize_t index = 0;
  Py_ssize_t width = 0, i;
  static char* kwlist[] = {"array", "index", "width", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Onn:getword", 
				   kwlist, &arr, &index, &width))
    return NULL;
  if (!PyArray_Check(arr))
    {
      PyErr_SetString(PyExc_TypeError,"first argument must be array object");
      return NULL;
    }
  if (((index+width-1) >= BITS(PyArray_NBYTES((PyArrayObject*)arr))) || (width<0))
    {
      PyErr_SetString(PyExc_IndexError,"bit index out of range");
      return NULL;
    }
  
  // fast code, at least 3x
  if (width<=32)
    {
      npy_uint32 x = *((npy_uint64*)DATAPTR(PyArray_DATA((PyArrayObject*)arr), index)) >> (index % CHAR_BITS);
      return Py_BuildValue("kn",x & (NPY_MAX_UINT32>>(32-width)), index+width);
    }
  // generic code
  if (width<=64)
    {
      npy_uint64 word = 0;
      for (i=0; i<width; ++i)
	if (ARRGETBIT(arr, index + i))
	    word |= BITMASK(i, width);
	else
	    word &= ~BITMASK(i, width);

      return Py_BuildValue("kn",word,index+width);
    }
  PyErr_SetString(PyExc_ValueError,"bit width must not be larger than 64");
  return NULL;
}

static PyObject *setword(PyObject *self, PyObject *args, PyObject *kwds)
{
  PyObject* arr = NULL;
  Py_ssize_t index = 0;
  Py_ssize_t width = 0, i, value_width=sizeof(npy_uint64)*CHAR_BITS;
  npy_uint64 value = 0;
  char opt = 0;
  static char* kwlist[] = {"array", "index", "width", "value", "opt", NULL};
  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Onnkb:setword", 
				   kwlist, &arr, &index, &width, &value, &opt))
    return NULL;
  if (!opt)
    {
      if (!PyArray_Check(arr))
	{
	  PyErr_SetString(PyExc_TypeError,"first argument must be array object");
	  return NULL;
	}
      if ((index+width-1) >= BITS(PyArray_NBYTES((PyArrayObject*)arr)) || width<0)
	{
	  printf("index,width,nbits=%d,%d,%d\n", index, width, BITS(PyArray_NBYTES((PyArrayObject*)arr)));
	  PyErr_SetString(PyExc_IndexError,"bit index out of range");
	  return NULL;
	}
      if (width>64)
	{
	  PyErr_SetString(PyExc_ValueError,"bit width must not be larger than 64");
	  return NULL;
	}
    }
  for (i=0; i<width; ++i)
    if ((i<value_width) && (GETBIT(value, i, value_width)))
      DATA(PyArray_DATA((PyArrayObject*)arr), index+i) |= BITMASK(index+i, CHAR_BITS);
    else
      DATA(PyArray_DATA((PyArrayObject*)arr), index+i) &= ~BITMASK(index+i, CHAR_BITS);

  return Py_BuildValue("n",index + width);
  /*
  Py_INCREF(Py_None);
  return Py_None;
  */
}

static PyMethodDef module_methods[] = {
  {"getbit", (PyCFunction)getbit, METH_VARARGS|METH_KEYWORDS, "Get bit value of an array at bit index."},
  {"setbit", (PyCFunction)setbit, METH_VARARGS|METH_KEYWORDS, "Set bit value of an array at bit index."},
  {"getword", (PyCFunction)getword, METH_VARARGS|METH_KEYWORDS, "getword(array, bitindex, wordwidth) - get word value from an array at bitindex with bitwidth."},
  {"setword", (PyCFunction)setword, METH_VARARGS|METH_KEYWORDS, "setword(array, bitindex, wordwidth, word) - set word value to an array at bitindex with bitwidth."},
  {NULL}  /* Sentinel */
};

PyMODINIT_FUNC
initbittools(void) 
{
  PyObject* m = NULL;
  import_array();
  if (PyErr_Occurred())
    {
      PyErr_SetString(PyExc_ImportError, "can't initialize module bittools (failed to import numpy)"); 
      return;
    }
  m = Py_InitModule3("bittools", module_methods, "");
}