rgeo 2.3.1 → 2.4.0

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.
@@ -10,6 +10,8 @@
10
10
  #include <ruby.h>
11
11
  #include <geos_c.h>
12
12
 
13
+ #include "globals.h"
14
+
13
15
  #include "factory.h"
14
16
  #include "geometry.h"
15
17
  #include "point.h"
@@ -36,82 +38,89 @@ static void message_handler(const char* fmt, ...)
36
38
  // objects that have been created for the factory, and then destroy
37
39
  // the GEOS context, before freeing the factory data itself.
38
40
 
39
- static void destroy_factory_func(RGeo_FactoryData* data)
41
+ static void destroy_factory_func(void* data)
40
42
  {
43
+ RGeo_FactoryData* factory_data;
41
44
  GEOSContextHandle_t context;
42
45
 
43
- context = data->geos_context;
44
- if (data->wkt_reader) {
45
- GEOSWKTReader_destroy_r(context, data->wkt_reader);
46
+ factory_data = (RGeo_FactoryData*)data;
47
+ context = factory_data->geos_context;
48
+ if (factory_data->wkt_reader) {
49
+ GEOSWKTReader_destroy_r(context, factory_data->wkt_reader);
46
50
  }
47
- if (data->wkb_reader) {
48
- GEOSWKBReader_destroy_r(context, data->wkb_reader);
51
+ if (factory_data->wkb_reader) {
52
+ GEOSWKBReader_destroy_r(context, factory_data->wkb_reader);
49
53
  }
50
- if (data->wkt_writer) {
51
- GEOSWKTWriter_destroy_r(context, data->wkt_writer);
54
+ if (factory_data->wkt_writer) {
55
+ GEOSWKTWriter_destroy_r(context, factory_data->wkt_writer);
52
56
  }
53
- if (data->wkb_writer) {
54
- GEOSWKBWriter_destroy_r(context, data->wkb_writer);
57
+ if (factory_data->wkb_writer) {
58
+ GEOSWKBWriter_destroy_r(context, factory_data->wkb_writer);
55
59
  }
56
- if (data->psych_wkt_reader) {
57
- GEOSWKTReader_destroy_r(context, data->psych_wkt_reader);
60
+ if (factory_data->psych_wkt_reader) {
61
+ GEOSWKTReader_destroy_r(context, factory_data->psych_wkt_reader);
58
62
  }
59
- if (data->marshal_wkb_reader) {
60
- GEOSWKBReader_destroy_r(context, data->marshal_wkb_reader);
63
+ if (factory_data->marshal_wkb_reader) {
64
+ GEOSWKBReader_destroy_r(context, factory_data->marshal_wkb_reader);
61
65
  }
62
- if (data->psych_wkt_writer) {
63
- GEOSWKTWriter_destroy_r(context, data->psych_wkt_writer);
66
+ if (factory_data->psych_wkt_writer) {
67
+ GEOSWKTWriter_destroy_r(context, factory_data->psych_wkt_writer);
64
68
  }
65
- if (data->marshal_wkb_writer) {
66
- GEOSWKBWriter_destroy_r(context, data->marshal_wkb_writer);
69
+ if (factory_data->marshal_wkb_writer) {
70
+ GEOSWKBWriter_destroy_r(context, factory_data->marshal_wkb_writer);
67
71
  }
68
72
  finishGEOS_r(context);
69
- free(data);
73
+ free(factory_data);
70
74
  }
71
75
 
72
76
 
73
77
  // Destroy function for geometry data. We destroy the internal
74
78
  // GEOS geometry (if present) before freeing the data itself.
75
79
 
76
- static void destroy_geometry_func(RGeo_GeometryData* data)
80
+ static void destroy_geometry_func(void* data)
77
81
  {
82
+ RGeo_GeometryData* geometry_data;
78
83
  const GEOSPreparedGeometry* prep;
79
84
 
80
- if (data->geom) {
81
- GEOSGeom_destroy_r(data->geos_context, data->geom);
85
+ geometry_data = (RGeo_GeometryData*)data;
86
+ if (geometry_data->geom) {
87
+ GEOSGeom_destroy_r(geometry_data->geos_context, geometry_data->geom);
82
88
  }
83
- prep = data->prep;
89
+ prep = geometry_data->prep;
84
90
  if (prep && prep != (const GEOSPreparedGeometry*)1 && prep != (const GEOSPreparedGeometry*)2 &&
85
91
  prep != (const GEOSPreparedGeometry*)3)
86
92
  {
87
- GEOSPreparedGeom_destroy_r(data->geos_context, prep);
93
+ GEOSPreparedGeom_destroy_r(geometry_data->geos_context, prep);
88
94
  }
89
- free(data);
95
+ free(geometry_data);
90
96
  }
91
97
 
92
98
 
93
99
  // Mark function for factory data. This marks the wkt and wkb generator
94
100
  // handles so they don't get collected.
95
101
 
96
- static void mark_factory_func(RGeo_FactoryData* data)
102
+ static void mark_factory_func(void* data)
97
103
  {
98
- if (!NIL_P(data->wkrep_wkt_generator)) {
99
- rb_gc_mark(data->wkrep_wkt_generator);
104
+ RGeo_FactoryData* factory_data;
105
+
106
+ factory_data = (RGeo_FactoryData*)data;
107
+ if (!NIL_P(factory_data->wkrep_wkt_generator)) {
108
+ mark(factory_data->wkrep_wkt_generator);
100
109
  }
101
- if (!NIL_P(data->wkrep_wkb_generator)) {
102
- rb_gc_mark(data->wkrep_wkb_generator);
110
+ if (!NIL_P(factory_data->wkrep_wkb_generator)) {
111
+ mark(factory_data->wkrep_wkb_generator);
103
112
  }
104
- if (!NIL_P(data->wkrep_wkt_parser)) {
105
- rb_gc_mark(data->wkrep_wkt_parser);
113
+ if (!NIL_P(factory_data->wkrep_wkt_parser)) {
114
+ mark(factory_data->wkrep_wkt_parser);
106
115
  }
107
- if (!NIL_P(data->wkrep_wkb_parser)) {
108
- rb_gc_mark(data->wkrep_wkb_parser);
116
+ if (!NIL_P(factory_data->wkrep_wkb_parser)) {
117
+ mark(factory_data->wkrep_wkb_parser);
109
118
  }
110
- if (!NIL_P(data->proj4_obj)) {
111
- rb_gc_mark(data->proj4_obj);
119
+ if (!NIL_P(factory_data->proj4_obj)) {
120
+ mark(factory_data->proj4_obj);
112
121
  }
113
- if (!NIL_P(data->coord_sys_obj)) {
114
- rb_gc_mark(data->coord_sys_obj);
122
+ if (!NIL_P(factory_data->coord_sys_obj)) {
123
+ mark(factory_data->coord_sys_obj);
115
124
  }
116
125
  }
117
126
 
@@ -119,32 +128,83 @@ static void mark_factory_func(RGeo_FactoryData* data)
119
128
  // Mark function for geometry data. This marks the factory and klasses
120
129
  // held by the geometry so those don't get collected.
121
130
 
122
- static void mark_geometry_func(RGeo_GeometryData* data)
131
+ static void mark_geometry_func(void* data)
123
132
  {
124
- if (!NIL_P(data->factory)) {
125
- rb_gc_mark(data->factory);
133
+ RGeo_GeometryData* geometry_data;
134
+
135
+ geometry_data = (RGeo_GeometryData*)data;
136
+ if (!NIL_P(geometry_data->factory)) {
137
+ mark(geometry_data->factory);
126
138
  }
127
- if (!NIL_P(data->klasses)) {
128
- rb_gc_mark(data->klasses);
139
+ if (!NIL_P(geometry_data->klasses)) {
140
+ mark(geometry_data->klasses);
129
141
  }
130
142
  }
131
143
 
132
144
 
133
- // Destroy function for globals data. We don't need to destroy any
134
- // auxiliary data for now...
135
-
136
- static void destroy_globals_func(RGeo_Globals* data)
145
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
146
+ static void compact_factory_func(void* data)
137
147
  {
138
- free(data);
139
- }
148
+ RGeo_FactoryData* factory_data;
140
149
 
150
+ factory_data = (RGeo_FactoryData*)data;
151
+ if (!NIL_P(factory_data->wkrep_wkt_generator)) {
152
+ factory_data->wkrep_wkt_generator = rb_gc_location(factory_data->wkrep_wkt_generator);
153
+ }
154
+ if (!NIL_P(factory_data->wkrep_wkb_generator)) {
155
+ factory_data->wkrep_wkb_generator = rb_gc_location(factory_data->wkrep_wkb_generator);
156
+ }
157
+ if (!NIL_P(factory_data->wkrep_wkt_parser)) {
158
+ factory_data->wkrep_wkt_parser = rb_gc_location(factory_data->wkrep_wkt_parser);
159
+ }
160
+ if (!NIL_P(factory_data->wkrep_wkb_parser)) {
161
+ factory_data->wkrep_wkb_parser = rb_gc_location(factory_data->wkrep_wkb_parser);
162
+ }
163
+ if (!NIL_P(factory_data->proj4_obj)) {
164
+ factory_data->proj4_obj = rb_gc_location(factory_data->proj4_obj);
165
+ }
166
+ if (!NIL_P(factory_data->coord_sys_obj)) {
167
+ factory_data->coord_sys_obj = rb_gc_location(factory_data->coord_sys_obj);
168
+ }
169
+ }
141
170
 
142
- // Mark function for globals data. This should mark any globals that
143
- // need to be held through garbage collection (none at the moment.)
144
171
 
145
- static void mark_globals_func(RGeo_Globals* data)
172
+ static void compact_geometry_func(void* data)
146
173
  {
174
+ RGeo_GeometryData* geometry_data;
175
+
176
+ geometry_data = (RGeo_GeometryData*)data;
177
+ if (!NIL_P(geometry_data->factory)) {
178
+ geometry_data->factory = rb_gc_location(geometry_data->factory);
179
+ }
180
+ if (!NIL_P(geometry_data->klasses)) {
181
+ geometry_data->klasses = rb_gc_location(geometry_data->klasses);
182
+ }
147
183
  }
184
+ #endif
185
+
186
+
187
+ const rb_data_type_t rgeo_factory_type = {
188
+ .wrap_struct_name = "RGeo/Factory",
189
+ .function = {
190
+ .dmark = mark_factory_func,
191
+ .dfree = destroy_factory_func,
192
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
193
+ .dcompact = compact_factory_func,
194
+ #endif
195
+ }
196
+ };
197
+
198
+ const rb_data_type_t rgeo_geometry_type = {
199
+ .wrap_struct_name = "RGeo/Geometry",
200
+ .function = {
201
+ .dmark = mark_geometry_func,
202
+ .dfree = destroy_geometry_func,
203
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
204
+ .dcompact = compact_geometry_func,
205
+ #endif
206
+ }
207
+ };
148
208
 
149
209
 
150
210
  /**** RUBY METHOD DEFINITIONS ****/
@@ -248,7 +308,6 @@ static VALUE method_factory_read_for_marshal(VALUE self, VALUE str)
248
308
  return result;
249
309
  }
250
310
 
251
-
252
311
  static VALUE method_factory_read_for_psych(VALUE self, VALUE str)
253
312
  {
254
313
  RGeo_FactoryData* self_data;
@@ -275,6 +334,9 @@ static VALUE method_factory_read_for_psych(VALUE self, VALUE str)
275
334
  return result;
276
335
  }
277
336
 
337
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
338
+ static VALUE marshal_wkb_generator;
339
+ #endif
278
340
 
279
341
  static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
280
342
  {
@@ -286,25 +348,18 @@ static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
286
348
  char* str;
287
349
  size_t size;
288
350
  char has_3d;
289
- #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
290
- RGeo_Globals* globals;
291
- VALUE wkb_generator;
292
- #endif
293
351
 
294
352
  self_data = RGEO_FACTORY_DATA_PTR(self);
295
353
  self_context = self_data->geos_context;
296
354
  has_3d = self_data->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
297
355
  #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
298
356
  if (has_3d) {
299
- globals = self_data->globals;
300
- wkb_generator = globals->marshal_wkb_generator;
301
- if (NIL_P(wkb_generator)) {
302
- wkb_generator = rb_funcall(
303
- rb_const_get_at(globals->geos_module, rb_intern("Utils")),
357
+ if (NIL_P(marshal_wkb_generator)) {
358
+ marshal_wkb_generator = rb_funcall(
359
+ rb_const_get_at(rgeo_geos_module, rb_intern("Utils")),
304
360
  rb_intern("marshal_wkb_generator"), 0);
305
- globals->marshal_wkb_generator = wkb_generator;
306
361
  }
307
- return rb_funcall(wkb_generator, globals->id_generate, 1, obj);
362
+ return rb_funcall(marshal_wkb_generator, rb_intern("generate"), 1, obj);
308
363
  }
309
364
  #endif
310
365
  wkb_writer = self_data->marshal_wkb_writer;
@@ -329,6 +384,9 @@ static VALUE method_factory_write_for_marshal(VALUE self, VALUE obj)
329
384
  return result;
330
385
  }
331
386
 
387
+ #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
388
+ static VALUE psych_wkt_generator;
389
+ #endif
332
390
 
333
391
  static VALUE method_factory_write_for_psych(VALUE self, VALUE obj)
334
392
  {
@@ -339,25 +397,18 @@ static VALUE method_factory_write_for_psych(VALUE self, VALUE obj)
339
397
  VALUE result;
340
398
  char* str;
341
399
  char has_3d;
342
- #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
343
- RGeo_Globals* globals;
344
- VALUE wkt_generator;
345
- #endif
346
400
 
347
401
  self_data = RGEO_FACTORY_DATA_PTR(self);
348
402
  self_context = self_data->geos_context;
349
403
  has_3d = self_data->flags & RGEO_FACTORYFLAGS_SUPPORTS_Z_OR_M;
350
404
  #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
351
405
  if (has_3d) {
352
- globals = self_data->globals;
353
- wkt_generator = globals->psych_wkt_generator;
354
- if (NIL_P(wkt_generator)) {
355
- wkt_generator = rb_funcall(
356
- rb_const_get_at(globals->geos_module, rb_intern("Utils")),
406
+ if (NIL_P(psych_wkt_generator)) {
407
+ psych_wkt_generator = rb_funcall(
408
+ rb_const_get_at(rgeo_geos_module, rb_intern("Utils")),
357
409
  rb_intern("psych_wkt_generator"), 0);
358
- globals->psych_wkt_generator = wkt_generator;
359
410
  }
360
- return rb_funcall(wkt_generator, globals->id_generate, 1, obj);
411
+ return rb_funcall(psych_wkt_generator, rb_intern("generate"), 1, obj);
361
412
  }
362
413
  #endif
363
414
  wkt_writer = self_data->psych_wkt_writer;
@@ -404,15 +455,12 @@ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE
404
455
  VALUE result;
405
456
  RGeo_FactoryData* data;
406
457
  GEOSContextHandle_t context;
407
- VALUE wrapped_globals;
408
458
 
409
459
  result = Qnil;
410
460
  data = ALLOC(RGeo_FactoryData);
411
461
  if (data) {
412
462
  context = initGEOS_r(message_handler, message_handler);
413
463
  if (context) {
414
- wrapped_globals = rb_const_get_at(klass, rb_intern("INTERNAL_CGLOBALS"));
415
- data->globals = (RGeo_Globals*)DATA_PTR(wrapped_globals);
416
464
  data->geos_context = context;
417
465
  data->flags = NUM2INT(flags);
418
466
  data->srid = NUM2INT(srid);
@@ -431,7 +479,7 @@ static VALUE cmethod_factory_create(VALUE klass, VALUE flags, VALUE srid, VALUE
431
479
  data->wkrep_wkb_parser = Qnil;
432
480
  data->proj4_obj = proj4_obj;
433
481
  data->coord_sys_obj = coord_sys_obj;
434
- result = Data_Wrap_Struct(klass, mark_factory_func, destroy_factory_func, data);
482
+ result = TypedData_Wrap_Struct(klass, &rgeo_factory_type, data);
435
483
  }
436
484
  else {
437
485
  free(data);
@@ -496,7 +544,7 @@ static VALUE method_factory_initialize_copy(VALUE self, VALUE orig)
496
544
  self_data->coord_sys_obj = Qnil;
497
545
 
498
546
  // Copy new data from original object
499
- if (TYPE(orig) == T_DATA && RDATA(orig)->dfree == (RUBY_DATA_FUNC)destroy_factory_func) {
547
+ if (RGEO_FACTORY_TYPEDDATA_P(orig)) {
500
548
  orig_data = RGEO_FACTORY_DATA_PTR(orig);
501
549
  self_data->flags = orig_data->flags;
502
550
  self_data->srid = orig_data->srid;
@@ -569,48 +617,20 @@ static VALUE alloc_geometry(VALUE klass)
569
617
  /**** INITIALIZATION FUNCTION ****/
570
618
 
571
619
 
572
- RGeo_Globals* rgeo_init_geos_factory()
620
+ void rgeo_init_geos_factory()
573
621
  {
574
- RGeo_Globals* globals;
575
- VALUE rgeo_module;
576
622
  VALUE geos_factory_class;
577
- VALUE wrapped_globals;
578
- VALUE feature_module;
579
-
580
- rgeo_module = rb_define_module("RGeo");
581
-
582
- globals = ALLOC(RGeo_Globals);
583
-
584
- // Cache some modules so we don't have to look them up by name every time
585
- feature_module = rb_define_module_under(rgeo_module, "Feature");
586
- globals->feature_module = feature_module;
587
- globals->geos_module = rb_define_module_under(rgeo_module, "Geos");
588
- globals->feature_geometry = rb_const_get_at(feature_module, rb_intern("Geometry"));
589
- globals->feature_point = rb_const_get_at(feature_module, rb_intern("Point"));
590
- globals->feature_line_string = rb_const_get_at(feature_module, rb_intern("LineString"));
591
- globals->feature_linear_ring = rb_const_get_at(feature_module, rb_intern("LinearRing"));
592
- globals->feature_line = rb_const_get_at(feature_module, rb_intern("Line"));
593
- globals->feature_polygon = rb_const_get_at(feature_module, rb_intern("Polygon"));
594
- globals->feature_geometry_collection = rb_const_get_at(feature_module, rb_intern("GeometryCollection"));
595
- globals->feature_multi_point = rb_const_get_at(feature_module, rb_intern("MultiPoint"));
596
- globals->feature_multi_line_string = rb_const_get_at(feature_module, rb_intern("MultiLineString"));
597
- globals->feature_multi_polygon = rb_const_get_at(feature_module, rb_intern("MultiPolygon"));
598
-
599
- // Cache some commonly used names
600
- globals->id_cast = rb_intern("cast");
601
- globals->id_eql = rb_intern("eql?");
602
- globals->id_generate = rb_intern("generate");
603
- globals->id_enum_for = rb_intern("enum_for");
604
- globals->id_hash = rb_intern("hash");
605
- globals->sym_force_new = ID2SYM(rb_intern("force_new"));
606
- globals->sym_keep_subtype = ID2SYM(rb_intern("keep_subtype"));
623
+
607
624
  #ifndef RGEO_GEOS_SUPPORTS_SETOUTPUTDIMENSION
608
- globals->psych_wkt_generator = Qnil;
609
- globals->marshal_wkb_generator = Qnil;
625
+ /* We favor rb_gc_register_address over rb_gc_register_mark_object because the value changes at runtime */
626
+ psych_wkt_generator = Qnil;
627
+ rb_gc_register_address(&psych_wkt_generator);
628
+ marshal_wkb_generator = Qnil;
629
+ rb_gc_register_address(&marshal_wkb_generator);
610
630
  #endif
611
631
 
612
632
  // Add C methods to the factory.
613
- geos_factory_class = rb_define_class_under(globals->geos_module, "CAPIFactory", rb_cObject);
633
+ geos_factory_class = rb_define_class_under(rgeo_geos_module, "CAPIFactory", rb_cObject);
614
634
  rb_define_alloc_func(geos_factory_class, alloc_factory);
615
635
  rb_define_method(geos_factory_class, "initialize_copy", method_factory_initialize_copy, 1);
616
636
  rb_define_method(geos_factory_class, "_parse_wkt_impl", method_factory_parse_wkt, 1);
@@ -633,34 +653,17 @@ RGeo_Globals* rgeo_init_geos_factory()
633
653
  rb_define_module_function(geos_factory_class, "_geos_version", cmethod_factory_geos_version, 0);
634
654
  rb_define_module_function(geos_factory_class, "_supports_unary_union?", cmethod_factory_supports_unary_union, 0);
635
655
 
636
- // Pre-define implementation classes and set up allocation methods
637
- globals->geos_geometry = rb_define_class_under(globals->geos_module, "CAPIGeometryImpl", rb_cObject);
638
- rb_define_alloc_func(globals->geos_geometry, alloc_geometry);
639
- globals->geos_point = rb_define_class_under(globals->geos_module, "CAPIPointImpl", rb_cObject);
640
- rb_define_alloc_func(globals->geos_point, alloc_geometry);
641
- globals->geos_line_string = rb_define_class_under(globals->geos_module, "CAPILineStringImpl", rb_cObject);
642
- rb_define_alloc_func(globals->geos_line_string, alloc_geometry);
643
- globals->geos_linear_ring = rb_define_class_under(globals->geos_module, "CAPILinearRingImpl", rb_cObject);
644
- rb_define_alloc_func(globals->geos_linear_ring, alloc_geometry);
645
- globals->geos_line = rb_define_class_under(globals->geos_module, "CAPILineImpl", rb_cObject);
646
- rb_define_alloc_func(globals->geos_line, alloc_geometry);
647
- globals->geos_polygon = rb_define_class_under(globals->geos_module, "CAPIPolygonImpl", rb_cObject);
648
- rb_define_alloc_func(globals->geos_polygon, alloc_geometry);
649
- globals->geos_geometry_collection = rb_define_class_under(globals->geos_module, "CAPIGeometryCollectionImpl", rb_cObject);
650
- rb_define_alloc_func(globals->geos_geometry_collection, alloc_geometry);
651
- globals->geos_multi_point = rb_define_class_under(globals->geos_module, "CAPIMultiPointImpl", rb_cObject);
652
- rb_define_alloc_func(globals->geos_multi_point, alloc_geometry);
653
- globals->geos_multi_line_string = rb_define_class_under(globals->geos_module, "CAPIMultiLineStringImpl", rb_cObject);
654
- rb_define_alloc_func(globals->geos_multi_line_string, alloc_geometry);
655
- globals->geos_multi_polygon = rb_define_class_under(globals->geos_module, "CAPIMultiPolygonImpl", rb_cObject);
656
- rb_define_alloc_func(globals->geos_multi_polygon, alloc_geometry);
657
-
658
- // Wrap the globals in a Ruby object and store it off so we have access
659
- // to it later. Each factory instance will reference it internally.
660
- wrapped_globals = Data_Wrap_Struct(rb_cObject, mark_globals_func, destroy_globals_func, globals);
661
- rb_define_const(geos_factory_class, "INTERNAL_CGLOBALS", wrapped_globals);
662
-
663
- return globals;
656
+ // Define allocation methods for global class types
657
+ rb_define_alloc_func(rgeo_geos_geometry_class, alloc_geometry);
658
+ rb_define_alloc_func(rgeo_geos_point_class, alloc_geometry);
659
+ rb_define_alloc_func(rgeo_geos_line_string_class, alloc_geometry);
660
+ rb_define_alloc_func(rgeo_geos_linear_ring_class, alloc_geometry);
661
+ rb_define_alloc_func(rgeo_geos_line_class, alloc_geometry);
662
+ rb_define_alloc_func(rgeo_geos_polygon_class, alloc_geometry);
663
+ rb_define_alloc_func(rgeo_geos_geometry_collection_class, alloc_geometry);
664
+ rb_define_alloc_func(rgeo_geos_multi_point_class, alloc_geometry);
665
+ rb_define_alloc_func(rgeo_geos_multi_line_string_class, alloc_geometry);
666
+ rb_define_alloc_func(rgeo_geos_multi_polygon_class, alloc_geometry);
664
667
  }
665
668
 
666
669
 
@@ -673,7 +676,6 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
673
676
  RGeo_FactoryData* factory_data;
674
677
  GEOSContextHandle_t factory_context;
675
678
  VALUE klasses;
676
- RGeo_Globals* globals;
677
679
  VALUE inferred_klass;
678
680
  char is_collection;
679
681
  RGeo_GeometryData* data;
@@ -682,7 +684,6 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
682
684
  if (geom || !NIL_P(klass)) {
683
685
  factory_data = NIL_P(factory) ? NULL : RGEO_FACTORY_DATA_PTR(factory);
684
686
  factory_context = factory_data ? factory_data->geos_context : NULL;
685
- globals = factory_data ? factory_data->globals : NULL;
686
687
 
687
688
  // We don't allow "empty" points, so replace such objects with
688
689
  // an empty collection.
@@ -690,7 +691,7 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
690
691
  if (GEOSGeomTypeId_r(factory_context, geom) == GEOS_POINT && GEOSGetNumCoordinates_r(factory_context, geom) == 0) {
691
692
  GEOSGeom_destroy_r(factory_context, geom);
692
693
  geom = GEOSGeom_createCollection_r(factory_context, GEOS_GEOMETRYCOLLECTION, NULL, 0);
693
- klass = globals->geos_geometry_collection;
694
+ klass = rgeo_geos_geometry_collection_class;
694
695
  }
695
696
  }
696
697
 
@@ -700,35 +701,35 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
700
701
  is_collection = 0;
701
702
  switch (GEOSGeomTypeId_r(factory_context, geom)) {
702
703
  case GEOS_POINT:
703
- inferred_klass = globals->geos_point;
704
+ inferred_klass = rgeo_geos_point_class;
704
705
  break;
705
706
  case GEOS_LINESTRING:
706
- inferred_klass = globals->geos_line_string;
707
+ inferred_klass = rgeo_geos_line_string_class;
707
708
  break;
708
709
  case GEOS_LINEARRING:
709
- inferred_klass = globals->geos_linear_ring;
710
+ inferred_klass = rgeo_geos_linear_ring_class;
710
711
  break;
711
712
  case GEOS_POLYGON:
712
- inferred_klass = globals->geos_polygon;
713
+ inferred_klass = rgeo_geos_polygon_class;
713
714
  break;
714
715
  case GEOS_MULTIPOINT:
715
- inferred_klass = globals->geos_multi_point;
716
+ inferred_klass = rgeo_geos_multi_point_class;
716
717
  is_collection = 1;
717
718
  break;
718
719
  case GEOS_MULTILINESTRING:
719
- inferred_klass = globals->geos_multi_line_string;
720
+ inferred_klass = rgeo_geos_multi_line_string_class;
720
721
  is_collection = 1;
721
722
  break;
722
723
  case GEOS_MULTIPOLYGON:
723
- inferred_klass = globals->geos_multi_polygon;
724
+ inferred_klass = rgeo_geos_multi_polygon_class;
724
725
  is_collection = 1;
725
726
  break;
726
727
  case GEOS_GEOMETRYCOLLECTION:
727
- inferred_klass = globals->geos_geometry_collection;
728
+ inferred_klass = rgeo_geos_geometry_collection_class;
728
729
  is_collection = 1;
729
730
  break;
730
731
  default:
731
- inferred_klass = globals->geos_geometry;
732
+ inferred_klass = rgeo_geos_geometry_class;
732
733
  break;
733
734
  }
734
735
  if (TYPE(klass) == T_ARRAY && is_collection) {
@@ -747,13 +748,12 @@ VALUE rgeo_wrap_geos_geometry(VALUE factory, GEOSGeometry* geom, VALUE klass)
747
748
  (GEOSPreparedGeometry*)1 : NULL;
748
749
  data->factory = factory;
749
750
  data->klasses = klasses;
750
- result = Data_Wrap_Struct(klass, mark_geometry_func, destroy_geometry_func, data);
751
+ result = TypedData_Wrap_Struct(klass, &rgeo_geometry_type, data);
751
752
  }
752
753
  }
753
754
  return result;
754
755
  }
755
756
 
756
-
757
757
  VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VALUE klass)
758
758
  {
759
759
  VALUE result;
@@ -773,19 +773,17 @@ VALUE rgeo_wrap_geos_geometry_clone(VALUE factory, const GEOSGeometry* geom, VAL
773
773
  const GEOSGeometry* rgeo_convert_to_geos_geometry(VALUE factory, VALUE obj, VALUE type)
774
774
  {
775
775
  VALUE object;
776
- RGeo_Globals* globals;
777
776
 
778
- if (NIL_P(type) && TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func && RGEO_GEOMETRY_DATA_PTR(obj)->factory == factory) {
777
+ if (NIL_P(type) && RGEO_GEOMETRY_TYPEDDATA_P(obj) && RGEO_GEOMETRY_DATA_PTR(obj)->factory == factory) {
779
778
  object = obj;
780
779
  }
781
780
  else {
782
- globals = RGEO_FACTORY_DATA_PTR(factory)->globals;
783
- object = rb_funcall(globals->feature_module, globals->id_cast, 3, obj, factory, type);
781
+ object = rb_funcall(rgeo_feature_module, rb_intern("cast"), 3, obj, factory, type);
784
782
  }
785
783
  if (NIL_P(object))
786
784
  return NULL;
787
785
 
788
- Check_Type(object, T_DATA);
786
+ Check_TypedStruct(object, &rgeo_geometry_type);
789
787
  return RGEO_GEOMETRY_DATA_PTR(object)->geom;
790
788
  }
791
789
 
@@ -796,13 +794,11 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
796
794
  GEOSGeometry* geom;
797
795
  RGeo_GeometryData* object_data;
798
796
  const GEOSPreparedGeometry* prep;
799
- RGeo_Globals* globals;
800
797
 
801
798
  if (klasses) {
802
799
  *klasses = Qnil;
803
800
  }
804
- globals = RGEO_FACTORY_DATA_PTR(factory)->globals;
805
- object = rb_funcall(globals->feature_module, globals->id_cast, 5, obj, factory, type, globals->sym_force_new, globals->sym_keep_subtype);
801
+ object = rb_funcall(rgeo_feature_module, rb_intern("cast"), 5, obj, factory, type, ID2SYM(rb_intern("force_new")), ID2SYM(rb_intern("keep_subtype")));
806
802
  geom = NULL;
807
803
  if (!NIL_P(object)) {
808
804
  object_data = RGEO_GEOMETRY_DATA_PTR(object);
@@ -829,7 +825,7 @@ GEOSGeometry* rgeo_convert_to_detached_geos_geometry(VALUE obj, VALUE factory, V
829
825
 
830
826
  char rgeo_is_geos_object(VALUE obj)
831
827
  {
832
- return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? 1 : 0;
828
+ return RGEO_GEOMETRY_TYPEDDATA_P(obj) ? 1 : 0;
833
829
  }
834
830
 
835
831
  void rgeo_check_geos_object(VALUE obj)
@@ -842,7 +838,7 @@ void rgeo_check_geos_object(VALUE obj)
842
838
 
843
839
  const GEOSGeometry* rgeo_get_geos_geometry_safe(VALUE obj)
844
840
  {
845
- return (TYPE(obj) == T_DATA && RDATA(obj)->dfree == (RUBY_DATA_FUNC)destroy_geometry_func) ? (const GEOSGeometry*)(RGEO_GEOMETRY_DATA_PTR(obj)->geom) : NULL;
841
+ return RGEO_GEOMETRY_TYPEDDATA_P(obj) ? (const GEOSGeometry*)(RGEO_GEOMETRY_DATA_PTR(obj)->geom) : NULL;
846
842
  }
847
843
 
848
844
 
@@ -930,7 +926,8 @@ VALUE rgeo_geos_klasses_and_factories_eql(VALUE obj1, VALUE obj2)
930
926
  }
931
927
  else {
932
928
  factory = RGEO_GEOMETRY_DATA_PTR(obj1)->factory;
933
- result = rb_funcall(factory, RGEO_FACTORY_DATA_PTR(factory)->globals->id_eql, 1, RGEO_GEOMETRY_DATA_PTR(obj2)->factory);
929
+ /* No need to cache the internal here (https://ips.fastruby.io/4x) */
930
+ result = rb_funcall(factory, rb_intern("eql?"), 1, RGEO_GEOMETRY_DATA_PTR(obj2)->factory);
934
931
  }
935
932
  return result;
936
933
  }
@@ -983,7 +980,7 @@ st_index_t rgeo_geos_objbase_hash(VALUE factory, VALUE type_module, st_index_t h
983
980
  ID hash_method;
984
981
  RGeo_Objbase_Hash_Struct hash_struct;
985
982
 
986
- hash_method = RGEO_FACTORY_DATA_PTR(factory)->globals->id_hash;
983
+ hash_method = rb_intern("hash");
987
984
  hash_struct.seed_hash = hash;
988
985
  hash_struct.h1 = FIX2LONG(rb_funcall(factory, hash_method, 0));
989
986
  hash_struct.h2 = FIX2LONG(rb_funcall(type_module, hash_method, 0));