Most efficient way of getting large std::vector into Swift? - arrays

I have an Objective-C class that populates a std:vector with millions of points. The structure of the vector is:
typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;
So a CGContour is a vector of CGPoints and CGContours is a vector of the CGContour vector.
I need to access this data in a Swift class somehow. I don't want to use an NSArray because it has a huge overhead compared to using vector (it is like 10x as big and slow).
What would be the most efficient way to get millions of CGPoints accessible in Swift from my Objective-C class?
Edit:
I am populating my CGContours vector like this:
contourVector = CGContours(contours.size());
populatedContourNum = 0
//contours is OpenCV's contours
for( long c = 0; c < contours.size(); c++) {
if (populatedContourNum >= contourVector.size()) {
contourVector.resize(contourVector.size() + 1);
}
contourVector[populatedContourNum] = CGContour(contours[c].size());
for( long pointNum = 0; pointNum < contours[c].size(); pointNum++ )
{
contourVector[populatedContourNum][pointNum] = CGPointMake(contours[c][pointNum].x * scale,
contours[c][pointNum].y * scale);
}
populatedContourNum++;
}

Some parts are not clear enough but I will try to show you some example.
First of all, you need to prepare a class which can access your contourVector. (I cannot see if it is an instance field or a global variable, if it is an instance field, you may use the existing class.)
Create a header for the prepared class, again you may utilize the existing header, but this header needs to be compiled both in C-context and in C++ context. So, if your existing header contains some declaration which cannot be compiled in C-context, you may need separated two headers or some #ifs.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface YourClass : NSObject
- (NSInteger)contoursSize;
- (NSInteger)contourSizeAtIndex:(NSInteger)index;
- (CGPoint *)contourAtIndex:(NSInteger)index;
//...
#end
NS_ASSUME_NONNULL_END
Then add 3 methods to the class specified in the header:
#import "YourClass.h"
#import <vector>
typedef std::vector<CGPoint> CGContour;
typedef std::vector<CGContour> CGContours;
static CGContours contourVector;
#implementation YourClass
- (NSInteger)contoursSize {
return contourVector.size();
}
- (NSInteger)contourSizeAtIndex:(NSInteger)index {
return contourVector[index].size();
}
- (CGPoint *)contourAtIndex:(NSInteger)index {
return contourVector[index].data();
}
#end
Please do not forget to include the header inside your Project-Bridging-Header.h:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "YourClass.h"
You need to create a Swift side wrapper class, as you cannot create UnsafeBufferPointer in Objective-C.
class YourClassWrapper {
let yourInstance = YourClass()
var count: Int {
return yourInstance.contoursSize()
}
subscript(index: Int) -> UnsafeBufferPointer<CGPoint> {
guard 0..<count ~= index else {fatalError("Index \(index) out of bounds \(0..<count)")}
let start = yourInstance.contour(at: index)
let count = yourInstance.contourSize(at: index)
return UnsafeBufferPointer(start: start, count: count)
}
}
With these preparations above, you can access each CGPoint as:
let wrapper = YourClassWrapper()
let point = wrapper[0][1]
Or you can get the pointer to the first element in CGContour as:
let ptr = wrapper[0].baseAddress!
You may need to modify some parts to fit this into your actual code. Hope you can make it.

Related

Kotlin/Native to C dylib : How to access class members in a instance object which returned by a method?

I am trying to learn Kotlin/Native C interop
I exported some Kotlin classes as C dynamic Lib and succeeded in access methods with primitive return types
But When trying to access class members in a instance object which returned by a method, the object contains something named as pinned
Code sample:
#Serializable
data class Persons (
val results: Array<Result>,
val info: Info
)
class RandomUserApiJS {
fun getPersonsDirect() : Persons {
return runBlocking {
RandomUserApi().getPersons()
}
}
}
Now when using them in C codeblocks,
In this image, note that the persons obj only showing a field named pinned and no other member functions found.
Since I don't know that much in C/C++ and can't investigate further.
Please help me to understand to access instance members of Kotlin Class in exported C lib?
Header file for ref:
https://gist.github.com/RageshAntony/a0b9007376084fa8b213b022b58f9886
for your gist
https://gist.github.com/RageshAntony/a0b9007376084fa8b213b022b58f9886
I modified the following:
// I comment this annotation
// #Serializable
data class Persons(
val results: List<Result>,
val info: Info,
/**
* the Result's properties too many
* I will use a simple data class for this example
* how to get c array from Persons (also suitable any iterable)
*/
val testList: List<Simple>,
) {
public fun toJson() = Json.encodeToString(this)
companion object {
public fun fromJson(json: String) = Json.decodeFromString<Persons>(json)
}
val arena = Arena()
fun getTestListForC(size: CPointer<IntVar>): CPointer<COpaquePointerVar> {
size.pointed.value = testList.size
return arena.allocArray<COpaquePointerVar>(testList.size) {
this.value = StableRef.create(testList[it]).asCPointer()
}
}
fun free() {
arena.clear()
}
}
/**
* kotlin <-> c bridge is primitive type
* like int <-> Int
* like char* <-> String
* so the Simple class has two primitive properties
*/
data class Simple(
val name: String,
val age: Int,
)
#include <stdio.h>
#include "libnative_api.h"
int main(int argc, char **argv) {
libnative_ExportedSymbols* lib = libnative_symbols();
libnative_kref_MathNative mn = lib->kotlin.root.MathNative.MathNative();
const char *a = lib->kotlin.root.MathNative.mul(mn,5,6); // working
printf ("Math Resullt %s\n",a);
libnative_kref_RandomUserApiJS pr = lib->kotlin.root.RandomUserApiJS.RandomUserApiJS();
libnative_kref_Persons persons = lib->kotlin.root.RandomUserApiJS.getPersonsDirect(pr);
// when accessing above persons obj, only a field 'pinned' availabe, nothing else
int size;
libnative_kref_Simple* list = (libnative_kref_Simple *)lib->kotlin.root.Persons.getTestListForC(persons, &size);
printf("size = %d\n", size);
for (int i = 0; i < size; ++i) {
const char *name = lib->kotlin.root.Simple.get_name(list[i]);
int age = lib->kotlin.root.Simple.get_age(list[i]);
printf("%s\t%d\n", name, age);
}
lib->kotlin.root.Persons.free(persons);
return 0;
}
// for output
Math Resullt The answer is 30
size = 3
name1 1
name2 2
name3 3
But I don't think calling kotlin lib through C is a good behavior, because kotlin native is not focused on improving performance for now, in my opinion, all functions that can be implemented with kotlin native can find solutions implemented in pure c, So I'm more focused on how to access the c lib from kotlin. Of course, it's a good solution if you absolutely need to access klib from c, but I'm still not very satisfied with it, then I may create a github template to better solve kotlin-interop from c.But that's not the point of this answer.

Creating a FIFO fixed size array in Swift

I'm attempting to create a FIFO array in swift. I want to create something that acts like this:
var Arr = FixedFIFOArray<Int>(maxSize:3)
Arr.append(1) //Arr = [1]
Arr.append(2) //Arr = [1,2]
Arr.append(3) //Arr = [1,2,3]
Arr.append(4) //Arr = [2,3,4] <- the max size is fixed to 3, so any
additional values added remove old values
Other than this behavior, it should act like an array: allow slicing, indexing, iterating in for loops, etc.
In any other language, this would be a job for subclassing. We aren't changing much, just adding an initializer and amending a function or two. However, in Swift, we can't subclass array. What is the best way to do this? Do I need to implement every protocol that array implements, and just pass the associated functions off to an array? Something like this:
struct FixedFIFOArray<T> {
var _maxSize: Int
var _array: [T] = []
init(maxSize: Int) {
self._maxSize = maxSize
}
}
extension FixedFIFOArray : Collection {
//...
}
extension FixedFIFOArray : RandomAccessCollection {
//...
}
extension FixedFIFOArray : Sequence {
//...
}
// etc...
This seems like a lot of work to do something so simple. What am I missing?
It is not as bad as it seems, because many protocol requirements have
default implementations.
Unfortunately I do not have the perfect recipe to find a "minimal" implementation.
Some information can be found in the
RandomAccessCollection documentation
where some methods are marked as "Required. Default implementation provided."
You can also start with an empty implementation extension FixedFIFOArray : RandomAccessCollection {} and study the error messages or try the Fix-its.
With "Jump to Definiton" in the Xcode editor one can inspect the protocol definitions and extension methods.
In your case it turned out that it suffices to implement
startIndex, endIndex, and subscript:
extension FixedFIFOArray : RandomAccessCollection {
var startIndex: Int {
return _array.startIndex
}
var endIndex: Int {
return _array.endIndex
}
subscript(i: Int) -> T {
return _array[i]
}
}
Or, if you need a read-write subscript:
subscript(i: Int) -> T {
get {
return _array[i]
}
set {
_array[i] = newValue
}
}

Map modify array of objects in Swift 2.2 (3.0)

I want to be able to modify my array of objects using map in Swift of the fly, without looping through each element.
Before here were able to do something like this (Described in more details here:
gnomes = gnomes.map { (var gnome: Gnome) -> Gnome in
gnome.age = 140
return gnome
}
Thanks for Erica Sadun and others, new proposals have gone through and we're now getting rid of C-style loops and using var inside the loop.
In my case I'm first getting a warning to remove the var in then an error my gnome is a constant (naturally)
My question is : How do we alter arrays inside a map or the new styled loops for that matter to be fully prepared for Swift 3.0?
If you want to keep that syntax, just use a (mutable) temporary variable
gnomes = gnomes.map { (gnome: Gnome) -> Gnome in
var mutableGnome = gnome
mutableGnome.age = 140
return mutableGnome
}
(Below follows the case where Gnome is a reference type; a class -- since you haven't showed us how you've defined Gnome. For the case where Gnome as value type (a struct), see #vadian:s answer)
The removal of var will not effect using .map to mutate mutable members of an array of reference type objects. I.e., you could simply use your old approach (omitting however, the var in the .map closure signature).
class Gnome {
var age = 42
}
var gnomes = [Gnome(), Gnome(), Gnome()]
gnomes = gnomes.map {
$0.age = 150
return $0
}
/* result */
gnomes.forEach { print($0.age) } // 3x 150
However, in case you just want to modify your original array rather than assigning the result of .map to a new array, .forEach might be a more appropriate choice than .map.
gnomes.forEach { $0.age = 140 }
/* result */
gnomes.forEach { print($0.age) } // 3x 140
Given:
struct Gnome {
var age: Int = 0
}
var gnomes = Array(count: 5, repeatedValue: Gnome())
... there are two decent options. The first is as #vadian put it:
gnomes = gnomes.map{
var gnome = $0
gnome.age = 70
return gnome
}
Whilst the second keeps control over "ageing" private and simplifies mapping at the point of call:
struct Gnome {
private(set) var age: Int = 0
func aged(age: Int) -> Gnome {
var gnome = self
gnome.age = age
// any other ageing related changes
return gnome
}
}
gnomes = gnomes.map{ $0.aged(140) }
Of course, reference types still have their place in programming, which may well be a better fit in this case. The friction we are experiencing here suggests that we are trying to treat these structures as if they were objects. If that is the behaviour you need, then you should consider implementing Gnome as a class.

How do I access an array from one file in another file?

I am really new to Xcode. I don't quite understand exactly what it means when you initialize variables in certain places, but my code works so this isn't the issue... for now. Anyway, here is a my .h file. Everywhere there is a "----" it just means there is code there.
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
NSInteger charactersLocked[3] = {0,0,1};
int charSel = 0;
#interface Tutorial : UIViewController
{
-------
}
------
#end
So I need to access the array charactersLocked in a different .m file, lets call it File2 and this one File1. When I try to #import "File1.h" in File2.m, the program crashes and gives me this error for both charactersLocked and charSel:
duplicate symbol _charactersLocked in:
/Users/me/Library/Developer/Xcode/DerivedData/SpaceRace-
apawbkpiogvbvddranqfltyybuqr/Build/Intermediates/SpaceRace.build/Debug-
iphoneos/SpaceRace.build/Objects-normal/arm64/Tutorial.o
/Users/me/Library/Developer/Xcode/DerivedData/SpaceRace
apawbkpiogvbvddranqfltyybuqr/Build/Intermediates/SpaceRace.build/Debug-
iphoneos/SpaceRace.build/Objects-normal/arm64/Space.o
I have no idea what this is. I've tried looking for solutions online, but none of them seem to work. I am not importing the .m file by accident. If there is an easier way to just get access to that specific array, please let me know. Sorry if this post was formatted horribly, it is my first time so bear with me. Thank you.
The short answer to your question is located in this answer; you need to declare your variables as extern for the compiler to know that you want to use it in multiple files.
This is very rarely done in Objective-C though, because its heritage as an object-oriented programming language means that global state in programs is most often handled in class methods or singleton classes. Without knowing too much about your program, I am going to guess that you want a singleton class, something like CharacterLocker, which would look like this:
CharacterLocker.h
#interface CharacterLocker : NSObject
{
NSInteger charactersLocked[3];
}
+ (id) sharedObject;
#property NSInteger* charactersLocked;
#end
CharacterLocker.m
#implementation CharacterLocker
#synthesize charactersLocked;
+ (void) sharedObject
{
static CharacterLocker *singleton = nil;
// Required so that multiple calls to sharedObject don't create two
static dispatch_once_t pred;
dispatch_once(&pred, ^{ singleton = [[CharacterLocker alloc] init]; });
return singleton;
}
- (id) init
{
if ( self = [super init] )
{
charactersLocked[0] = 0;
charactersLocked[1] = 0;
charactersLocked[2] = 1;
}
return self;
}
#end
Then, in your code, you call [CharacterLocker sharedObject].charactersLocked to access the array.

Printing element of 2d array in swift

I'm attempting to customize the "Page-Based Application" template and am new to Swift (and all programming for that matter). In my ModelController.swift I've created a 2D array to use as the primary datasource.
However, when I go to print it or use it as label.text it is including the parenthesis. How do I get just the strings of the array element I'm calling for?
class ModelController: NSObject, UIPageViewControllerDataSource {
var pageData: NSArray = [[String]]()
override init() {
super.init()
// Create the data model.
pageData = [["right", "wrong"], ["left", "right"]]
println(pageData[1]) //For
}
I'm not sure what else from this file is relevant but here's another bit.
func indexOfViewController(viewController: DataViewController) -> Int {
// Return the index of the given data view controller.
// For simplicity, this implementation uses a static array of model objects and the view controller stores the model object; you can therefore use the model object to identify the index.
if let dataObject: AnyObject = viewController.dataObject {
return self.pageData.indexOfObject(dataObject)
} else {
return NSNotFound
}
}
If you just want left, right
println("\(pageData[1][0]), \(pageData[1][1])")
If you literally want "left, right" with the double quotes included it's
println("\"\(pageData[1][0]), \(pageData[1][1])\"")
The reason you got the results you did is because pageData[1] isn't a String it's an NSArray. Because NSArray conforms to the Printable protocol it supplies its .description when used in println.

Resources