utilrb 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/Changes.txt +20 -0
  2. data/License.txt +26 -0
  3. data/Manifest.txt +64 -0
  4. data/README.txt +44 -0
  5. data/Rakefile +46 -0
  6. data/bm/allocation.rb +7 -0
  7. data/bm/speed.rb +19 -0
  8. data/ext/extconf.rb +5 -0
  9. data/ext/faster.cc +48 -0
  10. data/ext/swap.cc +61 -0
  11. data/ext/value_set.cc +290 -0
  12. data/lib/utilrb.rb +2 -0
  13. data/lib/utilrb/array.rb +2 -0
  14. data/lib/utilrb/array/to_s.rb +16 -0
  15. data/lib/utilrb/common.rb +50 -0
  16. data/lib/utilrb/enumerable.rb +2 -0
  17. data/lib/utilrb/enumerable/null.rb +18 -0
  18. data/lib/utilrb/enumerable/random_element.rb +16 -0
  19. data/lib/utilrb/enumerable/sequence.rb +24 -0
  20. data/lib/utilrb/enumerable/uniq.rb +61 -0
  21. data/lib/utilrb/exception.rb +2 -0
  22. data/lib/utilrb/exception/full_message.rb +8 -0
  23. data/lib/utilrb/gc.rb +2 -0
  24. data/lib/utilrb/gc/force.rb +11 -0
  25. data/lib/utilrb/hash.rb +2 -0
  26. data/lib/utilrb/hash/slice.rb +6 -0
  27. data/lib/utilrb/hash/to_s.rb +6 -0
  28. data/lib/utilrb/hash/to_sym_keys.rb +6 -0
  29. data/lib/utilrb/kernel.rb +2 -0
  30. data/lib/utilrb/kernel/arity.rb +10 -0
  31. data/lib/utilrb/kernel/options.rb +69 -0
  32. data/lib/utilrb/kernel/poll.rb +24 -0
  33. data/lib/utilrb/kernel/require.rb +12 -0
  34. data/lib/utilrb/kernel/swap.rb +2 -0
  35. data/lib/utilrb/logger.rb +3 -0
  36. data/lib/utilrb/logger/forward.rb +15 -0
  37. data/lib/utilrb/logger/hierarchy.rb +34 -0
  38. data/lib/utilrb/module.rb +2 -0
  39. data/lib/utilrb/module/ancestor_p.rb +6 -0
  40. data/lib/utilrb/module/attr_enumerable.rb +28 -0
  41. data/lib/utilrb/module/define_method.rb +30 -0
  42. data/lib/utilrb/module/include.rb +30 -0
  43. data/lib/utilrb/module/inherited_enumerable.rb +122 -0
  44. data/lib/utilrb/object.rb +2 -0
  45. data/lib/utilrb/object/address.rb +14 -0
  46. data/lib/utilrb/object/attribute.rb +89 -0
  47. data/lib/utilrb/object/singleton_class.rb +53 -0
  48. data/lib/utilrb/objectstats.rb +52 -0
  49. data/lib/utilrb/time.rb +2 -0
  50. data/lib/utilrb/time/to_hms.rb +6 -0
  51. data/lib/utilrb/unbound_method.rb +2 -0
  52. data/lib/utilrb/unbound_method/call.rb +5 -0
  53. data/lib/utilrb/value_set.rb +17 -0
  54. data/test/test_array.rb +9 -0
  55. data/test/test_config.rb +4 -0
  56. data/test/test_enumerable.rb +89 -0
  57. data/test/test_gc.rb +39 -0
  58. data/test/test_hash.rb +22 -0
  59. data/test/test_kernel.rb +70 -0
  60. data/test/test_misc.rb +42 -0
  61. data/test/test_module.rb +127 -0
  62. data/test/test_object.rb +65 -0
  63. data/test/test_objectstats.rb +19 -0
  64. data/test/test_unbound_method.rb +23 -0
  65. metadata +128 -0
@@ -0,0 +1,20 @@
1
+ === Version 0.2.1
2
+ * new features:
3
+ - is_singleton?
4
+ - inherited_enumerable (class_inherited_enumerable on steroids)
5
+ - attribute() can be used in singleton classes (previously we had to
6
+ call class_attribute() in the class itself)
7
+ - UnboundMethod#call(obj, *args, &block) calls the method on obj with
8
+ the provided arguments
9
+
10
+ * changes:
11
+ - changed semantics of Module::include for inclusion of modules in modules:
12
+ the source_module::ClassExtension gets included in
13
+ target_module::ClassExtension. Previously, it was extending the target's
14
+ singleton class. This way, Module really acts as a mixin for both class
15
+ methods and instance methods
16
+
17
+ === Version 0.1
18
+ * Initial release
19
+
20
+
@@ -0,0 +1,26 @@
1
+ Copyright (c) The Regents of the University of California.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ 3. Neither the name of the University nor the names of its contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
+ SUCH DAMAGE.
@@ -0,0 +1,64 @@
1
+ bm/allocation.rb
2
+ bm/speed.rb
3
+ Changes.txt
4
+ ext/extconf.rb
5
+ ext/faster.cc
6
+ ext/swap.cc
7
+ ext/value_set.cc
8
+ lib/utilrb/array.rb
9
+ lib/utilrb/array/to_s.rb
10
+ lib/utilrb/common.rb
11
+ lib/utilrb/enumerable/null.rb
12
+ lib/utilrb/enumerable/random_element.rb
13
+ lib/utilrb/enumerable.rb
14
+ lib/utilrb/enumerable/sequence.rb
15
+ lib/utilrb/enumerable/uniq.rb
16
+ lib/utilrb/exception/full_message.rb
17
+ lib/utilrb/exception.rb
18
+ lib/utilrb/gc/force.rb
19
+ lib/utilrb/gc.rb
20
+ lib/utilrb/hash.rb
21
+ lib/utilrb/hash/slice.rb
22
+ lib/utilrb/hash/to_s.rb
23
+ lib/utilrb/hash/to_sym_keys.rb
24
+ lib/utilrb/kernel/arity.rb
25
+ lib/utilrb/kernel/options.rb
26
+ lib/utilrb/kernel/poll.rb
27
+ lib/utilrb/kernel.rb
28
+ lib/utilrb/kernel/require.rb
29
+ lib/utilrb/kernel/swap.rb
30
+ lib/utilrb/logger/forward.rb
31
+ lib/utilrb/logger/hierarchy.rb
32
+ lib/utilrb/logger.rb
33
+ lib/utilrb/module/ancestor_p.rb
34
+ lib/utilrb/module/attr_enumerable.rb
35
+ lib/utilrb/module/define_method.rb
36
+ lib/utilrb/module/include.rb
37
+ lib/utilrb/module/inherited_enumerable.rb
38
+ lib/utilrb/module.rb
39
+ lib/utilrb/object/address.rb
40
+ lib/utilrb/object/attribute.rb
41
+ lib/utilrb/object.rb
42
+ lib/utilrb/object/singleton_class.rb
43
+ lib/utilrb/objectstats.rb
44
+ lib/utilrb.rb
45
+ lib/utilrb/time.rb
46
+ lib/utilrb/time/to_hms.rb
47
+ lib/utilrb/unbound_method/call.rb
48
+ lib/utilrb/unbound_method.rb
49
+ lib/utilrb/value_set.rb
50
+ License.txt
51
+ Manifest.txt
52
+ Rakefile
53
+ README.txt
54
+ test/test_array.rb
55
+ test/test_config.rb
56
+ test/test_enumerable.rb
57
+ test/test_gc.rb
58
+ test/test_hash.rb
59
+ test/test_kernel.rb
60
+ test/test_misc.rb
61
+ test/test_module.rb
62
+ test/test_object.rb
63
+ test/test_objectstats.rb
64
+ test/test_unbound_method.rb
@@ -0,0 +1,44 @@
1
+ Utilrb
2
+ http://utilrb.rubyforge.org
3
+ http://www.laas.fr/~sjoyeux/darcs/utilrb
4
+ http://www.laas.fr/~sjoyeux/research.php
5
+
6
+ Copyright (c) 2006
7
+ Sylvain Joyeux <sylvain.joyeux@m4x.org>
8
+ LAAS/CNRS <openrobots@laas.fr>
9
+
10
+ This work is licensed under the BSD license. See License.txt for details
11
+
12
+ == What is Utilrb ?
13
+ Utilrb is yet another Ruby toolkit, in the spirit of facets. It includes all
14
+ the standard class extensions I use in my own projects like Genom.rb.
15
+
16
+ == Utilrb's C extension
17
+ Utilrb includes a C extension in ext/. It is optional, but some of the
18
+ functionalities will be disabled if it is not present. Trying to require
19
+ a file in which there is a C-only feature will yield a warning on STDOUT.
20
+
21
+ * some features have a Ruby version, but a C version is provided for
22
+ performance:
23
+ - Enumerable#each_uniq
24
+
25
+ * some features are C-only
26
+ - ValueSet class
27
+ - Kernel#swap!
28
+
29
+ The environment variable <tt>UTILRB_FASTER_MODE</tt> controls the extension
30
+ loading. Set it to +no+ to disable the extension, to +yes+ to force it
31
+ (an error is generated if the extension is not available). If the variable
32
+ is not set, the extension is loaded if available.
33
+
34
+ == TODO
35
+ * put the +block+ argument in front in Module#define_method_with_block. This
36
+ would allow to do
37
+
38
+ define_method_with_block(:bla) do |block, *args|
39
+ end
40
+
41
+ [DONE 20061101125259-1e605-fef189550540b8e096f0bbe6c219d892bf3e13fc.gz]
42
+
43
+ == CHANGES
44
+ :include: Changes.txt
@@ -0,0 +1,46 @@
1
+ require 'hoe'
2
+ require './lib/utilrb/common'
3
+
4
+ Hoe.new('utilrb', Utilrb::VERSION) do |p|
5
+ p.author = "Sylvain Joyeux"
6
+ p.email = "sylvain.joyeux@m4x.org"
7
+
8
+ p.summary = 'Yet another Ruby toolkit'
9
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
10
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
11
+ p.changes = p.paragraphs_of('Changes.txt', 0..1).join("\n\n")
12
+
13
+ p.extra_deps = ['facets']
14
+ end
15
+
16
+ task :full_test do
17
+ ENV['UTILRB_FASTER_MODE'] = 'no'
18
+ system("testrb test/")
19
+ ENV['UTILRB_FASTER_MODE'] = 'yes'
20
+ system("testrb test/")
21
+ end
22
+
23
+ task :rcov_test do
24
+ Dir.chdir('test') do
25
+ if !File.directory?('../rcov')
26
+ File.mkdir('../rcov')
27
+ end
28
+ File.open("../rcov/index.html", "w") do |index|
29
+ index.puts <<-EOF
30
+ <!DOCTYPE html PUBLIC
31
+ "-//W3C//DTD XHTML 1.0 Transitional//EN"
32
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
33
+ <body>
34
+ EOF
35
+
36
+ Dir.glob('test_*.rb').each do |path|
37
+ puts "\n" * 4 + "=" * 5 + " #{path} " + "=" * 5 + "\n"
38
+ basename = File.basename(path, '.rb')
39
+ system("rcov --replace-progname -o ../rcov/#{basename} #{path}")
40
+ index.puts "<div class=\"test\"><a href=\"#{basename}/index.html\">#{basename}</a></div>"
41
+ end
42
+ index.puts "</body>"
43
+ end
44
+ end
45
+ end
46
+
@@ -0,0 +1,7 @@
1
+ require 'utilrb'
2
+ require 'pp'
3
+
4
+ STDERR.puts "== Enumerable#each_uniq =="
5
+ test_array = 10000.enum_for(:times).map { rand(10) }
6
+ pp ObjectStats.profile { test_array.each_uniq { } }
7
+
@@ -0,0 +1,19 @@
1
+ require 'benchmark'
2
+ require 'utilrb'
3
+
4
+ STDERR.puts "== Enumerable#each_uniq =="
5
+ test_arrays = []
6
+ 1000.times {
7
+ new = []
8
+ 1000.times { new << rand(10) }
9
+ test_arrays << new
10
+ }
11
+
12
+ Benchmark.bm(7) do |x|
13
+ x.report('each_uniq') do
14
+ test_arrays.each do |test|
15
+ test.each_uniq { }
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,5 @@
1
+ require 'mkmf'
2
+ CONFIG['CC'] = "g++"
3
+ $LDFLAGS += "-module"
4
+ create_makefile("faster")
5
+
@@ -0,0 +1,48 @@
1
+ #include <ruby.h>
2
+ #include <set>
3
+
4
+ using namespace std;
5
+
6
+ static VALUE enumerable_each_uniq_i(VALUE i, VALUE* memo)
7
+ {
8
+ set<VALUE>& seen = *reinterpret_cast< set<VALUE>* >(memo);
9
+ if (seen.find(i) == seen.end())
10
+ {
11
+ seen.insert(i);
12
+ return rb_yield(i);
13
+ }
14
+ else
15
+ return Qnil;
16
+
17
+ }
18
+
19
+ /* :nodoc: */
20
+ static VALUE enumerable_each_uniq(VALUE self)
21
+ {
22
+ set<VALUE> seen;
23
+ rb_iterate(rb_each, self,
24
+ RUBY_METHOD_FUNC(enumerable_each_uniq_i), (VALUE)&seen);
25
+ return self;
26
+ }
27
+
28
+ /* Returns true if +self+ is a singleton class */
29
+ static VALUE kernel_is_singleton_p(VALUE self)
30
+ {
31
+ if (BUILTIN_TYPE(self) == T_CLASS && FL_TEST(self, FL_SINGLETON))
32
+ return Qtrue;
33
+ else
34
+ return Qfalse;
35
+ }
36
+
37
+ extern "C" void Init_value_set();
38
+ extern "C" void Init_swap();
39
+
40
+ extern "C" void Init_faster()
41
+ {
42
+ rb_define_method(rb_mEnumerable, "each_uniq", RUBY_METHOD_FUNC(enumerable_each_uniq), 0);
43
+ rb_define_method(rb_mKernel, "is_singleton?", RUBY_METHOD_FUNC(kernel_is_singleton_p), 0);
44
+
45
+ Init_value_set();
46
+ Init_swap();
47
+ }
48
+
@@ -0,0 +1,61 @@
1
+ #include <ruby.h>
2
+ #include <intern.h>
3
+ #include <node.h>
4
+ #include <re.h>
5
+ #include <env.h>
6
+
7
+ typedef struct RVALUE {
8
+ union {
9
+ struct {
10
+ unsigned long flags; /* always 0 for freed obj */
11
+ struct RVALUE *next;
12
+ } free;
13
+ struct RBasic basic;
14
+ struct RObject object;
15
+ struct RClass klass;
16
+ struct RFloat flonum;
17
+ struct RString string;
18
+ struct RArray array;
19
+ struct RRegexp regexp;
20
+ struct RHash hash;
21
+ struct RData data;
22
+ struct RStruct rstruct;
23
+ struct RBignum bignum;
24
+ struct RFile file;
25
+ struct RNode node;
26
+ struct RMatch match;
27
+ struct RVarmap varmap;
28
+ struct SCOPE scope;
29
+ } as;
30
+ #ifdef GC_DEBUG
31
+ char *file;
32
+ int line;
33
+ #endif
34
+ } RVALUE;
35
+ static const size_t SLOT_SIZE = sizeof(RVALUE);
36
+
37
+ /*
38
+ * Kernel.swap!(obj1, obj2, *args)
39
+ *
40
+ * Swaps the object which are being hold by obj1 and obj2.
41
+ *
42
+ * WARNING: I don't know if this can be called in a method of +obj1+ or +obj2+
43
+ */
44
+ static VALUE kernel_swap_bang(VALUE self, VALUE obj1, VALUE obj2)
45
+ {
46
+ // Save the definition of the old object
47
+ RVALUE old_obj;
48
+ memcpy(&old_obj, reinterpret_cast<void*>(obj1), SLOT_SIZE);
49
+ // Place the definition of the new object in the slot of the old one
50
+ memcpy(reinterpret_cast<void*>(obj1), reinterpret_cast<void*>(obj2), SLOT_SIZE);
51
+ // Place the definition of the old object in the slot of the new one
52
+ memcpy(reinterpret_cast<void*>(obj2), &old_obj, SLOT_SIZE);
53
+
54
+ return Qnil;
55
+ }
56
+
57
+ extern "C" void Init_swap()
58
+ {
59
+ rb_define_singleton_method(rb_mKernel, "swap!", RUBY_METHOD_FUNC(kernel_swap_bang), 2);
60
+ }
61
+
@@ -0,0 +1,290 @@
1
+ #include <ruby.h>
2
+ #include <set>
3
+ #include <algorithm>
4
+
5
+ #include <boost/tuple/tuple.hpp>
6
+
7
+ using namespace boost;
8
+ using namespace std;
9
+
10
+ static VALUE cValueSet;
11
+ static ID id_new;
12
+ static ID id_to_value_set;
13
+
14
+ typedef std::set<VALUE> ValueSet;
15
+ static ValueSet& get_wrapped_set(VALUE self)
16
+ {
17
+ ValueSet* object = 0;
18
+ Data_Get_Struct(self, ValueSet, object);
19
+ return *object;
20
+ }
21
+
22
+ static void value_set_mark(ValueSet const* set) { std::for_each(set->begin(), set->end(), rb_gc_mark); }
23
+ static void value_set_free(ValueSet const* set) { delete set; }
24
+ static VALUE value_set_alloc(VALUE klass)
25
+ {
26
+ ValueSet* cxx_set = new ValueSet;
27
+ return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
28
+ }
29
+ /* call-seq:
30
+ * set.empty? => true or false
31
+ *
32
+ * Checks if this set is empty
33
+ */
34
+ static VALUE value_set_empty_p(VALUE self)
35
+ {
36
+ ValueSet& set = get_wrapped_set(self);
37
+ return set.empty() ? Qtrue : Qfalse;
38
+ }
39
+
40
+ /* call-seq:
41
+ * set.size => size
42
+ *
43
+ * Returns this set size
44
+ */
45
+ static VALUE value_set_size(VALUE self)
46
+ {
47
+ ValueSet& set = get_wrapped_set(self);
48
+ return INT2NUM(set.size());
49
+ }
50
+
51
+
52
+ /* call-seq:
53
+ * set.each { |obj| ... } => set
54
+ *
55
+ */
56
+ static VALUE value_set_each(VALUE self)
57
+ {
58
+ ValueSet& set = get_wrapped_set(self);
59
+ for (ValueSet::iterator it = set.begin(); it != set.end();)
60
+ {
61
+ // Increment before calling yield() so that
62
+ // the current element can be deleted safely
63
+ ValueSet::iterator this_it = it++;
64
+ rb_yield(*this_it);
65
+ }
66
+ return self;
67
+ }
68
+ /* call-seq:
69
+ * set.include?(value) => true or false
70
+ *
71
+ * Checks if +value+ is in +set+
72
+ */
73
+ static VALUE value_set_include_p(VALUE vself, VALUE vother)
74
+ {
75
+ ValueSet const& self = get_wrapped_set(vself);
76
+ return self.find(vother) == self.end() ? Qfalse : Qtrue;
77
+ }
78
+
79
+ /* call-seq:
80
+ * set.to_value_set => set
81
+ */
82
+ static VALUE value_set_to_value_set(VALUE self) { return self; }
83
+
84
+ /* call-seq:
85
+ * set.include_all?(other) => true or false
86
+ *
87
+ * Checks if all elements of +other+ are in +set+
88
+ */
89
+ static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
90
+ {
91
+ ValueSet const& self = get_wrapped_set(vself);
92
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
93
+ return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
94
+ }
95
+
96
+ /* call-seq:
97
+ * set.union(other) => union_set
98
+ * set | other => union_set
99
+ *
100
+ * Computes the union of +set+ and +other+. This operation is O(N + M)
101
+ * is +other+ is a ValueSet
102
+ */
103
+ static VALUE value_set_union(VALUE vself, VALUE vother)
104
+ {
105
+ ValueSet const& self = get_wrapped_set(vself);
106
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
107
+
108
+ VALUE vresult = rb_funcall(cValueSet, id_new, 0);
109
+ ValueSet& result = get_wrapped_set(vresult);
110
+ std::set_union(self.begin(), self.end(), other.begin(), other.end(),
111
+ std::inserter(result, result.end()));
112
+ return vresult;
113
+ }
114
+
115
+ /* call-seq:
116
+ * set.merge(other) => set
117
+ *
118
+ * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
119
+ */
120
+ static VALUE value_set_merge(VALUE vself, VALUE vother)
121
+ {
122
+ ValueSet& self = get_wrapped_set(vself);
123
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
124
+
125
+ self.insert(other.begin(), other.end());
126
+ return vself;
127
+ }
128
+
129
+ /* call-seq:
130
+ * set.intersection(other) => intersection_set
131
+ * set & other => intersection_set
132
+ *
133
+ * Computes the intersection of +set+ and +other+. This operation
134
+ * is O(N + M) if +other+ is a ValueSet
135
+ */
136
+ static VALUE value_set_intersection(VALUE vself, VALUE vother)
137
+ {
138
+ ValueSet const& self = get_wrapped_set(vself);
139
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
140
+
141
+ VALUE vresult = rb_funcall(cValueSet, id_new, 0);
142
+ ValueSet& result = get_wrapped_set(vresult);
143
+ std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
144
+ std::inserter(result, result.end()));
145
+ return vresult;
146
+ }
147
+ /* call-seq:
148
+ * set.difference(other) => difference_set
149
+ * set - other => difference_set
150
+ *
151
+ * Computes the set of all elements of +set+ not in +other+. This operation
152
+ * is O(N + M) if +other+ is a ValueSet
153
+ */
154
+ static VALUE value_set_difference(VALUE vself, VALUE vother)
155
+ {
156
+ ValueSet const& self = get_wrapped_set(vself);
157
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
158
+
159
+ VALUE vresult = rb_funcall(cValueSet, id_new, 0);
160
+ ValueSet& result = get_wrapped_set(vresult);
161
+ std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
162
+ std::inserter(result, result.end()));
163
+ return vresult;
164
+ }
165
+
166
+ /* call-seq:
167
+ * set.insert(value) => true or false
168
+ *
169
+ * Inserts +value+ into +set+. Returns true if the value did not exist
170
+ * in the set yet (it has actually been inserted), and false otherwise.
171
+ * This operation is O(log N)
172
+ */
173
+ static VALUE value_set_insert(VALUE vself, VALUE v)
174
+ {
175
+ ValueSet& self = get_wrapped_set(vself);
176
+ bool exists;
177
+ tie(tuples::ignore, exists) = self.insert(v);
178
+ return exists ? Qtrue : Qfalse;
179
+ }
180
+ /* call-seq:
181
+ * set.delete(value) => true or false
182
+ *
183
+ * Removes +value+ from +set+. Returns true if the value did exist
184
+ * in the set yet (it has actually been removed), and false otherwise.
185
+ */
186
+ static VALUE value_set_delete(VALUE vself, VALUE v)
187
+ {
188
+ ValueSet& self = get_wrapped_set(vself);
189
+ size_t count = self.erase(v);
190
+ return count > 0 ? Qtrue : Qfalse;
191
+ }
192
+
193
+ /* call-seq:
194
+ * set == other => true or false
195
+ *
196
+ * Equality
197
+ */
198
+ static VALUE value_set_equal(VALUE vself, VALUE vother)
199
+ {
200
+ ValueSet const& self = get_wrapped_set(vself);
201
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
202
+ return (self == other) ? Qtrue : Qfalse;
203
+ }
204
+
205
+ /* call-seq:
206
+ * set.clear => set
207
+ *
208
+ * Remove all elements of this set
209
+ */
210
+ static VALUE value_set_clear(VALUE self)
211
+ {
212
+ get_wrapped_set(self).clear();
213
+ return self;
214
+ }
215
+
216
+ /* call-seq:
217
+ * set.initialize_copy(other) => set
218
+ *
219
+ * Initializes +set+ with the values in +other+. Needed by #dup
220
+ */
221
+ static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
222
+ {
223
+ ValueSet const& other = get_wrapped_set(rb_funcall(vother, id_to_value_set, 0));
224
+ set<VALUE> new_set(other.begin(), other.end());
225
+ get_wrapped_set(vself).swap(new_set);
226
+ return vself;
227
+ }
228
+
229
+
230
+
231
+
232
+
233
+
234
+
235
+ static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
236
+ {
237
+ ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
238
+ result.insert(i);
239
+ return Qnil;
240
+ }
241
+
242
+ /* call-seq:
243
+ * enum.to_value_set => value_set
244
+ *
245
+ * Builds a ValueSet object from this enumerable
246
+ */
247
+ static VALUE enumerable_to_value_set(VALUE self)
248
+ {
249
+ VALUE vresult = rb_funcall(cValueSet, id_new, 0);
250
+ ValueSet& result = get_wrapped_set(vresult);
251
+
252
+ rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
253
+ return vresult;
254
+ }
255
+
256
+ /*
257
+ * Document-class: ValueSet
258
+ *
259
+ * ValueSet is a wrapper around the C++ set<> template. set<> is an ordered container,
260
+ * for which union(), intersection() and difference() is done in linear time. For performance
261
+ * reasons, in the case of ValueSet, the values are ordered by their VALUE, which roughly is
262
+ * their object_id.
263
+ */
264
+
265
+ extern "C" void Init_value_set()
266
+ {
267
+ rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);
268
+
269
+ cValueSet = rb_define_class("ValueSet", rb_cObject);
270
+ id_new = rb_intern("new");
271
+ id_to_value_set = rb_intern("to_value_set");
272
+ rb_define_alloc_func(cValueSet, value_set_alloc);
273
+ rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
274
+ rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
275
+ rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
276
+ rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
277
+ rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
278
+ rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
279
+ rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
280
+ rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
281
+ rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
282
+ rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
283
+ rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
284
+ rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
285
+ rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
286
+ rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
287
+ rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
288
+ }
289
+
290
+