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