sizeof() in RubyMotion

203 views
Skip to first unread message

Matthew Nguyen

unread,
Jul 18, 2012, 4:26:57 PM7/18/12
to rubym...@googlegroups.com
Hi, I'm stuck when converting Obj-C code using sizeof() into RubyMotion.

For instance:

CTTextAlignment theAlignment = kCTCenterTextAlignment;
CFIndex theNumberOfSettings = 1;
CTParagraphStyleSetting theSettings[1] = {{ kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &theAlignment }};
CTParagraphStyleRef theParagraphRef = CTParagraphStyleCreate(theSettings, theNumberOfSettings);

How should I translate: sizeof(CTTextAlignment) ?

Thank you.

Matthew Nguyen

John Labovitz

unread,
Jul 18, 2012, 5:22:21 PM7/18/12
to rubym...@googlegroups.com
A short answer: it's defined as uint8_t, which is one byte, so you can just pass 1 for the value.

I feel there's a better way to do this (e.g., NSGetSizeAndAlignment), but maybe not for simple typedef'ed enums like this.

--John
> --
>
>
>

Matthew Nguyen

unread,
Jul 19, 2012, 8:25:12 AM7/19/12
to rubym...@googlegroups.com
Thanks for your answer.

So basically, I have to directly write the value of sizeof() in hard?
No other better way?

(The code in the first post was a mere sample of code, I have plenty of other situations where sizeof() is required)

John Labovitz

unread,
Jul 19, 2012, 3:00:05 PM7/19/12
to rubym...@googlegroups.com
I had some time this morning, so poked around at this for a while. Here's what I found. Note that I'm by no means an expert on any of this; I'm just playing detective.

Let's start with the declaration of CTTextAlignment, from Apple's docs:

enum{
kCTLeftTextAlignment = 0,
kCTRightTextAlignment = 1,
kCTCenterTextAlignment = 2,
kCTJustifiedTextAlignment = 3,
kCTNaturalTextAlignment = 4
};
typedef uint8_t CTTextAlignment;

A C enum type is, by definition, equivalent in size to an "int", however the compiler wants to define that; in other words, "sizeof(kCTLeftTextAlignment) == sizeof(int)". It seems that in Ruby (i.e., MacRuby or RubyMotion), an enum's values are converted to instances of the Fixnum class. So kCTLeftTextAlignment, etc., are accessible as Fixnum constants (capitalized). This is totally unrelated (to the compiler) to the typedef line that follows it, above.

The CTTextAlignment typedef seems to be ignored by Ruby (i.e., MacRuby/RubyMotion). It's not defined as any sort of object or class I can find. It's referenced in the CoreText.bridgesupport file [1] only when a function using that enum is declared; for example:

<function name='CTTextTabCreate'>
<arg type='C' declared_type='CTTextAlignment' name='alignment'/>
<arg type='d' declared_type='double' name='location'/>
<arg type='^{__CFDictionary=}' declared_type='CFDictionaryRef' name='options'/>
<retval type='^{__CTTextTab=}' already_retained='true' declared_type='CTTextTabRef'/>
</function>

That first argument indirectly describes the type of CTTextAlignment. According to Apple's docs [1], 'C' means "unsigned char", which is what "uint8_t" is actually typedef'ed to. However, I don't know how to get at the bridgesupport data programmatically, and anyway, that's not the function you're trying to call.

CTParagraphStyleCreate() is a lot slipperier. Here's the declaration:

<function name='CTParagraphStyleCreate'>
<arg const='true' type='^{CTParagraphStyleSetting=II^v}' declared_type='CTParagraphStyleSetting*' name='settings'/>
<arg type='l' declared_type='CFIndex' name='settingCount'/>
<retval type='^{__CTParagraphStyle=}' already_retained='true' declared_type='CTParagraphStyleRef'/>
</function>

The function itself is relatively straightforward, but the definition of CTParagraphStyleSetting is not. That 'II^v' means "int, int, void *". The "void *" is really the problem here: by effectively throwing away the type, CTParagraphStyleSetting() is not exposing enough information to the bridging system to be able to understand what it's needing here.

So in short, the only answer to your question is found in the documentation and header files (and the source to CTParagraphStyleSetting(), of course).

I think I'd solve this problem by finding the gray areas like CTParagraphStyleSetting, determining the sizes based on the docs/headers, and just defining those as constants (or a hash of values). (It may be possible to convert an encoding type like 'C' to a byte-length programmatically, like the standard Ruby pack/unpack methods, but I haven't figured out a way to do.)

Then your code could be written in Ruby like this (I hate that "theVariable" style Apple uses, so I've renamed the variables):

CTTextAlignmentSize = 1

alignmentPtr = Pointer.new(:int)
alignmentPtr[0] = KCTCenterTextAlignment
setting = CTParagraphStyleSetting.new(KCTParagraphStyleSpecifierAlignment, CTTextAlignmentSize, alignmentPtr)
settingsPtr = Pointer.new(CTParagraphStyleSetting.type)
settingsPtr[0] = setting
paragraphRef = CTParagraphStyleCreate(settingsPtr, 1)

Hope this helps! It certainly helped me. ;-)

--John


1. /Library/RubyMotion/data/5.1/BridgeSupport/CoreText.bridgesupport
2. http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html)
> --
>
>
>

John Labovitz

unread,
Jul 19, 2012, 3:42:01 PM7/19/12
to rubym...@googlegroups.com
I had a bit of a brain-flash while away from the computer, and came up with a less hacky way to do this.

See code at:

https://gist.github.com/3146276

Given this code, it's fairly easy to define new subclasses of Enum as needed, as long as you know the encoding type (eg, 'C' = uint8_t). Then you can call #new to create a new enum with a specific value, #pointer to get a pointer to that enum, and #size to get the sizeof() equivalent.

Thoughts?

--John

Matthew Nguyen

unread,
Jul 20, 2012, 5:39:26 PM7/20/12
to rubym...@googlegroups.com
Hi John!

I didn't know NSGetSizeAndAlignment function!

You code didn't work for me but I changed it a bit and it seems to work fine:

def sizeof(type)
  size_ptr = Pointer.new(:uint)
  align_ptr = Pointer.new(:uint)
  NSGetSizeAndAlignment(type, size_ptr, align_ptr)
  size_ptr[0]
end

sizeof(CTParagraphStyleSetting.type) # => 12
sizeof(CGRect.type) # => 16
sizeof(:float) # => 4

Thank you very much for your help!!

Matthew Nguyen

John Labovitz

unread,
Jul 20, 2012, 5:50:55 PM7/20/12
to rubym...@googlegroups.com
That's a nice solution, too.

The code I posted before definitely worked -- but under MacRuby. Maybe there are some differences with RubyMotion.

--John
> --
>
>
>

Reply all
Reply to author
Forward
0 new messages