Self referential Structs are possible in objective C. Eg:
typedef struct Sample {
struct Sample* first;
struct Sample* second;
struct Sample* third;
} SampleStruct;
The swift conversion looks something like
struct Sample {
var first: Sample?
var second: Sample?
var third: Sample?
}
typealias SampleStruct = Sample
But it throws a compiler error saying "Value type 'Sample' cannot have a stored property that references itself".
How do i convert the self referential struct to swift?
You know you cannot define this sort of struct in Objective-C.
typedef struct Sample {
struct Sample first;
struct Sample second;
struct Sample third;
} SampleStruct;
(Swift adds a hidden isNil... field for each Optional, but it's not a big difference.)
If you want to define an exact equivalent to your Objective-C code, you need to use pointers, as in the original code.
struct Sample {
var first: UnsafeMutablePointer<Sample>?
var second: UnsafeMutablePointer<Sample>?
var third: UnsafeMutablePointer<Sample>?
}
Better consider using class as commented.
Related
In Kotlin/Native, what is the correct way to create and initialize an array of a structure? My code interfaces with a C library that defines the relevant structures as:
typedef struct VkDeviceQueueCreateInfo {
...
} VkDeviceQueueCreateInfo;
typedef struct VkDeviceCreateInfo {
...
uint32_t queueCreateInfoCount;
const VkDeviceQueueCreateInfo* pQueueCreateInfos;
...
} VkDeviceCreateInfo;
I've created wrapper classes DeviceQueueCreateInfo and DeviceCreateInfo. The Kotlin bindings are generated as classes inheriting from CStructVar and used like this:
class DeviceQueueCreateInfo(...) {
// Allocates in `scope` and fills a `VkDeviceQueueCreateInfo`
fun toRaw(scope: MemScope): VkDeviceQueueCreateInfo = ...
}
class DeviceCreateInfo(val queueCreateInfos: List<DeviceQueueCreateInfo>) {
// Allocates in `scope` and fills a `VkDeviceCreateInfo`
fun toRaw(scope: MemScope) = with(scope) {
alloc<VkDeviceCreateInfo>().also {
it.queueCreateInfoCount = queueCreateInfos.size.toUInt()
it.pQueueCreateInfos = ??? // Allocate array of struct in `scope`
}
}
}
I've added a ??? to the code to show where I'm having trouble. Kotlin NativePlacement has allocArray<T>(length: Int), so that was obviously my first stop:
it.pQueueCreateInfos = allocArray(queueCreateInfos.size)
And then to initialize them I tried:
it.pQueueCreateInfos = allocArray<VkDeviceQueueCreateInfo>(queueCreateInfos.size)
.also { arr ->
queueCreateInfos.forEachIndexed { index, x -> arr[index] = x.toRaw(scope) }
}
However, this fails to compile with error No set method providing array access at arr[index] = x. I wrote the following code which compiles and runs as expected:
val floats = listOf(1f, 2f, 3f)
allocArray<FloatVar>(floats.size).also { arr ->
floats.forEachIndexed { index, x -> arr[index] = x }
}
The code is identical apart from the type used, leading me to believe that I was perhaps trying to assign to an rvalue. I went looking for VkDeviceQueueCreateInfoVar only to find this:
Also, any C type has the Kotlin type representing the lvalue of this type, i.e., the value located in memory rather than a simple immutable self-contained value. Think C++ references, as a similar concept. For structs (and typedefs to structs) this representation is the main one and has the same name as the struct itself, for Kotlin enums it is named ${type}Var, for CPointer it is CPointerVar, and for most other types it is ${type}Var.
This states that for structs, the lvalue representation has the same name as the struct (no Var suffix)... so VkDeviceQueueCreateInfo should represent an assignable lvalue, and I'm confused as to why I am unable to assign values to my array. It occurs to me that Kotlin's assignment does something very different to a C assignment, but I had assumed there would be an idiomatic way to perform a structure assignment.
I've looked through the other overloads and methods in NativePlacement to find one that allows me to initialize the values in the newly created array, and I found allocArray<T>(length: Long, initializer: T.(index: Long)->Unit), but this seems to suffer from the same problem.
How do I allocate and initialize an array of structures through cinterop?
I am writing an OS X/iOS framework in Objective-C, and I would like for the framework to be useful for developers using either Objective-C or Swift.
In normal Objective-C enums are defined like this (this example is taken directly from Apple's own UIView class reference).
typedef enum {
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear
} UIViewAnimationCurve;
To make this enum Swift-friendly, my understanding is that it should be declared like this.
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurve_EaseInOut,
UIViewAnimationCurve_EaseIn,
UIViewAnimationCurve_EaseOut,
UIViewAnimationCurve_Linear
};
This allows the enum to be accessed in the style of let curve: UIViewAnimationCurve = .EaseInOut from Swift.
My problem is that the NS_ENUM and underscore method produces strangely named enums when used from Objective-C. The NS_ENUM method allows dot notation to be used from Swift, but it also means that any ObjC code will need to use an underscore in the enumerated name, which is undesirable.
How can I allow dot notation for Swift while still preserving Objective-C style naming conventions for within ObjC code?
You simply follow the usual convention – no underscoring is necessary. Swift compiler is smart enough to just cut the common prefix out (the part that matches the enum type name). You do have to use an NS_ENUM for the enum to be made visible to Swift, but it's good practice anyway.
Case in point, for instance UIViewAnimationCurve is defined in an Objective-C header in just the form you describe in your first code example and works just fine in Swift:
If you define it like this:
typedef long TrafficLightColor NS_TYPED_ENUM;
TrafficLightColor const TrafficLightColorRed;
TrafficLightColor const TrafficLightColorYellow;
TrafficLightColor const TrafficLightColorGreen;
if get compiled to swift like this:
struct TrafficLightColor: RawRepresentable, Equatable, Hashable {
typealias RawValue = Int
init(rawValue: RawValue)
var rawValue: RawValue { get }
static var red: TrafficLightColor { get }
static var yellow: TrafficLightColor { get }
static var green: TrafficLightColor { get }
}
Looks like what you need, anyway take a look at: https://itunes.apple.com/us/book/using-swift-with-cocoa-and-objective-c-swift-4-1-beta/id1002624212?mt=11
I am in the process of porting an application from (Objective-)C to Swift but have to use a third-party framework written in C. There are a couple of incompatibilities like typedefs that are interpreted as Int but have to be passed to the framework's functions as UInts or the like. So to avoid constant casting operations throughout the entire Swift application I decided to transfer the C header files to Swift, having all types as I I need them to be in one place.
I was able to transfer nearly everything and have overcome a lot of hurdles, but this one:
The C header defines a struct which contains a uint64_t variable among others. This struct is used to transfer data to a callback function as a pointer. The callback function takes a void pointer as argument and I have to cast it with the UnsafeMutablePointer operation to the type of the struct (or another struct of the header if appropriate). All the casting and memory-accessing works fine as long as I use the original struct from the C header that was automatically transformed by Swift on import.
Replicating the struct manually in Swift does not "byte-fit" however.
Let me show you a reduced example of this situation:
Inside the CApiHeader.h file there is something like
typedef struct{
uint32_t var01;
uint64_t var02;
uint8_t arr[2];
}MyStruct, *MyStructPtr;
From my understanding this here should be the Swift equivalent
struct MyStruct{
var01: UInt32
var02: UInt64
arr: (UInt8, UInt8)
}
Or what should also work is this tuple notation
typealias MyStruct = (
var01: UInt32,
var02: UInt64,
arr: (UInt8, UInt8)
)
This works normally, but not as soon as there is an UInt64 type.
Okay, so what happens?
Casting the pointer to one of my own Swift MyStruct implementations the hole data is shifted by 2 bytes, starting at the UInt64 field. So in this example the both arr fields are not at the correct position, but inside the UInt64 bits, that should be 64 in number. So it seams that the UInt64 field has only 48 bits.
This accords to my observation that if I replace the UIn64 variable with this alternative
struct MyStruct{
var01: UInt32
reserved: UInt16
var02: UInt32
arr: (UInt8, UInt8)
}
or this one
struct MyStruct{
var01: UInt32
var02: (UInt32, UInt32)
arr: (UInt8, UInt8)
}
(or the equivalent tuple notation) it aligns the arr fields correctly.
But as you can easily guess var02 contains not directly usable data, because it is split over multiple address ranges. It is even worse with the first alternative, because it seams that Swift fills up the gap between the reserved field and the var02 field with 16 bits - the missing / shifted 2 bytes I mentioned above - but these are not easily accessible.
So I haven't figured out any equivalent transformation of the C struct in Swift.
What happens here exactly and how does Swift transforms the struct from the C header actually?
Do you guys have a hint or an explanation or even a solution for me, please?
Update
The C framework has an API function with this signature:
int16_t setHandlers(MessageHandlerProc messageHandler);
MessageHandlerProc is procedure type:
typedef void (*messageHandlerProc)(unsigned int id, unsigned int messageType, void *messageArgument);
So setHandlers is a C procedure inside the framework that gets a pointer to a callback function. This callback function has to provide an argument of a void Pointer, that gets casted to e.g.
typedef struct {
uint16_t revision;
uint16_t client;
uint16_t cmd;
int16_t parameter;
int32_t value;
uint64_t time;
uint8_t stats[8];
uint16_t compoundValueOld;
int16_t axis[6];
uint16_t address;
uint32_t compoundValueNew;
} DeviceState, *DeviceStatePtr;
Swift is smart enough to import the messageHandlerProc with the convention(c) syntax, so the procedure type is directly available. On the other hand it is not possible use the standard func syntax and bitcast my messageHandler callback function to this type. So I used the closure syntax to define the callback function:
let myMessageHandler : MessageHandlerProc = { (deviceID : UInt32, msgType : UInt32, var msgArgPtr : UnsafeMutablePointer<Void>) -> Void in
...
}
I converted the above mentioned structure into the different structures of my original post.
And No! Defining stats as Swift Array does not work. An Array in Swift in not equivalent to an Array in C, because Swift's Array is a extended type. Writing to and reading from it with a pointer causes an exception
Only Tuples are natively implemented in Swift and you can run back and forth with pointers over it.
Okay... this works all fine and my callback function gets called whenever data is available.
So inside myMessageHandler I want to use the stored Data inside msgArgPtr which is a void pointer and thus has to be cast into DeviceState.
let state = (UnsafeMutablePointer<MyDeviceState>(msgArgPtr)).memory
Accessing state it like:
...
print(state.time)
print(state.stats.0)
...
Whenever I use the automatically generated Swift pendant of DeviceState it all works nicely. The time variable has the Unix Time Stamp and the following stats (accessible with tuple syntax!!!) are all where they belong.
Using my manually implemented struct however results in a completely senseless time stamp value and the stats fields are shifted to the left (towards the time field - that's probably why the time stamp value is useless, because it contains bits from the stats "array"). So in the last two fields of stats I get values from compoundValueOld and the first axis field - with all the overflowing of course.
As long as I am willing to sacrifice the time value and change the UInt64 variable by either a tuple of two UInt32 types or by changing it to a UInt32 type and adding a auxiliary variable of the type UInt16 right before time, I receive a stats "array" with correct alignment.
Have a nice day! :-)
Martin
This is an update to my earlier answer after reading your updated question and experimenting some more. I believe the problem is an alignment discrepancy between the imported C structure and the one you manually implemented in Swift. The problem can be solved by using a C helper function to get an instance of the C struct from void pointer as was suggested yesterday, which can then be converted to the manually implemented Swift struct.
I've been able to reproduce the problem after creating an abbreviated mock-up of your DeviceState structure that looks like
typedef struct
{
uint16_t revision;
uint16_t client;
uint16_t cmd;
int16_t parameter;
int32_t value;
uint64_t time;
uint8_t stats[8];
uint16_t compoundValueOld;
} APIStruct;
The corresponding hand-crafted Swift native structure is:
struct MyStruct
{
init( _apis : APIStruct)
{
revision = _apis.revision
client = _apis.client
cmd = _apis.cmd
parameter = _apis.parameter
value = _apis.value
time = _apis.time
stats = _apis.stats
compoundValueOld = _apis.compoundValueOld
}
var revision : UInt16
var client : UInt16
var cmd : UInt16
var parameter : Int16
var value : Int32
var time : UInt64
var stats : (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8);
var compoundValueOld : UInt16
}
The C framework you are working with could have been compiled using a different struct packing, resulting in a non-matching alignment. I used
#pragma pack(2)
in my C code to break the bit-matching between the Swift's native and imported C struct.
If I do something like
func swiftCallBackVoid( p: UnsafeMutablePointer<Void> )
{
...
let _locMS:MyStruct = (UnsafeMutablePointer<MyStruct>(p)).memory
...
}
the data in _locMS is different from what was placed there by C code. This problem only occurs if I change struct packing using a pragma in my C code; the above unsafe conversion works fine if the default alignment is used. One can solve this problem as follows:
let _locMS:MyStruct = MyStruct(_apis: (UnsafeMutablePointer<APIStruct>(p)).memory)
BTW, the way Swift imports the C struct, the array members become tuples; this can be seen from the fact that tuple notation has to be used to access them in Swift.
I have a sample Xcode project illustrating all this that I've placed on github:
https://github.com/omniprog/xcode-samples
Obviously, the approach of using a helper C function to get APIStruct from a void pointer and then converting the APIStruct to MyStruct may or may not be an option, depending on how the structures are used, how large they are, and on the performance requirements of the application. As you can tell, this approach involves some copying of the structure. Other approaches, I think, include writing a C-layer between Swift code and the 3rd party C framework, studying the memory layout of the C structure and accessing it in creative ways (may break easily), using the imported C struct more extensively in your Swift code, etc...
Here is a way to share data between C and Swift code without unnecessary copying and with changes made in Swift visible to C code. With the following approach, however, it's imperative to be aware of object lifetime and other memory management issues. One can create a class as follows:
// This typealias isn't really necessary, just a convenience
typealias APIStructPtr = UnsafeMutablePointer<APIStruct>
struct MyStructUnsafe
{
init( _p : APIStructPtr )
{
pAPIStruct = _p
}
var time: UInt64 {
get {
return pAPIStruct.memory.time
}
set( newVal ) {
pAPIStruct.memory.time = newVal
}
}
var pAPIStruct: APIStructPtr
}
Then we can use this structure as follows:
func swiftCallBackVoid( p: UnsafeMutablePointer<Void> )
{
...
var _myUnsafe : MyStructUnsafe = MyStructUnsafe(_p: APIStructPtr(p))
...
_myUnsafe.time = 9876543210 // this change is visible in C code!
...
}
Your two definitions are not equivalent. An array is not the same as a tuple. Your C struct gives 24 bytes (see this question as to why). The size in Swift differs depend on how you implement it:
struct MyStruct1 {
var var01: UInt32
var var02: UInt64
var arr: (UInt8, UInt8)
}
typealias MyStruct2 = (
var01: UInt32,
var02: UInt64,
arr: (UInt8, UInt8)
)
struct MyStruct3 {
var var01: UInt32
var var02: UInt64
var arr: [UInt8] = [0,0]
}
print(sizeof(MyStruct1)) // 18
print(sizeof(MyStruct2)) // 18
print(sizeof(MyStruct3)) // 24, match C's
This question already has answers here:
C Typedef and Struct Question
(5 answers)
Closed 8 years ago.
Theres some sample code I have been working with from the book "Learning Core Audio" like so..
typedef struct MySineWavePlayer
{
AudioUnit outputUnit;
double startingFrameCount;
} MySineWavePlayer;
Why is "MySineWavePlayer" in this code twice?
This is a common question which is answered by explaining the difference between using typedef when defining a struct and not using typedef.
The common idiom is using both: typedef struct X { int x; } X;
They are different definitions. To make the discussion clearer I will split the sentence:
struct S { int x; };
typedef struct S S;
In the first line you are defining the identifier S within the struct name space (not in the C++ sense). You can use it and define variables or function arguments of the newly defined type by defining the type of the argument as struct S:
void f( struct S argument ); // struct is required here
The second line adds a type alias S in the global name space and thus allows you to just write:
void f( S argument ); // struct keyword no longer needed
Note that since both identifier name spaces are different, defining S both in the structs and global spaces is not an error, as it is not redefining the same identifier, but rather creating a different identifier in a different place.
To make the difference clearer:
typedef struct S { int x; } T;
void S() {} // correct
//void T() {} // error: symbol T already defined as an alias to 'struct S'
You can define a function with the same name of the struct as the identifiers are kept in different spaces, but you cannot define a function with the same name as a typedef as those identifiers collide.
In C++, it is slightly different as the rules to locate a symbol have changed subtly. C++ still keeps the two different identifier spaces, but unlike in C, when you only define the symbol within the class identifier space, you are not required to provide the struct/class keyword:
// C++
struct S { int x; }; // S defined as a class
void f( S a ); // correct: struct is optional
What changes are the search rules, not where the identifiers are defined. The compiler will search the global identifier table and after S has not been found it will search for S within the class identifiers.
The code presented before behaves in the same way:
typedef struct S { int x; } T;
void S() {} // correct [*]
//void T() {} // error: symbol T already defined as an alias to 'struct S'
After the definition of the S function in the second line, the struct S cannot be resolved automatically by the compiler, and to create an object or define an argument of that type you must fall back to including the struct keyword:
// previous code here...
int main() {
S();
struct S s;
}
source
the first one is actually not needed in this case, the second one is for the typedef if you write this
struct MySineWavePlayer
{
AudioUnit outputUnit;
double startingFrameCount;
};
then you need to do something like this to declare an instance of struct
struct MySineWavePlayer mySineWavePlayer;
you can then do this
typedef struct MySineWavePlayer MySineWavePlayer;
and then the declaration would become
MySineWavePlayer mySineWavePlayer;
so the original one
typedef struct MySineWavePlayer
{
AudioUnit outputUnit;
double startingFrameCount;
} MySineWavePlayer;
is a combination if these.
And you could even do the typedef for an anonymous struct
typedef struct
{
AudioUnit outputUnit;
double startingFrameCount;
} MySineWavePlayer;
So short answer is first MySineWavePlayer is the name of the struct while the second is the name of the typedefd type.
Using Objective-C++, can I write a C++ IsObjectiveCClass<T> template metafunction such that IsObjectiveCClass<T>::value is true if and only if T is an Objective-C class?
Exactly what are ObjC classes from the viewpoint of the C / C++ subset of the language? When used in a C / C++ context, MyClass* pointers seem to behave like ordinary C pointers; does that mean that MyClass is also a C type?
Here is a simplistic solution that should work in most (if not all? Can anyone think of when this might fail?) cases (it uses clang 3.0 via xcode 4.2 - use typedefs instead of using aliases for earlier clang versions):
template<class T> struct IsObjectiveCClass
{
using yesT = char (&)[10];
using noT = char (&)[1];
static yesT choose(id);
static noT choose(...);
static T make();
enum { value = sizeof(choose(make())) == sizeof(yesT) };
};
You can read my most recent rant about ObjC++ in this question. Avoid it as much as you can possibly get away with. Definitely don't try to integrate Objective-C into C++ template metaprogramming. The compiler might actually rip a hole in space.
Hyperbole aside, what you're trying to do is likely impossible. Objective-C classes are just structs. (C++ classes actually just structs too.) There's not much compile-time introspection available.
An id is a C pointer to a struct objc_object. At runtime, every object is an id, no matter its class.
typedef struct objc_class *Class;
typedef struct objc_object {
Class isa;
} *id;
As with the accepted answer, you can test whether the type is convertible to id, in C++17:
template <typename T>
struct is_objc_ptr : std::integral_constant<bool,
std::is_convertible_v<T, id> && !std::is_null_pointer_v<T>> {};
template <typename T>
constexpr bool is_objc_ptr_v = is_objc_ptr<T>::value;
Testing:
static_assert(!is_objc_ptr_v<nullptr_t>);
static_assert(!is_objc_ptr_v<int>);
static_assert(!is_objc_ptr_v<char *>);
static_assert(is_objc_ptr_v<id>);
static_assert(is_objc_ptr_v<NSObject *>);
I don't know of a way to discover ObjC inheritance relationships at compile-time; in theory they're changeable at runtime so you would have to query the runtime.
If you look at the implementation of the C++ STL library in Xcode, you can follow the template specialization models of others like std::is_integral or std::is_floating_point:
template <class T> struct isObjcObject : public std::false_type { };
template <> struct isObjcObject<id> : public std::true_type { };
where std::false_type and std::true_type are defined in the <type_traits> header file.
If for whatever reason you don't have std::false_type and std::true_type (depending on your C++ version), you can define them yourself as such:
template<bool B> struct boolean_constant { static constexpr const bool value = B; };
template <class T> struct isObjcObject : public boolean_constant<false> { };
template <> struct isObjcObject<id> : public boolean_constant<true> { };
Note that you can also do this for Objective-C classes too:
template <class T> struct isObjcClass : public std::false_type { };
template <> struct isObjcClass<Class> : public std::true_type { };
I would create a template specialisation for 'id' and 'NSObject*', but you'll always be working against the language because the ObjC type system is not the C++ type system.
Similar to Doug's answer, but slightly simpler:
template<typename T>
inline constexpr bool is_objc_v = std::is_convertible_v<id,T>;
Checking that id is convertible to T – instead of the other way around – avoids false positives for C++ types which have a user-defined implicit conversion to an Obj-C type.