Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}