Skip to content

Commit

Permalink
Conversions from Array & Dictionary to PerlAV & PerlHV
Browse files Browse the repository at this point in the history
+ make unsafe conversions more explict
+ add more test
+ renaming a little
  • Loading branch information
aleksey-mashanov committed Sep 30, 2016
1 parent 3c07d28 commit 4543816
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 100 deletions.
13 changes: 13 additions & 0 deletions Sources/Perl/AV.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ final class PerlAV : PerlSVProtocol {
pointer.pointee.refcntDec(perl: perl)
}

convenience init<C : Collection>(_ c: C, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current)
where C.Iterator.Element : PerlSVConvertible {
self.init(perl: perl)
reserveCapacity(numericCast(c.count))
for (i, v) in c.enumerated() {
self[i] = v as? PerlSV ?? PerlSV(v, perl: perl)
}
}

func value<T : PerlSVConvertible>() throws -> [T] {
return try map { try T.promoteFromUnsafeSV($0.pointer) }
}
Expand Down Expand Up @@ -62,6 +71,10 @@ extension PerlAV : RangeReplaceableCollection {
extend(to: self.count + count)
}

func reserveCapacity(_ capacity: Int) {
extend(to: capacity)
}

func replaceSubrange<C: Collection>(_ subRange: Range<Index>, with newElements: C)
where C.Iterator.Element == Element {
/* precondition(subRange.lowerBound >= 0, "replace: subRange start is negative")
Expand Down
8 changes: 4 additions & 4 deletions Sources/Perl/CV.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,13 @@ extension PerlCV {

extension PerlCV {
@discardableResult
convenience init<R: Collection>(name: String? = nil, file: StaticString = #file, body: @escaping (ContiguousArray<PerlSV>) throws -> R)
convenience init<R: Collection>(name: String? = nil, file: StaticString = #file, body: @escaping ([PerlSV]) throws -> R)
where R.Iterator.Element == PerlSV {
self.init(name: name, file: file) {
(stack: UnsafeXSubStack) in
let args = try ContiguousArray<PerlSV>(stack.args, perl: stack.perl)
let args = stack.args.map(PerlSV.promoteFromUnsafeSV)
let result = try body(args)
stack.xsReturn(ContiguousArray<UnsafeSvPointer>(result, perl: stack.perl))
stack.xsReturn(result.map { $0.promoteToUnsafeSV(perl: stack.perl) })
}
}
}
Expand All @@ -104,7 +104,7 @@ extension PerlMappedClass {
% end

@discardableResult
static func createPerlMethod<R: Collection>(_ method: String, file: StaticString = #file, body: @escaping (ContiguousArray<PerlSV>) throws -> R) -> PerlCV
static func createPerlMethod<R: Collection>(_ method: String, file: StaticString = #file, body: @escaping ([PerlSV]) throws -> R) -> PerlCV
where R.Iterator.Element == PerlSV {
return PerlCV(name: perlClassName + "::" + method, file: file, body: body)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Perl/Call.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ extension UnsafeInterpreter {
where C.Iterator.Element == PerlSVConvertible? {
enterScope()
defer { leaveScope() }
let svArgs = ContiguousArray<UnsafeSvPointer>(args, perl: &self)
let svArgs: [UnsafeSvPointer] = args.map { $0?.promoteToUnsafeSV(perl: &self) ?? newSV() }
% if r == "Void":
try unsafeCall(sv: sv, discardingResultWithArgs: svArgs, flags: flags)
% else:
Expand Down
7 changes: 7 additions & 0 deletions Sources/Perl/HV.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ final class PerlHV : PerlSVProtocol {
pointer.pointee.refcntDec(perl: perl)
}

convenience init<T : PerlSVConvertible>(_ dict: [String: T]) {
self.init()
for (k, v) in dict {
self[k] = v as? PerlSV ?? PerlSV(v)
}
}

func value<T: PerlSVConvertible>() throws -> [String: T] {
var dict = [String: T]()
for (k, v) in pointer.pointee.collection(perl: perl) {
Expand Down
41 changes: 16 additions & 25 deletions Sources/Perl/SV.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,9 @@ final class PerlSV : PerlSVProtocol {
pointer = perl.pointee.newSV()
}

init(_ v: Bool, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
init<T : PerlSVConvertible>(_ v: T, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
self.perl = perl
pointer = perl.pointee.newSV(v)
}

init(_ v: Int, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
self.perl = perl
pointer = perl.pointee.newSV(v)
}

init(_ v: String, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
self.perl = perl
pointer = perl.pointee.newSV(v)
pointer = v.promoteToUnsafeSV(perl: perl)
}

init<T: PerlSVProtocol>(referenceTo sv: T) {
Expand All @@ -47,21 +37,22 @@ final class PerlSV : PerlSVProtocol {
}
}

convenience init(_ av: PerlAV) {
self.init(referenceTo: av)
}

convenience init(_ hv: PerlHV) {
self.init(referenceTo: hv)
init<T : PerlSVConvertible>(_ array: [T], perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
self.perl = perl
pointer = array.promoteToUnsafeSV(perl: perl)
}

convenience init(_ cv: PerlCV) {
self.init(referenceTo: cv)
init<T : PerlSVConvertible>(_ dict: [String: T], perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
self.perl = perl
pointer = dict.promoteToUnsafeSV(perl: perl)
}

init(_ v: PerlMappedClass, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
self.perl = perl
pointer = perl.pointee.newSV(v)
convenience init<T : PerlSVConvertible>(_ v: T?, perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) {
if let v = v {
self.init(v, perl: perl)
} else {
self.init(perl: perl)
}
}

deinit {
Expand All @@ -75,8 +66,8 @@ final class PerlSV : PerlSVProtocol {
var isRef: Bool { return pointer.pointee.isRef }
var isObject: Bool { return pointer.pointee.isObject(perl: perl) }

var refValue: PerlSV? {
guard let sv = pointer.pointee.refValue else { return nil }
var referent: PerlSV? {
guard let sv = pointer.pointee.referent else { return nil }
return PerlSV(sv)
}

Expand Down
73 changes: 16 additions & 57 deletions Sources/Perl/SvConvertible.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,67 +114,26 @@ extension Optional where Wrapped : PerlSVConvertible {
}
}

extension RangeReplaceableCollection where Iterator.Element == UnsafeSvPointer, IndexDistance == Int {
init<C : Collection>(_ c: C, perl: UnsafeInterpreterPointer) where C.Iterator.Element == PerlSVConvertible? {
func transform(_ v: PerlSVConvertible?) -> UnsafeSvPointer {
return v?.promoteToUnsafeSV(perl: perl) ?? perl.pointee.newSV()
}
self.init()
let initialCapacity = c.underestimatedCount
self.reserveCapacity(initialCapacity)

var iterator = c.makeIterator()

// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
self.append(transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() {
self.append(transform(element))
}
}

// FIXME remove it
init<C : Collection>(_ c: C, perl: UnsafeInterpreterPointer) where C.Iterator.Element : PerlSVConvertible {
func transform(_ v: PerlSVConvertible) -> UnsafeSvPointer {
return v.promoteToUnsafeSV(perl: perl)
}
self.init()
let initialCapacity = c.underestimatedCount
self.reserveCapacity(initialCapacity)

var iterator = c.makeIterator()

// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
self.append(transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() {
self.append(transform(element))
extension Collection where Iterator.Element : PerlSVConvertible {
func promoteToUnsafeSV(perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) -> UnsafeSvPointer {
let av = perl.pointee.newAV()!
var c = av.pointee.collection(perl: perl)
c.reserveCapacity(numericCast(count))
for (i, v) in enumerated() {
c[i] = v.promoteToUnsafeSV(perl: perl)
}
return perl.pointee.newRV(noinc: av)
}
}

extension RangeReplaceableCollection where Iterator.Element : PerlSVConvertible, IndexDistance == Int {
init<C : Collection>(_ c: C, perl: UnsafeInterpreterPointer) throws where C.Iterator.Element == UnsafeSvPointer {
func transform(_ v: UnsafeSvPointer) throws -> Iterator.Element {
return try Iterator.Element.promoteFromUnsafeSV(v)
}
self.init()
let initialCapacity = c.underestimatedCount
self.reserveCapacity(initialCapacity)

var iterator = c.makeIterator()

// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
self.append(try transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() {
self.append(try transform(element))
// where Key == String, but it is unsupported
extension Dictionary where Value : PerlSVConvertible {
func promoteToUnsafeSV(perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) -> UnsafeSvPointer {
let hv = perl.pointee.newHV()!
var c = hv.pointee.collection(perl: perl)
for (k, v) in self {
c[k as! String] = v.promoteToUnsafeSV(perl: perl)
}
return perl.pointee.newRV(noinc: hv)
}
}
4 changes: 4 additions & 0 deletions Sources/Perl/UnsafeAV.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ struct UnsafeAvCollection : RandomAccessCollection {
extend(to: self.count + count)
}

func reserveCapacity(_ capacity: Int) {
extend(to: capacity)
}

func append(_ sv: Element) {
perl.pointee.av_push(av, sv)
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/Perl/UnsafeSV.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extension UnsafeSV {
return perl.pointee.sv_isobject(&self)
}

var refValue: UnsafeSvPointer? { mutating get { return SvROK(&self) ? SvRV(&self) : nil } }
var referent: UnsafeSvPointer? { mutating get { return SvROK(&self) ? SvRV(&self) : nil } }

mutating func value(perl: UnsafeInterpreterPointer = UnsafeInterpreter.current) -> Bool {
return perl.pointee.SvTRUE(&self)
Expand All @@ -65,7 +65,7 @@ extension UnsafeSV {
case .array:
return UnsafeMutableRawPointer(&self).bindMemory(to: UnsafeAV.self, capacity: 1)
case .scalar:
if let v = refValue {
if let v = referent {
return try v.pointee.value()
} else {
fallthrough
Expand All @@ -80,7 +80,7 @@ extension UnsafeSV {
case .hash:
return UnsafeMutableRawPointer(&self).bindMemory(to: UnsafeHV.self, capacity: 1)
case .scalar:
if let v = refValue {
if let v = referent {
return try v.pointee.value()
} else {
fallthrough
Expand All @@ -95,7 +95,7 @@ extension UnsafeSV {
case .code:
return UnsafeMutableRawPointer(&self).bindMemory(to: UnsafeCV.self, capacity: 1)
case .scalar:
if let v = refValue {
if let v = referent {
return try v.pointee.value()
} else {
fallthrough
Expand Down
2 changes: 1 addition & 1 deletion Sources/SampleXS/SampleXS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func boot(_ p: PerlInterpreter.Pointer) {
stack.xsReturn(CollectionOfOne(result))
}
MyTest.createPerlMethod("test") {
(args: ContiguousArray<PerlSV>) -> ContiguousArray<PerlSV> in
(args: [PerlSV]) -> [PerlSV] in
// let slf: MyTest = try! args[0].value()
// slf.test(value: args[1].value())
// slf.test2(value: try! args[2].value() as PerlTestMouse)
Expand Down
3 changes: 2 additions & 1 deletion Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import XCTest

var tests = [XCTestCaseEntry]()
tests += [testCase(EmbedTests.allTests)]
tests += [testCase(BasicTests.allTests)]
tests += [testCase(ConvertFromPerlTests.allTests)]
tests += [testCase(ConvertToPerlTests.allTests)]
tests += [testCase(ObjectTests.allTests)]
tests += [testCase(BenchmarkTests.allTests)]
tests += [testCase(PerlCoroTests.allTests)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import XCTest
@testable import Perl

class BasicTests : EmbeddedTestCase {
static var allTests: [(String, (BasicTests) -> () throws -> Void)] {
class ConvertFromPerlTests : EmbeddedTestCase {
static var allTests: [(String, (ConvertFromPerlTests) -> () throws -> Void)] {
return [
("testUndef", testUndef),
("testInt", testInt),
Expand Down Expand Up @@ -58,8 +58,8 @@ class BasicTests : EmbeddedTestCase {
XCTAssert(!v.isInt)
XCTAssert(!v.isString)
XCTAssert(v.isRef)
XCTAssertNotNil(v.refValue)
let r: PerlSV = v.refValue!
XCTAssertNotNil(v.referent)
let r: PerlSV = v.referent!
XCTAssert(r.isInt)
XCTAssertEqual(r.value() as Int, 42)
}
Expand All @@ -70,7 +70,7 @@ class BasicTests : EmbeddedTestCase {
XCTAssert(!sv.isInt)
XCTAssert(!sv.isString)
XCTAssert(sv.isRef)
XCTAssertNotNil(sv.refValue)
XCTAssertNotNil(sv.referent)
let av: PerlAV = try sv.value()
XCTAssertEqual(av.count, 2)
XCTAssertEqual(av[0].value() as Int, 42)
Expand All @@ -95,7 +95,7 @@ class BasicTests : EmbeddedTestCase {
XCTAssert(!sv.isInt)
XCTAssert(!sv.isString)
XCTAssert(sv.isRef)
XCTAssertNotNil(sv.refValue)
XCTAssertNotNil(sv.referent)
let hv: PerlHV = try sv.value()
// XCTAssertEqual(hv.count, 2)
XCTAssertEqual(hv["one"]!.value() as Int, 1)
Expand All @@ -115,7 +115,7 @@ class BasicTests : EmbeddedTestCase {
XCTAssert(!sv.isInt)
XCTAssert(!sv.isString)
XCTAssert(sv.isRef)
XCTAssertNotNil(sv.refValue)
XCTAssertNotNil(sv.referent)
let cv: PerlCV = try sv.value()
XCTAssertEqual(try cv.call(10, 15) as Int?, 25)
// XCTAssertEqual(try sv.call(10, 15) as Int, 25)
Expand Down
Loading

0 comments on commit 4543816

Please sign in to comment.