lulu 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Lulu
2
+
3
+ Lulu - A ruby gem for merging map markers by agglomerative clustering.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'lulu'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install lulu
18
+
19
+ ## Usage
20
+
21
+ require 'lulu'
22
+
23
+ # Make an empty marker list
24
+ list = Lulu::MarkerList.new
25
+
26
+ # Add some markers. It's list.add(x, y, size). The size is actually area.
27
+ 10000.times{ |n| list.add(Random.rand(1000), Random.rand(1000), Random.rand(100)) }
28
+
29
+ # Get the list length.
30
+ p list.length # Produces 10000
31
+
32
+ # Optionally set merge parameters. Marker calculations can assume circular or
33
+ # square markers, and a scale factor may be set. The scale factor is applied
34
+ # to marker radii so that the marker size exists in a different coordinate
35
+ # space from the inter-marker distances. This makes sense, for example, if
36
+ # the marker coordinates are pixels on a map. A pixel on the map represents
37
+ # distance, a pixel in a marker something else. Returns self.
38
+ list.set_info(:circle, 1)
39
+
40
+ # Merge the markers. Pairs that are merged are deleted and replaced by a
41
+ # fresh marker added to the list. If the original list has N, this can
42
+ # result in 2N-1 markers in the result. Subsequent merges will remove
43
+ # all deleted markers from previous merges. This is called compression.
44
+ # See below. Returns list.length.
45
+ list.merge
46
+
47
+ # Get the list length again. If markers were merged, the list grew.
48
+ p list.length # Produces 10415
49
+
50
+ # Squeeze out deleted markers, i.e. ones that have been merged to form
51
+ # new ones. All remaining nodes are marked :single (see method parts below)
52
+ # Returns list.length
53
+ list.compress
54
+
55
+ # Merge after compress is idempotent.
56
+ list.merge # doesn't change list
57
+
58
+ # Get the marker at index 1000. This is a list [x, y, size].
59
+ # If the index is out of range, nil is returned.
60
+ p list.marker(1000) # Produces [748.0, 187.0, 80.0]
61
+
62
+ # Get whether the marker at index 100 was deleted during a merge.
63
+ p list.deleted(100) # returns true
64
+
65
+ # Print the list of all undeleted markers
66
+ p list.markers # Produces [[601.0, 715.0, 38.0]...[647.3314285714285, 179.19619047619048, 1050.0]]
67
+
68
+ # Clear the list, returning it to the empty state. Returns self.
69
+ list.clear
70
+
71
+ # For a given marker index, get the two indices of the markers (its _parts_)
72
+ # that were merged to create it, if any.
73
+ list.parts(5324)
74
+ # For the marker with index 5324, returns
75
+ # [:root, i, j] if it is the undeleted result of a merge of markers i and j
76
+ # [:merge, i, j] if it is the subsequently deleted result of a merge of markers i and j
77
+ # [:single] if it is an undeleted original node
78
+ # [:leaf] if ti is a deleted original node
79
+ # nil if 5324 is out of range
80
+
81
+ The method `parts` is sufficient to walk the tree of all nodes formed by merging.
82
+ In this manner, a parallel array of attribute information can be merged to match
83
+ so that merged attributes are available for each `:root`.
84
+
85
+ ## Contributing
86
+
87
+ 1. Fork it ( http://github.com/<my-github-username>/lulu/fork )
88
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
89
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
90
+ 4. Push to the branch (`git push origin my-new-feature`)
91
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require 'rake/extensiontask'
4
+
5
+ RSpec::Core::RakeTask.new
6
+
7
+ # Rake compiler's standard doesn't match the Ruby Guides
8
+ # http://guides.rubygems.org/gems-with-extensions/. So we need this.
9
+ Rake::ExtensionTask.new do |ext|
10
+ ext.name = 'lulu'
11
+ ext.ext_dir = 'ext/lulu'
12
+ ext.lib_dir = 'lib/lulu'
13
+ end
14
+
15
+ task :default => :spec
16
+ task :test => :spec
data/ext/lulu/Makefile ADDED
@@ -0,0 +1,220 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ # V=0 quiet, V=1 verbose. other values don't work.
5
+ V = 0
6
+ Q1 = $(V:1=)
7
+ Q = $(Q1:0=@)
8
+ n=$(NULLCMD)
9
+ ECHO1 = $(V:1=@$n)
10
+ ECHO = $(ECHO1:0=@echo)
11
+
12
+ #### Start of system configuration section. ####
13
+
14
+ srcdir = .
15
+ topdir = /usr/local/rvm/rubies/ruby-1.9.3-p484/include/ruby-1.9.1
16
+ hdrdir = /usr/local/rvm/rubies/ruby-1.9.3-p484/include/ruby-1.9.1
17
+ arch_hdrdir = /usr/local/rvm/rubies/ruby-1.9.3-p484/include/ruby-1.9.1/$(arch)
18
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
19
+ prefix = $(DESTDIR)/usr/local/rvm/rubies/ruby-1.9.3-p484
20
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
21
+ exec_prefix = $(prefix)
22
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
23
+ sitehdrdir = $(rubyhdrdir)/site_ruby
24
+ rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
25
+ vendordir = $(rubylibprefix)/vendor_ruby
26
+ sitedir = $(rubylibprefix)/site_ruby
27
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
28
+ mandir = $(datarootdir)/man
29
+ localedir = $(datarootdir)/locale
30
+ libdir = $(exec_prefix)/lib
31
+ psdir = $(docdir)
32
+ pdfdir = $(docdir)
33
+ dvidir = $(docdir)
34
+ htmldir = $(docdir)
35
+ infodir = $(datarootdir)/info
36
+ docdir = $(datarootdir)/doc/$(PACKAGE)
37
+ oldincludedir = $(DESTDIR)/usr/include
38
+ includedir = $(prefix)/include
39
+ localstatedir = $(prefix)/var
40
+ sharedstatedir = $(prefix)/com
41
+ sysconfdir = $(prefix)/etc
42
+ datadir = $(datarootdir)
43
+ datarootdir = $(prefix)/share
44
+ libexecdir = $(exec_prefix)/libexec
45
+ sbindir = $(exec_prefix)/sbin
46
+ bindir = $(exec_prefix)/bin
47
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
48
+ archdir = $(rubylibdir)/$(arch)
49
+ sitelibdir = $(sitedir)/$(ruby_version)
50
+ sitearchdir = $(sitelibdir)/$(sitearch)
51
+ vendorlibdir = $(vendordir)/$(ruby_version)
52
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
53
+
54
+ NULLCMD = :
55
+
56
+ CC = /usr/local/opt/apple-gcc42/bin/gcc-4.2
57
+ CXX = g++
58
+ LIBRUBY = $(LIBRUBY_SO)
59
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
60
+ LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
61
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
62
+ empty =
63
+ OUTFLAG = -o $(empty)
64
+ COUTFLAG = -o $(empty)
65
+
66
+ RUBY_EXTCONF_H =
67
+ cflags = $(optflags) $(debugflags) $(warnflags)
68
+ optflags = -O3
69
+ debugflags = -ggdb
70
+ warnflags = -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration
71
+ CFLAGS = -fno-common $(cflags) -fno-common -pipe -std=c99 -Wno-declaration-after-statement $(ARCH_FLAG)
72
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
73
+ DEFS =
74
+ CPPFLAGS = -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags) -I/usr/local/opt/libyaml/include -I/usr/local/opt/readline/include -I/usr/local/opt/libksba/include -I/usr/local/opt/openssl/include
75
+ CXXFLAGS = $(CFLAGS) $(cxxflags)
76
+ ldflags = -L. -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib
77
+ dldflags = -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib
78
+ ARCH_FLAG =
79
+ DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
80
+ LDSHARED = $(CC) -dynamic -bundle
81
+ LDSHAREDXX = $(CXX) -dynamic -bundle
82
+ AR = ar
83
+ EXEEXT =
84
+
85
+ RUBY_BASE_NAME = ruby
86
+ RUBY_INSTALL_NAME = ruby
87
+ RUBY_SO_NAME = ruby.1.9.1
88
+ arch = x86_64-darwin13.0.0
89
+ sitearch = $(arch)
90
+ ruby_version = 1.9.1
91
+ ruby = /usr/local/rvm/rubies/ruby-1.9.3-p484/bin/ruby
92
+ RUBY = $(ruby)
93
+ RM = rm -f
94
+ RM_RF = $(RUBY) -run -e rm -- -rf
95
+ RMDIRS = rmdir -p
96
+ MAKEDIRS = mkdir -p
97
+ INSTALL = /usr/bin/install -c
98
+ INSTALL_PROG = $(INSTALL) -m 0755
99
+ INSTALL_DATA = $(INSTALL) -m 644
100
+ COPY = cp
101
+ TOUCH = exit >
102
+
103
+ #### End of system configuration section. ####
104
+
105
+ preload =
106
+
107
+ libpath = . $(libdir) /usr/local/opt/libyaml/lib /usr/local/opt/readline/lib /usr/local/opt/libksba/lib /usr/local/opt/openssl/lib
108
+ LIBPATH = -L. -L$(libdir) -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl/lib
109
+ DEFFILE =
110
+
111
+ CLEANFILES = mkmf.log
112
+ DISTCLEANFILES =
113
+ DISTCLEANDIRS =
114
+
115
+ extout =
116
+ extout_prefix =
117
+ target_prefix = /lulu
118
+ LOCAL_LIBS =
119
+ LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc
120
+ SRCS = lulu.c marker.c merger.c pq.c qt.c test.c utility.c
121
+ OBJS = lulu.o marker.o merger.o pq.o qt.o test.o utility.o
122
+ TARGET = lulu
123
+ TARGET_NAME = lulu
124
+ TARGET_ENTRY = Init_$(TARGET_NAME)
125
+ DLLIB = $(TARGET).bundle
126
+ EXTSTATIC =
127
+ STATIC_LIB =
128
+
129
+ BINDIR = $(bindir)
130
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
131
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
132
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
133
+ HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
134
+ ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
135
+
136
+ TARGET_SO = $(DLLIB)
137
+ CLEANLIBS = $(TARGET).bundle
138
+ CLEANOBJS = *.o *.bak
139
+
140
+ all: $(DLLIB)
141
+ static: $(STATIC_LIB)
142
+ .PHONY: all install static install-so install-rb
143
+ .PHONY: clean clean-so clean-rb
144
+
145
+ clean-static::
146
+ clean-rb-default::
147
+ clean-rb::
148
+ clean-so::
149
+ clean: clean-so clean-static clean-rb-default clean-rb
150
+ -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
151
+
152
+ distclean-rb-default::
153
+ distclean-rb::
154
+ distclean-so::
155
+ distclean: clean distclean-so distclean-rb-default distclean-rb
156
+ @-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
157
+ @-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
158
+ @-$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
159
+
160
+ realclean: distclean
161
+ install: install-so install-rb
162
+
163
+ install-so: $(RUBYARCHDIR)/$(DLLIB)
164
+ $(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
165
+ -$(Q)$(MAKEDIRS) $(@D)
166
+ $(INSTALL_PROG) $(DLLIB) $(@D)
167
+ clean-static::
168
+ -$(Q)$(RM) $(STATIC_LIB)
169
+ install-rb: pre-install-rb install-rb-default
170
+ install-rb-default: pre-install-rb-default
171
+ pre-install-rb: Makefile
172
+ pre-install-rb-default: Makefile
173
+ pre-install-rb-default:
174
+ $(ECHO) installing default lulu libraries
175
+ ./.RUBYARCHDIR.time:
176
+ $(Q) $(MAKEDIRS) $(RUBYARCHDIR)
177
+ $(Q) $(TOUCH) $@
178
+
179
+ site-install: site-install-so site-install-rb
180
+ site-install-so: install-so
181
+ site-install-rb: install-rb
182
+
183
+ .SUFFIXES: .c .m .cc .mm .cxx .cpp .C .o
184
+
185
+ .cc.o:
186
+ $(ECHO) compiling $(<)
187
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
188
+
189
+ .mm.o:
190
+ $(ECHO) compiling $(<)
191
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
192
+
193
+ .cxx.o:
194
+ $(ECHO) compiling $(<)
195
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
196
+
197
+ .cpp.o:
198
+ $(ECHO) compiling $(<)
199
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
200
+
201
+ .C.o:
202
+ $(ECHO) compiling $(<)
203
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
204
+
205
+ .c.o:
206
+ $(ECHO) compiling $(<)
207
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
208
+
209
+ .m.o:
210
+ $(ECHO) compiling $(<)
211
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
212
+
213
+ $(DLLIB): $(OBJS) Makefile
214
+ $(ECHO) linking shared-object lulu/$(DLLIB)
215
+ -$(Q)$(RM) $(@)
216
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
217
+
218
+
219
+
220
+ $(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ # Turn off warnings about declarations mixed with code.
4
+ $CFLAGS += ' -std=c99 -Wno-declaration-after-statement'
5
+
6
+ create_makefile('lulu/lulu')
data/ext/lulu/lulu.c ADDED
@@ -0,0 +1,271 @@
1
+ /*
2
+ ============================================================================
3
+ Name : lulu.c
4
+ Author : Eugene K. Ressler
5
+ Version : 0.1
6
+ Copyright : GPLv3
7
+ Description : The Lulu gem for merging map markers.
8
+ ============================================================================
9
+ */
10
+
11
+ #include <stdio.h>
12
+ #include <stdlib.h>
13
+ #include <string.h>
14
+ #include "ruby.h"
15
+ #include "utility.h"
16
+ #include "marker.h"
17
+ #include "merger.h"
18
+ #include "pq.h"
19
+ #include "qt.h"
20
+
21
+ static char EXT_VERSION[] = "0.1.2";
22
+
23
+ // -------- C marker list to be wrapped in a Ruby object -----------------------
24
+
25
+ typedef struct marker_list_s {
26
+ MARKER_INFO info[1];
27
+ MARKER *markers;
28
+ int size, max_size;
29
+ } MARKER_LIST;
30
+
31
+ #define MARKER_LIST_DECL(Name) MARKER_LIST Name[1]; init_marker_list(Name)
32
+ #define ml_set_marker_list_info(L, Kind, Scale) mr_info_set((L)->info, (Kind), (Scale))
33
+
34
+ void init_marker_list(MARKER_LIST *list) {
35
+ mr_info_init(list->info);
36
+ list->markers = NULL;
37
+ list->size = list->max_size = 0;
38
+ }
39
+
40
+ MARKER_LIST *new_marker_list(void) {
41
+ NewDecl(MARKER_LIST, list);
42
+ init_marker_list(list);
43
+ return list;
44
+ }
45
+
46
+ void clear_marker_list(MARKER_LIST *list) {
47
+ Free(list->markers);
48
+ init_marker_list(list);
49
+ }
50
+
51
+ void free_marker_list(MARKER_LIST *list) {
52
+ clear_marker_list(list);
53
+ Free(list);
54
+ }
55
+
56
+ void add_marker(MARKER_LIST *list, COORD x, COORD y, SIZE size) {
57
+ if (list->size >= list->max_size) {
58
+ list->max_size = 4 + 2 * list->max_size;
59
+ RenewArray(list->markers, list->max_size);
60
+ }
61
+ MARKER *marker = list->markers + list->size++;
62
+ mr_set(list->info, marker, x, y, size);
63
+ }
64
+
65
+ void ensure_headroom(MARKER_LIST *list) {
66
+ int needed_size = 2 * list->size - 1;
67
+ if (list->max_size < needed_size) {
68
+ list->max_size = needed_size;
69
+ RenewArray(list->markers, list->max_size);
70
+ }
71
+ }
72
+
73
+ void compress(MARKER_LIST *list) {
74
+ int dst = 0;
75
+ for (int src = 0; src < list->size; src++)
76
+ if (!mr_deleted_p(list->markers + src)) {
77
+ if (src != dst)
78
+ list->markers[dst] = list->markers[src];
79
+ mr_reset_parts(list->markers + dst);
80
+ dst++;
81
+ }
82
+ list->size = dst;
83
+ }
84
+
85
+ // -------- Ruby API implementation --------------------------------------------
86
+
87
+ static void rb_api_free_marker_list(void *list) {
88
+ free_marker_list(list);
89
+ }
90
+
91
+ static VALUE rb_api_new_marker_list(VALUE klass) {
92
+ MARKER_LIST *list = new_marker_list();
93
+ return Data_Wrap_Struct(klass, 0, rb_api_free_marker_list, list);
94
+ }
95
+
96
+ #define MARKER_LIST_FOR_VALUE_DECL(Var) MARKER_LIST *Var; Data_Get_Struct(Var ## _value, MARKER_LIST, Var)
97
+
98
+ static VALUE rb_api_initialize_copy(VALUE dst_value, VALUE src_value)
99
+ #define ARGC_initialize_copy 1
100
+ {
101
+ if (dst_value == src_value)
102
+ return src_value;
103
+
104
+ if (TYPE(src_value) != T_DATA || RDATA(src_value)->dfree != (RUBY_DATA_FUNC)rb_api_free_marker_list)
105
+ rb_raise(rb_eTypeError, "type mismatch (copy_marker_list)");
106
+
107
+ MARKER_LIST_FOR_VALUE_DECL(src);
108
+ MARKER_LIST_FOR_VALUE_DECL(dst);
109
+
110
+ // Shallow copy contents, then deep copy array of markers.
111
+ *dst = *src;
112
+ NewArray(dst->markers, dst->max_size);
113
+ CopyArray(dst->markers, src->markers, dst->max_size);
114
+
115
+ return dst_value;
116
+ }
117
+
118
+ static VALUE rb_api_clear(VALUE self_value)
119
+ #define ARGC_clear 0
120
+ {
121
+ MARKER_LIST_FOR_VALUE_DECL(self);
122
+ clear_marker_list(self);
123
+ return self_value;
124
+ }
125
+
126
+ static VALUE rb_api_set_info(VALUE self_value, VALUE kind_value, VALUE scale_value)
127
+ #define ARGC_set_info 2
128
+ {
129
+ MARKER_LIST_FOR_VALUE_DECL(self);
130
+
131
+ // Get the valid symbol values.
132
+ VALUE square_sym = ID2SYM(rb_intern("square"));
133
+ VALUE circle_sym = ID2SYM(rb_intern("circle"));
134
+
135
+ // Try to convert the kind into a symbol. This could cause an exception.
136
+ VALUE kind_as_sym = rb_funcall(kind_value, rb_intern("to_sym"), 0);
137
+
138
+ // Also cause an exception if it's an incorrect symbol value.
139
+ if (kind_as_sym != square_sym && kind_as_sym != circle_sym)
140
+ rb_raise(rb_eTypeError, "invalid symbol for marker kind (set_info)");
141
+
142
+ mr_info_set(self->info, kind_as_sym == square_sym ? SQUARE : CIRCLE, rb_num2dbl(scale_value));
143
+
144
+ return self_value;
145
+ }
146
+
147
+ static VALUE rb_api_add(VALUE self_value, VALUE x_value, VALUE y_value, VALUE size_value)
148
+ #define ARGC_add 3
149
+ {
150
+ MARKER_LIST_FOR_VALUE_DECL(self);
151
+ add_marker(self, rb_num2dbl(x_value), rb_num2dbl(y_value), rb_num2dbl(size_value));
152
+ return INT2FIX(self->size);
153
+ }
154
+
155
+ static VALUE rb_api_length(VALUE self_value)
156
+ #define ARGC_length 0
157
+ {
158
+ MARKER_LIST_FOR_VALUE_DECL(self);
159
+ return INT2FIX(self->size);
160
+ }
161
+
162
+ static VALUE rb_api_marker(VALUE self_value, VALUE index)
163
+ #define ARGC_marker 1
164
+ {
165
+ MARKER_LIST_FOR_VALUE_DECL(self);
166
+ int i = NUM2INT(index);
167
+ if (0 <= i && i < self->size) {
168
+ MARKER *marker = self->markers + i;
169
+ VALUE triple = rb_ary_new2(3);
170
+ rb_ary_store(triple, 0, rb_float_new(mr_x(marker)));
171
+ rb_ary_store(triple, 1, rb_float_new(mr_y(marker)));
172
+ rb_ary_store(triple, 2, rb_float_new(marker->size));
173
+ return triple;
174
+ }
175
+ return Qnil;
176
+ }
177
+
178
+ static VALUE rb_api_parts(VALUE self_value, VALUE index)
179
+ #define ARGC_parts 1
180
+ {
181
+ MARKER_LIST_FOR_VALUE_DECL(self);
182
+ int i = NUM2INT(index);
183
+ if (0 <= i && i < self->size) {
184
+ MARKER *marker = self->markers + i;
185
+ VALUE rtn;
186
+ if (mr_merged(marker)) {
187
+ rtn = rb_ary_new2(3);
188
+ rb_ary_store(rtn, 0, ID2SYM(rb_intern(mr_deleted_p(marker) ? "merge" : "root")));
189
+ rb_ary_store(rtn, 1, INT2FIX(marker->part_a));
190
+ rb_ary_store(rtn, 2, INT2FIX(marker->part_b));
191
+ } else {
192
+ rtn = rb_ary_new2(1);
193
+ rb_ary_store(rtn, 0, ID2SYM(rb_intern(mr_deleted_p(marker) ? "leaf" : "single")));
194
+ }
195
+ return rtn;
196
+ }
197
+ return Qnil;
198
+ }
199
+
200
+ static VALUE rb_api_deleted(VALUE self_value, VALUE index)
201
+ #define ARGC_deleted 1
202
+ {
203
+ MARKER_LIST_FOR_VALUE_DECL(self);
204
+ int i = NUM2INT(index);
205
+ if (0 <= i && i < self->size)
206
+ return mr_deleted_p(self->markers + i) ? Qtrue : Qfalse;
207
+ return Qnil;
208
+ }
209
+
210
+ static VALUE rb_api_compress(VALUE self_value)
211
+ #define ARGC_compress 0
212
+ {
213
+ MARKER_LIST_FOR_VALUE_DECL(self);
214
+ compress(self);
215
+ return INT2FIX(self->size);
216
+ }
217
+
218
+ static VALUE rb_api_merge(VALUE self_value)
219
+ #define ARGC_merge 0
220
+ {
221
+ MARKER_LIST_FOR_VALUE_DECL(self);
222
+ ensure_headroom(self);
223
+ compress(self);
224
+ self->size = merge_markers_fast(self->info, self->markers, self->size);
225
+ return INT2FIX(self->size);
226
+ }
227
+
228
+ #define FUNCTION_TABLE_ENTRY(Name) { #Name, RUBY_METHOD_FUNC(rb_api_ ## Name), ARGC_ ## Name }
229
+
230
+ static struct ft_entry {
231
+ const char *name;
232
+ VALUE (*func)(ANYARGS);
233
+ int argc;
234
+ } function_table[] = {
235
+ FUNCTION_TABLE_ENTRY(add),
236
+ FUNCTION_TABLE_ENTRY(compress),
237
+ FUNCTION_TABLE_ENTRY(clear),
238
+ FUNCTION_TABLE_ENTRY(deleted),
239
+ FUNCTION_TABLE_ENTRY(initialize_copy),
240
+ FUNCTION_TABLE_ENTRY(length),
241
+ FUNCTION_TABLE_ENTRY(marker),
242
+ FUNCTION_TABLE_ENTRY(merge),
243
+ FUNCTION_TABLE_ENTRY(parts),
244
+ FUNCTION_TABLE_ENTRY(set_info),
245
+ };
246
+
247
+ #define STRING_CONST_TABLE_ENTRY(Name) { #Name, Name }
248
+
249
+ static struct sct_entry {
250
+ const char *name;
251
+ const char *val;
252
+ } string_const_table[] = {
253
+ STRING_CONST_TABLE_ENTRY(EXT_VERSION)
254
+ };
255
+
256
+ void Init_lulu(void)
257
+ {
258
+ VALUE module = rb_define_module("Lulu");
259
+ VALUE klass = rb_define_class_under(module, "MarkerList", rb_cObject);
260
+ rb_define_alloc_func(klass, rb_api_new_marker_list);
261
+
262
+ for (int i = 0; i < STATIC_ARRAY_SIZE(function_table); i++) {
263
+ struct ft_entry *e = function_table + i;
264
+ rb_define_method(klass, e->name, e->func, e->argc);
265
+ }
266
+
267
+ for (int i = 0; i < STATIC_ARRAY_SIZE(string_const_table); i++) {
268
+ struct sct_entry *e = string_const_table + i;
269
+ rb_define_const(module, e->name, rb_str_new2(e->val));
270
+ }
271
+ }