Initial commit

This commit is contained in:
yui-knk
2014-07-24 08:15:57 +09:00
commit 500bd30d6c
10 changed files with 935 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
language: c
compiler:
- gcc
- clang
before_install:
- sudo apt-get -qq update
install:
- sudo apt-get -qq install rake bison git gperf
before_script:
- cd ../
- git clone https://github.com/mruby/mruby.git
- cd mruby
- cp -fp ../mruby-set/.travis_build_config.rb build_config.rb
script:
- make all test
+5
View File
@@ -0,0 +1,5 @@
MRuby::Build.new do |conf|
toolchain :gcc
conf.gembox 'default'
conf.gem '../mruby-set'
end
+25
View File
@@ -0,0 +1,25 @@
mruby-set
Copyright (c) yui-knk 2014
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+27
View File
@@ -0,0 +1,27 @@
# mruby-set [![Build Status](https://travis-ci.org/yui-knk/mruby-set.png?branch=master)](https://travis-ci.org/yui-knk/mruby-set)
Set class
## install by mrbgems
- add conf.gem line to `build_config.rb`
```ruby
MRuby::Build.new do |conf|
# ... (snip) ...
conf.gem :git => 'https://github.com/yui-knk/mruby-set.git'
end
```
## example
```ruby
p Set.hi
#=> "hi!!"
t = Set.new "hello"
p t.hello
#=> "hello"
p t.bye
#=> "hello bye"
```
## License
under the MIT License:
- see LICENSE file
+4
View File
@@ -0,0 +1,4 @@
MRuby::Gem::Specification.new('mruby-set') do |spec|
spec.license = 'MIT'
spec.authors = 'yui-knk'
end
+270
View File
@@ -0,0 +1,270 @@
class Set
include Enumerable
def self.[](*ary)
new(ary)
end
def initialize(enum = nil, &block)
@hash ||= Hash.new
enum.nil? and return
if block_given?
do_with_enum(enum) { |o| add(block.call(o)) }
else
merge(enum)
end
end
def do_with_enum(enum, &block)
if enum.respond_to?(:each)
enum.each(&block)
else
raise ArgumentError, "value must be enumerable"
end
end
private :do_with_enum
def initialize_copy(orig)
super
@hash = orig.instance_variable_get(:@hash).dup
end
# def initialize_dup(orig)
# super
# @hash = orig.instance_variable_get(:@hash).dup
# end
# def initialize_clone(orig)
# super
# @hash = orig.instance_variable_get(:@hash).clone
# end
def freeze
@hash.freeze
super
end
def taint
@hash.taint
super
end
def untaint
@hash.untaint
super
end
def size
@hash.size
end
alias length size
def empty?
@hash.empty?
end
def clear
@hash.clear
self
end
def replace(enum)
clear
merge(enum)
end
def to_a
@hash.keys
end
# def to_set
# end
#
# def flatten_merge
# end
#
# def flatten
# end
#
# def flatten!
# end
def include?(o)
@hash.include?(o)
end
alias member? include?
def superset?(set)
raise ArgumentError, "value must be a set" unless set.is_a?(Set)
return false if size < set.size
set.all? { |o| include?(o) }
end
alias >= superset?
def proper_superset?(set)
raise ArgumentError, "value must be a set" unless set.is_a?(Set)
return false if size <= set.size
set.all? { |o| include?(o) }
end
alias > proper_superset?
def subset?(set)
raise ArgumentError, "value must be a set" unless set.is_a?(Set)
set.superset?(self)
end
alias <= subset?
def proper_subset?(set)
raise ArgumentError, "value must be a set" unless set.is_a?(Set)
set.proper_superset?(self)
end
alias < proper_subset?
def intersect?(set)
raise ArgumentError, "value must be a set" unless set.is_a?(Set)
if size < set.size
any? { |o| set.include?(o) }
else
set.any? { |o| include?(o) }
end
end
def disjoint?(set)
!intersect?(set)
end
def each(&block)
return to_enum :each unless block_given?
@hash.each_key(&block)
self
end
def add(o)
@hash[o] = true
self
end
alias << add
def add?(o)
if include?(o)
nil
else
add(o)
end
end
def delete(o)
@hash.delete(o)
self
end
def delete?(o)
if include?(o)
delete(o)
else
nil
end
end
def delete_if
return to_enum :delete_if unless block_given?
select { |o| yield o }.each { |o| @hash.delete(o) }
self
end
def keep_if
return to_enum :keep_if unless block_given?
reject { |o| yield o }.each { |o| @hash.delete(o) }
self
end
def collect!
return to_enum :collect! unless block_given?
set = self.class.new
each { |o| set << yield(o) }
replace(set)
end
alias map! collect!
def reject!(&block)
return to_enum :reject! unless block_given?
n = size
delete_if(&block)
size == n ? nil : self
end
def select!(&block)
return to_enum :select! unless block_given?
n = size
keep_if(&block)
size == n ? nil : self
end
def merge(enum)
if enum.instance_of?(self.class)
@hash.merge!(enum.instance_variable_get(:@hash))
else
do_with_enum(enum) { |o| add(o) }
end
self
end
def subtract(enum)
do_with_enum(enum) { |o| delete(o) }
self
end
def |(enum)
dup.merge(enum)
end
alias + |
alias union |
def -(enum)
dup.subtract(enum)
end
alias difference -
def &(enum)
n = Set.new
do_with_enum(enum) { |o| n.add(o) if include?(o) }
n
end
alias intersection &
def ^(enum)
(self | Set.new(enum)) - (self & Set.new(enum))
end
def ==(other)
if self.equal?(other)
true
elsif other.instance_of?(self.class) && self.size == other.size
other_hash = other.instance_variable_get(:@hash)
other_hash.keys.all? { |o| @hash.keys.include?(o) }
other_hash.values.all? { |o| @hash.values.include?(o) }
# @hash == other.instance_variable_get(:@hash)
elsif other.is_a?(self.class) && self.size == other.size
other.all? { |o| include?(o) }
else
false
end
end
def hash
@hash.hash
end
def eql?(o)
return false unless o.is_a?(Set)
@hash.eql?(o.instance_variable_get(:@hash))
end
def inspect
sprintf('#<%s: {%s}>', self.class, to_a.inspect[1..-2])
end
end
+6
View File
@@ -0,0 +1,6 @@
name: mruby-set
description: Set class
author: yui-knk
website: https://github.com/yui-knk/mruby-set
protocol: git
repository: https://github.com/yui-knk/mruby-set.git
+71
View File
@@ -0,0 +1,71 @@
/*
** mrb_set.c - Set class
**
** Copyright (c) yui-knk 2014
**
** See Copyright Notice in LICENSE
*/
#include "mruby.h"
#include "mruby/data.h"
#include "mrb_set.h"
#define DONE mrb_gc_arena_restore(mrb, 0);
typedef struct {
char *str;
int len;
} mrb_set_data;
static const struct mrb_data_type mrb_set_data_type = {
"mrb_set_data", mrb_free,
};
static mrb_value mrb_set_init(mrb_state *mrb, mrb_value self)
{
mrb_set_data *data;
char *str;
int len;
data = (mrb_set_data *)DATA_PTR(self);
if (data) {
mrb_free(mrb, data);
}
DATA_TYPE(self) = &mrb_set_data_type;
DATA_PTR(self) = NULL;
mrb_get_args(mrb, "s", &str, &len);
data = (mrb_set_data *)mrb_malloc(mrb, sizeof(mrb_set_data));
data->str = str;
data->len = len;
DATA_PTR(self) = data;
return self;
}
static mrb_value mrb_set_hello(mrb_state *mrb, mrb_value self)
{
mrb_set_data *data = DATA_PTR(self);
return mrb_str_new(mrb, data->str, data->len);
}
static mrb_value mrb_set_hi(mrb_state *mrb, mrb_value self)
{
return mrb_str_new_cstr(mrb, "hi!!");
}
void mrb_mruby_set_gem_init(mrb_state *mrb)
{
struct RClass *set;
set = mrb_define_class(mrb, "Set", mrb->object_class);
mrb_define_method(mrb, set, "initialize", mrb_set_init, MRB_ARGS_REQ(1));
mrb_define_method(mrb, set, "hello", mrb_set_hello, MRB_ARGS_NONE());
mrb_define_class_method(mrb, set, "hi", mrb_set_hi, MRB_ARGS_NONE());
DONE;
}
void mrb_mruby_set_gem_final(mrb_state *mrb)
{
}
+12
View File
@@ -0,0 +1,12 @@
/*
** mrb_set.h - Set class
**
** See Copyright Notice in LICENSE
*/
#ifndef MRB_SET_H
#define MRB_SET_H
void mrb_mruby_set_gem_init(mrb_state *mrb);
#endif
+500
View File
@@ -0,0 +1,500 @@
##
## Set Test
##
assert("Set.new") do
assert_nothing_raised {
Set.new()
Set.new(nil)
Set.new([])
Set.new([1,2])
Set.new(1..3)
}
assert_raise(ArgumentError) { Set.new(false) }
assert_raise(ArgumentError) { Set.new(1) }
assert_raise(ArgumentError) { Set.new(1,2) }
ary = [2,4,6,4]
set = Set.new(ary)
ary.clear
assert_false set.empty?
assert_equal(3, set.size)
ary = [1,2,3]
s = Set.new(ary) { |o| o * 2 }
assert_equal([2,4,6], s.sort)
end
assert("Set.[]") do
assert_nothing_raised {
Set[]
Set[nil]
Set[[]]
Set[[1,2]]
Set['a'..'c']
Set[false]
Set[1]
Set[1,2]
}
ary = [2,4,6,4]
set = Set[ary]
ary.clear
assert_false set.empty?
assert_equal([[]], set.to_a)
end
assert("Set#clone") do
set1 = Set.new
set2 = set1.clone
assert_false set1.equal?(set2) # assert_not_same
assert_equal(set1, set2)
set1 << 'abc'
assert_equal(Set.new, set2)
end
assert("Set#dup") do
set1 = Set[1,2]
set2 = set1.dup
assert_false set1.equal?(set2) # assert_not_same
assert_equal(set1, set2)
set1 << 'abc'
assert_equal(Set[1,2], set2)
end
assert("Set#size") do
assert_equal(0, Set[].size)
assert_equal(1, Set[nil].size)
assert_equal(1, Set[[]].size)
assert_equal(1, Set[[nil]].size)
end
assert("Set#empty?") do
assert_true Set[].empty?
assert_false Set[1,2].empty?
end
assert("Set#clear") do
set = Set[1,2]
ret = set.clear
assert_true set.equal?(ret) # assert_same
assert_true set.empty?
end
assert("Set#replace") do
set = Set[1,2]
ret = set.replace(['a','b','c'])
assert_true set.equal?(ret) # assert_same
assert_equal(Set['a','b','c'], set)
set = Set[1,2]
ret = set.replace(Set['a','b','c'])
assert_true set.equal?(ret) # assert_same
assert_equal(Set['a','b','c'], set)
end
assert("Set#to_a") do
set = Set[1,2,3,2]
ary = set.to_a
assert_equal([1,2,3], ary.sort)
end
#assert("Set#flatten") do
#end
assert("Set#include?") do
set = Set[1,2,3]
assert_true set.include?(1)
assert_true set.include?(2)
assert_true set.include?(3)
assert_false set.include?(0)
assert_false set.include?(nil)
set = Set["1",nil,"2",nil,"0","1",false]
assert_true set.include?(nil)
assert_true set.include?(false)
assert_true set.include?("1")
assert_false set.include?(0)
assert_false set.include?(true)
assert_false set.include?(2)
end
assert("Set#superset?") do
set = Set[1,2,3]
assert_raise(ArgumentError) { set.superset?(nil) }
assert_raise(ArgumentError) { set.superset?(2) }
assert_raise(ArgumentError) { set.superset?([2]) }
assert_true set.superset?(Set[])
assert_true set.superset?(Set[1,2])
assert_true set.superset?(Set[1,2,3])
assert_false set.superset?(Set[1,2,3,4])
assert_false set.superset?(Set[1,4])
assert_true set >= Set[1,2]
assert_true set >= Set[1,2,3]
assert_true Set[].superset?(Set[])
end
assert("Set#proper_superset?") do
set = Set[1,2,3]
assert_raise(ArgumentError) { set.proper_superset?(nil) }
assert_raise(ArgumentError) { set.proper_superset?(2) }
assert_raise(ArgumentError) { set.proper_superset?([2]) }
assert_true set.proper_superset?(Set[])
assert_true set.proper_superset?(Set[1,2])
assert_false set.proper_superset?(Set[1,2,3])
assert_false set.proper_superset?(Set[1,2,3,4])
assert_false set.proper_superset?(Set[1,4])
assert_true set > Set[1,2]
assert_false set > Set[1,2,3]
assert_false Set[].proper_superset?(Set[])
end
assert("Set#subset?") do
set = Set[1,2,3]
assert_raise(ArgumentError) { set.subset?(nil) }
assert_raise(ArgumentError) { set.subset?(2) }
assert_raise(ArgumentError) { set.subset?([2]) }
assert_true set.subset?(Set[1,2,3,4])
assert_true set.subset?(Set[1,2,3])
assert_false set.subset?(Set[1,2])
assert_false set.subset?(Set[])
assert_true set <= Set[1,2,3]
assert_false set <= Set[1,2]
assert_true Set[].subset?(Set[1])
assert_true Set[].subset?(Set[])
end
assert("Set#proper_subset?") do
set = Set[1,2,3]
assert_raise(ArgumentError) { set.proper_subset?(nil) }
assert_raise(ArgumentError) { set.proper_subset?(2) }
assert_raise(ArgumentError) { set.proper_subset?([2]) }
assert_true set.proper_subset?(Set[1,2,3,4])
assert_false set.proper_subset?(Set[1,2,3])
assert_false set.proper_subset?(Set[1,2])
assert_false set.proper_subset?(Set[])
assert_true set < Set[1,2,3,4]
assert_false set < Set[1,2,3]
assert_true Set[].proper_subset?(Set[1])
assert_false Set[].proper_subset?(Set[])
end
assert("Set#intersect?") do
set = Set[3,4,5]
assert_raise(ArgumentError) { set.intersect?(3) }
assert_raise(ArgumentError) { set.intersect?([2,4,6]) }
assert_true set.intersect?(set)
assert_true set.intersect?(Set[2,4])
assert_true set.intersect?(Set[5,6,7])
assert_true set.intersect?(Set[1,2,6,8,4])
assert_false(set.intersect?(Set[]))
assert_false(set.intersect?(Set[0,2]))
assert_false(set.intersect?(Set[0,2,6]))
assert_false(set.intersect?(Set[0,2,6,8,10]))
# Make sure set hasn't changed
assert_equal(Set[3,4,5], set)
end
assert("Set#disjoint?") do
set = Set[3,4,5]
assert_raise(ArgumentError) { set.disjoint?(3) }
assert_raise(ArgumentError) { set.disjoint?([2,4,6]) }
assert_true(set.disjoint?(Set[]))
assert_true(set.disjoint?(Set[0,2]))
assert_true(set.disjoint?(Set[0,2,6]))
assert_true(set.disjoint?(Set[0,2,6,8,10]))
assert_false set.disjoint?(set)
assert_false set.disjoint?(Set[2,4])
assert_false set.disjoint?(Set[5,6,7])
assert_false set.disjoint?(Set[1,2,6,8,4])
# Make sure set hasn't changed
assert_equal(Set[3,4,5], set)
end
assert("Set#each") do
ary = [1,3,5,7,10,20]
set = Set.new(ary)
ret = set.each { |o| }
assert_true set.equal?(ret) # assert_same
e = set.each
assert_true e.instance_of?(Enumerator)
assert_nothing_raised {
set.each { |o|
ary.delete(o) or raise "unexpected element: #{o}"
}
ary.empty? or raise "forgotten elements: #{ary.join(', ')}"
}
end
assert("Set#add") do
set = Set[1,2,3]
ret = set.add(2)
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,3], set)
ret = set.add(4)
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,3,4], set)
end
assert("Set#add?") do
set = Set[1,2,3]
ret = set.add?(2)
assert_nil ret
assert_equal(Set[1,2,3], set)
ret = set.add?(4)
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,3,4], set)
end
assert("Set#delete") do
set = Set[1,2,3]
ret = set.delete(4)
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,3], set)
ret = set.delete(2)
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,3], set)
end
assert("Set#delete?") do
set = Set[1,2,3]
ret = set.delete?(4)
assert_nil ret
assert_equal(Set[1,2,3], set)
ret = set.delete?(1)
assert_true set.equal?(ret) # assert_same
assert_equal(Set[2,3], set)
end
assert("Set#delete_if") do
set = Set.new(1..10)
ret = set.delete_if { |i| i > 10 }
assert_true set.equal?(ret) # assert_same
assert_equal(Set.new(1..10), set)
set = Set.new(1..10)
ret = set.delete_if { |i| i % 3 == 0 }
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,4,5,7,8,10], set)
end
assert("Set#keep_if") do
set = Set.new(1..10)
ret = set.keep_if { |i| i <= 10 }
assert_true set.equal?(ret) # assert_same
assert_equal(Set.new(1..10), set)
set = Set.new(1..10)
ret = set.keep_if { |i| i % 3 != 0 }
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,4,5,7,8,10], set)
end
assert("Set#collect!") do
set = Set[1,2,3,'a','b','c',-1..1,2..4]
ret = set.collect! { |i|
case i
when Numeric
i * 2
when String
i.upcase
else
nil
end
}
assert_true set.equal?(ret) # assert_same
assert_equal(Set[2,4,6,"A","B","C",nil], set)
end
assert("Set#reject!") do
set = Set.new(1..10)
ret = set.reject! { |i| i > 10 }
assert_nil(ret)
assert_equal(Set.new(1..10), set)
ret = set.reject! { |i| i % 3 == 0 }
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,4,5,7,8,10], set)
end
# this test is not in CRuby
assert("Set#select!") do
set = Set.new(1..10)
ret = set.select! { |i| i <= 10 }
assert_nil(ret)
assert_equal(Set.new(1..10), set)
ret = set.select! { |i| i % 3 != 0 }
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,4,5,7,8,10], set)
end
assert("Set#merge") do
set = Set[1,2,3]
ret = set.merge([2,4,6])
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,2,3,4,6], set)
end
assert("Set#subtract") do
set = Set[1,2,3]
ret = set.subtract([2,4,6])
assert_true set.equal?(ret) # assert_same
assert_equal(Set[1,3], set)
end
assert("Set#+") do
set = Set[1,2,3]
ret = set + [2,4,6]
assert_false set.equal?(ret) # assert_not_same
assert_equal(Set[1,2,3,4,6], ret)
end
assert("Set#-") do
set = Set[1,2,3]
ret = set - [2,4,6]
assert_false set.equal?(ret) # assert_not_same
assert_equal(Set[1,3], ret)
end
assert("Set#&") do
set = Set[1,2,3,4]
ret = set & [2,4,6]
assert_false set.equal?(ret) # assert_not_same
assert_equal(Set[2,4], ret)
end
assert("Set#^") do
set = Set[1,2,3,4]
ret = set ^ [2,4,5,5]
assert_false set.equal?(ret) # assert_not_same
assert_equal(Set[1,3,5], ret)
end
assert("Set#==") do
set1 = Set[2,3,1]
set2 = Set[1,2,3]
assert_equal(set1, set1)
assert_equal(set1, set2)
assert_not_equal(Set[1], [1])
set1 = Class.new(Set)["a", "b"]
set2 = Set["a", "b", set1]
set1 = set1.add(set1.clone)
assert_equal(set2, set2.clone)
assert_equal(set1.clone, set1)
end
#assert("Set#classify") do
#end
#
#assert("Set#divide") do
#end
# taint is not implemented yet
#assert("taintness") do
# orig = set = Set[1,2,3]
# assert_false set.tainted?
# assert_true set.taint.equal?(orig) # assert_same
# assert_true set.tainted?
# assert_true set.instance_variable_get(:@hash).tainted?
# assert_true set.untaint.equal?(orig) # assert_same
# assert_false set.tainted?
#end
# freeze is not implemented yet
#assert("freeze") do
# orig = set = Set[1,2,3]
# assert_equal false, set.frozen?
# set << 4
# assert_same orig, set.freeze
# assert_equal true, set.frozen?
# assert_raise(RuntimeError) {
# set << 5
# }
# assert_equal 4, set.size
#end
# assert("freeze_dup") do
# set1 = Set[1,2,3]
# set1.freeze
# set2 = set1.dup
#
# assert_not_predicate set2, :frozen?
# assert_nothing_raised {
# set2.add 4
# }
# end
# assert("reeze_clone") do
# set1 = Set[1,2,3]
# set1.freeze
# set2 = set1.clone
#
# assert_predicate set2, :frozen?
# assert_raise(RuntimeError) {
# set2.add 5
# }
# end
#
#assert("Set#inspect") do
#end