taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

CStringArray.swift (3082B)


      1 //  MIT License
      2 //  Copyright 2020 Robert Salesas
      3 //
      4 //  Permission is hereby granted, free of charge, to any person obtaining a copy of this software
      5 //  and associated documentation files (the "Software"), to deal in the Software without restriction,
      6 //  including without limitation the rights to use, copy, modify, merge, publish, distribute,
      7 //  sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
      8 //  furnished to do so, subject to the following conditions:
      9 //
     10 //  The above copyright notice and this permission notice shall be included in all copies or
     11 //  substantial portions of the Software.
     12 //
     13 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
     14 //  BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     15 //  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     16 //  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     17 //  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     18 //
     19 import Foundation
     20 
     21 /// `CStringArray` represents a C null-terminated array of pointers to C strings.
     22 ///
     23 /// The lifetime of the C strings will correspond to the lifetime of the `CStringArray`
     24 /// instance so be careful about copying the buffer as it may contain dangling pointers.
     25 
     26 public struct CStringArray {
     27     public let pointer: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>
     28     public let count: Int
     29     private var data: Data
     30 
     31     public init(_ array: [String]) {
     32         let count = array.count
     33 
     34         // Allocate memory to hold the CStrings and a terminating nil
     35         let pointer = UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>.allocate(capacity: count + 1)
     36         pointer.initialize(repeating: nil, count: count + 1)  // Implicit terminating nil at the end of the array
     37 
     38         // Populate the allocated memory with pointers to CStrings
     39         var e = 0
     40         array.forEach {
     41             pointer[e] = strdup($0)
     42             e += 1
     43         }
     44 
     45         // This uses the deallocator available on the data structure as a solution to the fact that structs do not have `deinit`
     46         self.data = Data(bytesNoCopy: pointer, count: MemoryLayout<UnsafeMutablePointer<CChar>>.size * count, deallocator: .custom({_,_ in
     47             for i in 0...count - 1 {
     48                 free(pointer[i])
     49             }
     50             pointer.deallocate()
     51         }))
     52 
     53         self.pointer = pointer
     54         self.count = array.count
     55     }
     56 
     57     public subscript(index: Data.Index) -> UnsafeMutablePointer<CChar>? {
     58         get {
     59             precondition(index >= 0 && index < count, "Index out of range")
     60             return pointer[index]
     61         }
     62     }
     63 
     64     public subscript(index: Data.Index) -> String? {
     65         get {
     66             precondition(index >= 0 && index < count, "Index out of range")
     67             if let pointee = pointer[index] {
     68                 return String(cString: pointee)
     69             }
     70 
     71             return nil
     72         }
     73     }
     74 }