0

I am trying to convert some python code into cython. In the python code I use data of type array.array('i', [...]) and use the method array.insert to insert an element at a specific index. in cython however, when I try to insert an element using the same method I get this error: BufferError: cannot resize an array that is exporting buffers

basically:

from cpython cimport array
cdef array.array[int] a = array.array('i', [1,2,3,3])
a.insert(1,5) # insert 5 in the index 1 -> throws error

I have been looking at cyappend3 of this answer but I am using libcpp and not sure I understand the magic written there. Any idea how to insert an element at a specific index in an array.array?

5
  • Either define another pointer to pint to you array then use indexing like : cdef int[:] ca = a or simply a.data.as_int returns pointer as int and you can use that to index as_int[1] … Commented Nov 1, 2022 at 23:03
  • @amirhm can you please share a piece of the code for both options? I am not sure I follow here Commented Nov 1, 2022 at 23:06
  • You are using the python array module, not numpy? Commented Nov 1, 2022 at 23:28
  • @hpaulj yes, the initial python code uses array.array and I want to convert it to cython using array.array of the cpyton Commented Nov 1, 2022 at 23:42
  • @sos I will write a answer, Commented Nov 2, 2022 at 9:49

2 Answers 2

2

Partial answer:

BufferError: cannot resize an array that is exporting buffers

This is telling you that you have a memoryview (or similar) of the array somewhere. It isn't possible to resize it because that memoryview is looking directly into that array's data and resizing the array will require reallocating the data. You can replicate this error in Python too if you do view = memoryview(arr) before you try to insert.

In your case:

cdef array.array[int] a = array.array('i', [1,2,3,3])

cdef array.array[int] a is defining an array with a fast buffer to elements of the array, and it's this buffer that prevents you from resizing it. If you just do cdef array.array a it works fine. Obviously you lose the fast buffer access to individual elements, but that's because you're trying to change the data out from under the buffer.


I strongly recommend you don't resize arrays though. Not only does it involve the O(n) copy of every element of the array. Also, unlike Python list, array doesn't over-allocate so even append causes a complete reallocation and copy every time (i.e. is O(n) rather than amortized O(1)).

Instead I'd suggest keeping the data as a Python list (or maybe something else) until you've finalized the length and only then converting to array.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! for append I think array has a method called extend_buffer that the documentation calls efficient. not sure how it will perform though against append of list.
2

what has been answered here in this post is correct, (https://stackoverflow.com/a/74285371/4529589), and I have the same recommendation.

However I want to add this point that if you want to use the insert but as well if you want to use the insert and still define as the c buffer, you could use the std::vector. This will be faster.

from libcpp.vector cimport vector

cdef vector[int] vect = array.array('i', [1,2,3,3])    
vect.insert(vect.begin() + 1 ,5)

and as well I recomend if you want to use this solution just drop the array and from the begining just use the vector initialization.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.