diff options
-rw-r--r-- | ext/rpatricia/rpatricia.c | 36 | ||||
-rw-r--r-- | test/test_duplicate.rb | 28 | ||||
-rw-r--r-- | test/test_gc.rb | 15 | ||||
-rw-r--r-- | test/test_subclass.rb | 11 |
4 files changed, 84 insertions, 6 deletions
diff --git a/ext/rpatricia/rpatricia.c b/ext/rpatricia/rpatricia.c index f395eea..f9564d2 100644 --- a/ext/rpatricia/rpatricia.c +++ b/ext/rpatricia/rpatricia.c @@ -6,6 +6,7 @@ #include "ruby.h" #include <stdlib.h> #include "patricia.h" +#include <assert.h> static VALUE cPatricia, cNode; @@ -245,11 +246,37 @@ p_tree_free (void *ptr) } static VALUE -p_new (VALUE self) +p_alloc(VALUE klass) { patricia_tree_t *tree; tree = New_Patricia(32); /* assuming only IPv4 */ - return Data_Wrap_Struct(cPatricia, p_tree_mark, p_tree_free, tree); + + return Data_Wrap_Struct(klass, p_tree_mark, p_tree_free, tree); +} + +static VALUE +p_init_copy(VALUE self, VALUE orig) +{ + patricia_tree_t *orig_tree; + + Data_Get_Struct(orig, patricia_tree_t, orig_tree); + if (orig_tree->head) { + patricia_tree_t *tree; + patricia_node_t *orig_node, *node; + prefix_t prefix; + VALUE user_data; + + Data_Get_Struct(self, patricia_tree_t, tree); + PATRICIA_WALK(orig_tree->head, orig_node) { + node = patricia_lookup(tree, orig_node->prefix); + assert(node->prefix == orig_node->prefix); + + user_data = (VALUE)(orig_node->data); + if (T_STRING == TYPE(user_data)) + user_data = rb_str_dup(user_data); + PATRICIA_DATA_SET(node, user_data); + } PATRICIA_WALK_END; + } } void @@ -258,8 +285,9 @@ Init_rpatricia (void) cPatricia = rb_define_class("Patricia", rb_cObject); cNode = rb_define_class_under(cPatricia, "Node", rb_cObject); - /* create new Patricia object */ - rb_define_singleton_method(cPatricia, "new", p_new, 0); + /* allocate new Patricia object, called before initialize */ + rb_define_alloc_func(cPatricia, p_alloc); + rb_define_method(cPatricia, "initialize_copy", p_init_copy, 1); /*---------- methods to tree ----------*/ /* add string */ diff --git a/test/test_duplicate.rb b/test/test_duplicate.rb new file mode 100644 index 0000000..c50a211 --- /dev/null +++ b/test/test_duplicate.rb @@ -0,0 +1,28 @@ +require 'test/unit' +require 'rpatricia' +require 'stringio' + +class TestDuplicate < Test::Unit::TestCase + def test_dup + tmp = {} + t = Patricia.new + t.add('127.0.0.0/8', tmp) + t2 = t.dup + assert_equal 1, t2.num_nodes + assert_equal tmp.object_id, t2.match_best('127.0.0.1').data.object_id + t2.add('10.0.0.0/8', zz = []) + assert_equal 2, t2.num_nodes + assert_equal 1, t.num_nodes + + oldout = $stdout + begin + $stdout = stringio = StringIO.new + t2.show_nodes + puts "--" + t.show_nodes + ensure + $stdout = oldout + end + p stringio.string + end +end diff --git a/test/test_gc.rb b/test/test_gc.rb index 5829deb..316d355 100644 --- a/test/test_gc.rb +++ b/test/test_gc.rb @@ -15,9 +15,20 @@ class TestGc < Test::Unit::TestCase @strings.add('127.0.0.0/24', "localhost") end + def test_gc_dup + 100000.times do + tmp = @strings.dup + tmp.remove '127.0.0.0/24' + tmp = @arrays.dup + tmp.remove '127.0.0.0/24' + end + assert_equal [], @arrays.match_best('127.0.0.1').data + assert_equal "localhost", @strings.match_best('127.0.0.1').data + end + def test_gc assert_nothing_raised do - 5_000_000.times do + 500_000.times do t = Patricia.new t.add('10.0.0.0/8', {}) t.add('127.0.0.0/24', "home sweet home") @@ -25,7 +36,7 @@ class TestGc < Test::Unit::TestCase end # ensure what we created originally didn't get GC-ed' - 5_000_000.times do + 500_000.times do assert_equal [], @arrays.match_best('127.0.0.1').data assert_equal "localhost", @strings.match_best('127.0.0.1').data end diff --git a/test/test_subclass.rb b/test/test_subclass.rb new file mode 100644 index 0000000..013bfdd --- /dev/null +++ b/test/test_subclass.rb @@ -0,0 +1,11 @@ +require 'test/unit' +require 'rpatricia' + +class SubPatricia < Patricia +end + +class TestSubclass < Test::Unit::TestCase + def test_new + assert_equal SubPatricia, SubPatricia.new.class + end +end |