utilrb 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Changes.txt +20 -0
- data/License.txt +26 -0
- data/Manifest.txt +64 -0
- data/README.txt +44 -0
- data/Rakefile +46 -0
- data/bm/allocation.rb +7 -0
- data/bm/speed.rb +19 -0
- data/ext/extconf.rb +5 -0
- data/ext/faster.cc +48 -0
- data/ext/swap.cc +61 -0
- data/ext/value_set.cc +290 -0
- data/lib/utilrb.rb +2 -0
- data/lib/utilrb/array.rb +2 -0
- data/lib/utilrb/array/to_s.rb +16 -0
- data/lib/utilrb/common.rb +50 -0
- data/lib/utilrb/enumerable.rb +2 -0
- data/lib/utilrb/enumerable/null.rb +18 -0
- data/lib/utilrb/enumerable/random_element.rb +16 -0
- data/lib/utilrb/enumerable/sequence.rb +24 -0
- data/lib/utilrb/enumerable/uniq.rb +61 -0
- data/lib/utilrb/exception.rb +2 -0
- data/lib/utilrb/exception/full_message.rb +8 -0
- data/lib/utilrb/gc.rb +2 -0
- data/lib/utilrb/gc/force.rb +11 -0
- data/lib/utilrb/hash.rb +2 -0
- data/lib/utilrb/hash/slice.rb +6 -0
- data/lib/utilrb/hash/to_s.rb +6 -0
- data/lib/utilrb/hash/to_sym_keys.rb +6 -0
- data/lib/utilrb/kernel.rb +2 -0
- data/lib/utilrb/kernel/arity.rb +10 -0
- data/lib/utilrb/kernel/options.rb +69 -0
- data/lib/utilrb/kernel/poll.rb +24 -0
- data/lib/utilrb/kernel/require.rb +12 -0
- data/lib/utilrb/kernel/swap.rb +2 -0
- data/lib/utilrb/logger.rb +3 -0
- data/lib/utilrb/logger/forward.rb +15 -0
- data/lib/utilrb/logger/hierarchy.rb +34 -0
- data/lib/utilrb/module.rb +2 -0
- data/lib/utilrb/module/ancestor_p.rb +6 -0
- data/lib/utilrb/module/attr_enumerable.rb +28 -0
- data/lib/utilrb/module/define_method.rb +30 -0
- data/lib/utilrb/module/include.rb +30 -0
- data/lib/utilrb/module/inherited_enumerable.rb +122 -0
- data/lib/utilrb/object.rb +2 -0
- data/lib/utilrb/object/address.rb +14 -0
- data/lib/utilrb/object/attribute.rb +89 -0
- data/lib/utilrb/object/singleton_class.rb +53 -0
- data/lib/utilrb/objectstats.rb +52 -0
- data/lib/utilrb/time.rb +2 -0
- data/lib/utilrb/time/to_hms.rb +6 -0
- data/lib/utilrb/unbound_method.rb +2 -0
- data/lib/utilrb/unbound_method/call.rb +5 -0
- data/lib/utilrb/value_set.rb +17 -0
- data/test/test_array.rb +9 -0
- data/test/test_config.rb +4 -0
- data/test/test_enumerable.rb +89 -0
- data/test/test_gc.rb +39 -0
- data/test/test_hash.rb +22 -0
- data/test/test_kernel.rb +70 -0
- data/test/test_misc.rb +42 -0
- data/test/test_module.rb +127 -0
- data/test/test_object.rb +65 -0
- data/test/test_objectstats.rb +19 -0
- data/test/test_unbound_method.rb +23 -0
- metadata +128 -0
data/Changes.txt
ADDED
@@ -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
|
+
|
data/License.txt
ADDED
@@ -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.
|
data/Manifest.txt
ADDED
@@ -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
|
data/README.txt
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|
+
|
data/bm/allocation.rb
ADDED
data/bm/speed.rb
ADDED
@@ -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
|
+
|
data/ext/extconf.rb
ADDED
data/ext/faster.cc
ADDED
@@ -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
|
+
|
data/ext/swap.cc
ADDED
@@ -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
|
+
|
data/ext/value_set.cc
ADDED
@@ -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
|
+
|