utilrb 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.
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
+