static PyObject* PyPointlessSet_iter(PyObject* set) { if (!PyPointlessSet_Check(set)) { PyErr_BadInternalCall(); return 0; } PyPointlessSetIter* iter = PyObject_New(PyPointlessSetIter, &PyPointlessSetIterType); if (iter == 0) return 0; Py_INCREF(set); iter->set = (PyPointlessSet*)set; iter->iter_state = 0; return (PyObject*)iter; }
static uint32_t pointless_export_py_rec(pointless_export_state_t* state, PyObject* py_object, uint32_t depth) { // don't go too deep if (depth >= POINTLESS_MAX_DEPTH) { PyErr_SetString(PyExc_ValueError, "structure is too deep"); state->is_error = 1; printf("line: %i\n", __LINE__); state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } // check simple types first uint32_t handle = POINTLESS_CREATE_VALUE_FAIL; // return an error on failure #define RETURN_OOM(state) {PyErr_NoMemory(); (state)->is_error = 1; printf("line: %i\n", __LINE__); state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL;} #define RETURN_OOM_IF_FAIL(handle, state) if ((handle) == POINTLESS_CREATE_VALUE_FAIL) RETURN_OOM(state); // booleans, need this above integer check, cause PyInt_Check return 1 for booleans if (PyBool_Check(py_object)) { if (py_object == Py_True) handle = pointless_create_boolean_true(&state->c); else handle = pointless_create_boolean_false(&state->c); RETURN_OOM_IF_FAIL(handle, state); // integer } else if (PyInt_Check(py_object)) { long v = PyInt_AS_LONG(py_object); // unsigned if (v >= 0) { if (v > UINT32_MAX) { PyErr_Format(PyExc_ValueError, "integer too large for mere 32 bits"); printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } handle = pointless_create_u32(&state->c, (uint32_t)v); // signed } else { if (!(INT32_MIN <= v && v <= INT32_MAX)) { PyErr_Format(PyExc_ValueError, "integer too large for mere 32 bits with a sign"); printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } handle = pointless_create_i32(&state->c, (int32_t)v); } RETURN_OOM_IF_FAIL(handle, state); // long } else if (PyLong_Check(py_object)) { // this will raise an overflow error if number is outside the legal range of PY_LONG_LONG PY_LONG_LONG v = PyLong_AsLongLong(py_object); // if there was an exception, clear it, and set our own if (PyErr_Occurred()) { PyErr_Clear(); PyErr_SetString(PyExc_ValueError, "value of long is way beyond what we can store right now"); printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } // unsigned if (v >= 0) { if (v > UINT32_MAX) { PyErr_Format(PyExc_ValueError, "long too large for mere 32 bits"); printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } handle = pointless_create_u32(&state->c, (uint32_t)v); // signed } else { if (!(INT32_MIN <= v && v <= INT32_MAX)) { PyErr_Format(PyExc_ValueError, "long too large for mere 32 bits with a sign"); printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } handle = pointless_create_i32(&state->c, (int32_t)v); } RETURN_OOM_IF_FAIL(handle, state); // None object } else if (py_object == Py_None) { handle = pointless_create_null(&state->c); RETURN_OOM_IF_FAIL(handle, state); } else if (PyFloat_Check(py_object)) { handle = pointless_create_float(&state->c, (float)PyFloat_AS_DOUBLE(py_object)); RETURN_OOM_IF_FAIL(handle, state); } if (handle != POINTLESS_CREATE_VALUE_FAIL) return handle; // remaining types are containers/big-values, which we track // either for space-savings or maintaining circular references // if object has been seen before, return its handle handle = pointless_export_get_seen(state, py_object); if (handle != POINTLESS_CREATE_VALUE_FAIL) return handle; // list/tuple object if (PyList_Check(py_object) || PyTuple_Check(py_object)) { // create and cache handle assert(is_container(py_object)); handle = pointless_create_vector_value(&state->c); RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // populate vector Py_ssize_t i, n_items = PyList_Check(py_object) ? PyList_GET_SIZE(py_object) : PyTuple_GET_SIZE(py_object); for (i = 0; i < n_items; i++) { PyObject* child = PyList_Check(py_object) ? PyList_GET_ITEM(py_object, i) : PyTuple_GET_ITEM(py_object, i); uint32_t child_handle = pointless_export_py_rec(state, child, depth + 1); if (child_handle == POINTLESS_CREATE_VALUE_FAIL) return child_handle; if (pointless_create_vector_value_append(&state->c, handle, child_handle) == POINTLESS_CREATE_VALUE_FAIL) { RETURN_OOM(state); } } // pointless value vectors } else if (PyPointlessVector_Check(py_object)) { // currently, we only support value vectors, they are simple PyPointlessVector* v = (PyPointlessVector*)py_object; const char* error = 0; switch(v->v->type) { case POINTLESS_VECTOR_VALUE: case POINTLESS_VECTOR_VALUE_HASHABLE: handle = pointless_recreate_value(&v->pp->p, v->v, &state->c, &error); if (handle == POINTLESS_CREATE_VALUE_FAIL) { printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; PyErr_Format(PyExc_ValueError, "pointless_recreate_value(): %s", error); return POINTLESS_CREATE_VALUE_FAIL; } break; case POINTLESS_VECTOR_I8: handle = pointless_create_vector_i8_owner(&state->c, pointless_reader_vector_i8(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_U8: handle = pointless_create_vector_u8_owner(&state->c, pointless_reader_vector_u8(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_I16: handle = pointless_create_vector_i16_owner(&state->c, pointless_reader_vector_i16(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_U16: handle = pointless_create_vector_u16_owner(&state->c, pointless_reader_vector_u16(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_I32: handle = pointless_create_vector_i32_owner(&state->c, pointless_reader_vector_i32(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_U32: handle = pointless_create_vector_u32_owner(&state->c, pointless_reader_vector_u32(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_I64: handle = pointless_create_vector_i64_owner(&state->c, pointless_reader_vector_i64(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_U64: handle = pointless_create_vector_u64_owner(&state->c, pointless_reader_vector_u64(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_FLOAT: handle = pointless_create_vector_float_owner(&state->c, pointless_reader_vector_float(&v->pp->p, v->v) + v->slice_i, v->slice_n); break; case POINTLESS_VECTOR_EMPTY: handle = pointless_create_vector_value(&state->c); break; default: state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; PyErr_SetString(PyExc_ValueError, "internal error: illegal type for primitive vector"); return POINTLESS_CREATE_VALUE_FAIL; } RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // python bytearray } else if (PyByteArray_Check(py_object)) { // create handle and hand over the memory Py_ssize_t n_items = PyByteArray_GET_SIZE(py_object); if (n_items > UINT32_MAX) { PyErr_SetString(PyExc_ValueError, "bytearray has too many items"); state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; return POINTLESS_CREATE_VALUE_FAIL; } handle = pointless_create_vector_u8_owner(&state->c, (uint8_t*)PyByteArray_AS_STRING(py_object), (uint32_t)n_items); RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // primitive vectors } else if (PyPointlessPrimVector_Check(py_object)) { // we just hand over the memory PyPointlessPrimVector* prim_vector = (PyPointlessPrimVector*)py_object; uint32_t n_items = pointless_dynarray_n_items(&prim_vector->array); void* data = prim_vector->array._data; switch (prim_vector->type) { case POINTLESS_PRIM_VECTOR_TYPE_I8: handle = pointless_create_vector_i8_owner(&state->c, (int8_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_U8: handle = pointless_create_vector_u8_owner(&state->c, (uint8_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_I16: handle = pointless_create_vector_i16_owner(&state->c, (int16_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_U16: handle = pointless_create_vector_u16_owner(&state->c, (uint16_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_I32: handle = pointless_create_vector_i32_owner(&state->c, (int32_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_U32: handle = pointless_create_vector_u32_owner(&state->c, (uint32_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_I64: handle = pointless_create_vector_i64_owner(&state->c, (int64_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_U64: handle = pointless_create_vector_u64_owner(&state->c, (uint64_t*)data, n_items); break; case POINTLESS_PRIM_VECTOR_TYPE_FLOAT: handle = pointless_create_vector_float_owner(&state->c, (float*)data, n_items); break; default: PyErr_SetString(PyExc_ValueError, "internal error: illegal type for primitive vector"); state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; return POINTLESS_CREATE_VALUE_FAIL; } RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // unicode object } else if (PyUnicode_Check(py_object)) { // get it from python Py_UNICODE* python_buffer = PyUnicode_AS_UNICODE(py_object); // string must not contain zero's Py_ssize_t s_len_python = PyUnicode_GET_SIZE(py_object); #if Py_UNICODE_SIZE == 4 uint32_t s_len_pointless = pointless_ucs4_len(python_buffer); #else uint32_t s_len_pointless = pointless_ucs2_len(python_buffer); #endif if (s_len_python < 0 || (uint64_t)s_len_python != s_len_pointless) { PyErr_SetString(PyExc_ValueError, "unicode string contains a zero, where it shouldn't"); state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; return POINTLESS_CREATE_VALUE_FAIL; } #if Py_UNICODE_SIZE == 4 if (state->unwiden_strings && pointless_is_ucs4_ascii((uint32_t*)python_buffer)) handle = pointless_create_string_ucs4(&state->c, python_buffer); else handle = pointless_create_unicode_ucs4(&state->c, python_buffer); #else if (state->unwiden_strings && pointless_is_ucs2_ascii(python_buffer)) handle = pointless_create_string_ucs2(&state->c, python_buffer); else handle = pointless_create_unicode_ucs2(&state->c, python_buffer); #endif RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // string object } else if (PyString_Check(py_object)) { // get it from python uint8_t* python_buffer = (uint8_t*)PyString_AS_STRING(py_object); // string must not contain zero's Py_ssize_t s_len_python = PyString_GET_SIZE(py_object); uint32_t s_len_pointless = pointless_ascii_len(python_buffer); if (s_len_python < 0 || (uint64_t)s_len_python != s_len_pointless) { PyErr_SetString(PyExc_ValueError, "string contains a zero, where it shouldn't"); state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; return POINTLESS_CREATE_VALUE_FAIL; } handle = pointless_create_string_ascii(&state->c, python_buffer); RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // dict object } else if (PyDict_Check(py_object)) { handle = pointless_create_map(&state->c); RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } PyObject* key = 0; PyObject* value = 0; Py_ssize_t pos = 0; while (PyDict_Next(py_object, &pos, &key, &value)) { uint32_t key_handle = pointless_export_py_rec(state, key, depth + 1); uint32_t value_handle = pointless_export_py_rec(state, value, depth + 1); if (key_handle == POINTLESS_CREATE_VALUE_FAIL || value_handle == POINTLESS_CREATE_VALUE_FAIL) break; if (pointless_create_map_add(&state->c, handle, key_handle, value_handle) == POINTLESS_CREATE_VALUE_FAIL) { PyErr_SetString(PyExc_ValueError, "error adding key/value pair to map"); state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; break; } } if (state->is_error) { return POINTLESS_CREATE_VALUE_FAIL; } // set object } else if (PyAnySet_Check(py_object)) { PyObject* iterator = PyObject_GetIter(py_object); PyObject* item = 0; if (iterator == 0) { printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } // get a handle handle = pointless_create_set(&state->c); RETURN_OOM_IF_FAIL(handle, state); // cache object if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // iterate over it while ((item = PyIter_Next(iterator)) != 0) { uint32_t item_handle = pointless_export_py_rec(state, item, depth + 1); if (item_handle == POINTLESS_CREATE_VALUE_FAIL) break; if (pointless_create_set_add(&state->c, handle, item_handle) == POINTLESS_CREATE_VALUE_FAIL) { PyErr_SetString(PyExc_ValueError, "error adding item to set"); printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; break; } } Py_DECREF(iterator); if (PyErr_Occurred()) { printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; return POINTLESS_CREATE_VALUE_FAIL; } // bitvector } else if (PyPointlessBitvector_Check(py_object)) { PyPointlessBitvector* bitvector = (PyPointlessBitvector*)py_object; if (bitvector->is_pointless) { uint32_t i, n_bits = pointless_reader_bitvector_n_bits(&bitvector->pointless_pp->p, bitvector->pointless_v); void* bits = pointless_calloc(ICEIL(n_bits, 8), 1); if (bits == 0) { RETURN_OOM(state); } for (i = 0; i < n_bits; i++) { if (pointless_reader_bitvector_is_set(&bitvector->pointless_pp->p, bitvector->pointless_v, i)) bm_set_(bits, i); } if (state->normalize_bitvector) handle = pointless_create_bitvector(&state->c, bits, n_bits); else handle = pointless_create_bitvector_no_normalize(&state->c, bits, n_bits); pointless_free(bits); bits = 0; } else { if (state->normalize_bitvector) handle = pointless_create_bitvector(&state->c, bitvector->primitive_bits, bitvector->primitive_n_bits); else handle = pointless_create_bitvector_no_normalize(&state->c, bitvector->primitive_bits, bitvector->primitive_n_bits); } RETURN_OOM_IF_FAIL(handle, state); if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } } else if (PyPointlessSet_Check(py_object)) { PyPointlessSet* set = (PyPointlessSet*)py_object; const char* error = 0; handle = pointless_recreate_value(&set->pp->p, set->v, &state->c, &error); if (handle == POINTLESS_CREATE_VALUE_FAIL) { printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; PyErr_Format(PyExc_ValueError, "pointless_recreate_value(): %s", error); return POINTLESS_CREATE_VALUE_FAIL; } if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } } else if (PyPointlessMap_Check(py_object)) { PyPointlessMap* map = (PyPointlessMap*)py_object; const char* error = 0; handle = pointless_recreate_value(&map->pp->p, map->v, &state->c, &error); if (handle == POINTLESS_CREATE_VALUE_FAIL) { printf("line: %i\n", __LINE__); state->is_error = 1; state->error_line = __LINE__; PyErr_Format(PyExc_ValueError, "pointless_recreate_value(): %s", error); return POINTLESS_CREATE_VALUE_FAIL; } if (!pointless_export_set_seen(state, py_object, handle)) { RETURN_OOM(state); } // type not supported } else { PyErr_Format(PyExc_ValueError, "type <%s> not supported", py_object->ob_type->tp_name); state->error_line = __LINE__; printf("line: %i\n", __LINE__); state->is_error = 1; } #undef RETURN_OOM #undef RETURN_IF_OOM return handle; }