[swift-users] Set size of byte array

Brent Royal-Gordon brent at architechies.com
Fri Aug 5 05:32:38 CDT 2016


> On Aug 4, 2016, at 11:42 PM, KS Sreeram via swift-users <swift-users at swift.org> wrote:
> 
> I’m trying to initialize a byte-array efficiently with minimal copying with the following steps:
> 
> 1. Create an empty byte array.
> 2. Reserve sufficient capacity in the array.
> 3. Use mutable pointers into the array to fill in the data.
> 4. The actual size that was filled is known only after it is filled in.
> 5. I would like to set the size of the array to the actual size.
> 
> I couldn’t find any methods for doing the last step. Is there a way to do this?

I don't believe this is possible with an Array; the only way to work with uninitialized memory is with an UnsafeMutablePointer.

The simplest solution is probably to load the data into an allocated chunk of memory with an UnsafeMutablePointer and then create an NSData object to keep track of its lifetime. The `init(bytesNoCopy:length:deallocator:)` initializer can be used to make sure it deallocates the memory correctly.

If you don't *need* to use mutable pointers to fill the array, however, a custom SequenceType might be a better option. For instance, you could write a type like this which returns the data a byte at a time:

	struct MyDataSource: SequenceType, GeneratorType {
		...
		
		init(...) {
			...
		}
		
		var initialCapacity: Int {
			...guess at the capacity...
		}
		
		mutating func next() -> UInt8? {
			...determine and return the next byte, or nil if you've reached the end...
		}
	}

Then you can write something like this:

	var source = MyDataSource(...)
	var array: [UInt8] = []
	array.reserveCapacity(source.initialCapacity)
	array.appendContentsOf(source)

And, et voila, `array` is full of your bytes. From what I can tell, if the capacity is already there, the standard library effectively uses a loop as tight as any you could hope for:

    let base = buffer.firstElementAddress

    while (nextItem != nil) && count < capacity {
      (base + count).initialize(to: nextItem!)
      count += 1
      nextItem = stream.next()
    }
    buffer.count = count

So I suspect a custom SequenceType will perform much better than you would first guess.

Hope this helps,
-- 
Brent Royal-Gordon
Architechies



More information about the swift-users mailing list