[MacRuby-devel] Pointer to an array of structs?

John Labovitz johnl at johnlabovitz.com
Wed Apr 24 11:19:13 PDT 2013


I just spent a couple of days on figuring out how to properly get a pointer to an array of C-structs. I finally figured it out, but it seems like more work than necessary, and I'm wondering what other folks think.

I'm using Harfbuzz, a C library, to do some OpenType text shaping & positioning -- that is, converting a Unicode string, plus a given font, to a sequence of glyphs with positions. In this specific code, I'm trying to convert an array of Ruby strings to 'features,' which are represented in Harfbuzz by the 'hb_feature_t' struct. The function hb_feature_from_string() handles the conversion, but needs a pointer to a pre-allocated 'hb_feature_t' struct. The set of features needs to be stored as an array of contiguous structs, which is then passed into the shaping function hb_shape().

Here are the definitions from the .h files:

	typedef struct hb_feature_t {
	  hb_tag_t      tag;
	  uint32_t      value;
	  unsigned int  start;
	  unsigned int  end;
	} hb_feature_t;

	hb_feature_from_string (const char *str, 
		int len, 
		hb_feature_t *feature);

	hb_shape (hb_font_t           *font,
		  hb_buffer_t         *buffer,
		  const hb_feature_t  *features,
		  unsigned int         num_features);

I've built a small framework with the Harfbuzz library and the BridgeSupport file that resulted from running gen_bridge_metadata on those .h files.

Here are excerpts from my current working MacRuby code.

	feature_strings = %w{dlig kern}
        features = feature_strings.map do |feature_string|
          feature = Pointer.new('{hb_feature_t=IIII}')
          hb_feature_from_string(feature_string, -1, feature)
          feature.value
        end
        features_ptr = Pointer.new_with_type('^{hb_feature_t=IIII}')
        features_ptr.assign(features)
        @features = features_ptr.value
        @num_features = features.length
	# ...later on...
	hb_shape_full(@font.hb_font, buffer, @features, @num_features)

In my first attempts, I tried to allocated a single Pointer object that would contain all the features, and then call hb_feature_from_string() with each element in turn, like this:

	@features = Pointer.new('{hb_feature_t=IIII}', feature_strings.length)
        feature_strings.each_with_index do |feature_string, i|
          hb_feature_from_string(feature_string, -1, @features[i])
        end
	@num_features = feature_strings.length

The code ran, but the '@features' pointer remained in the initialized state -- that is, all the values were 0. I tried this in several different ways, and no matter what, the values were never set. This seems like a potential bug.

(It also seems odd to need to specify the exact members of the type -- the '=IIII' part -- but MacRuby complained mightily when I removed that part.)

Can some Pointer guru take a look at the above and give me a reality check? Is the way I'm doing it just the way it must be done? Or should the second method, with the single Pointer object, actually work?

Best,
--John


More information about the MacRuby-devel mailing list