value_set.cc
Go to the documentation of this file.
00001 #include <ruby.h>
00002 #include <set>
00003 #include <algorithm>
00004 #include "ruby_allocator.hh"
00005 
00006 using namespace std;
00007 
00008 static VALUE cValueSet;
00009 static ID id_new;
00010 
00011 typedef std::set<VALUE, std::less<VALUE>, ruby_allocator<VALUE> > ValueSet;
00012 static ValueSet& get_wrapped_set(VALUE self)
00013 {
00014     ValueSet* object = 0;
00015     Data_Get_Struct(self, ValueSet, object);
00016     return *object;
00017 }
00018 
00019 static void value_set_mark(ValueSet const* set) { std::for_each(set->begin(), set->end(), rb_gc_mark); }
00020 static void value_set_free(ValueSet const* set) { delete set; }
00021 static VALUE value_set_alloc(VALUE klass)
00022 {
00023     ValueSet* cxx_set = new ValueSet;
00024     return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
00025 }
00026 /* call-seq:
00027  *  set.empty?                      => true or false
00028  *
00029  * Checks if this set is empty
00030  */
00031 static VALUE value_set_empty_p(VALUE self)
00032 { 
00033     ValueSet& set = get_wrapped_set(self);
00034     return set.empty() ? Qtrue : Qfalse;
00035 }
00036 
00037 /* call-seq:
00038  *  set.size                        => size
00039  *
00040  * Returns this set size
00041  */
00042 static VALUE value_set_size(VALUE self)
00043 { 
00044     ValueSet& set = get_wrapped_set(self);
00045     return INT2NUM(set.size());
00046 }
00047 
00048 
00049 /* call-seq:
00050  *  set.each { |obj| ... }          => set
00051  *
00052  */
00053 static VALUE value_set_each(VALUE self)
00054 {
00055     ValueSet& set = get_wrapped_set(self);
00056     for (ValueSet::iterator it = set.begin(); it != set.end();)
00057     {
00058         // Increment before calling yield() so that 
00059         // the current element can be deleted safely
00060         ValueSet::iterator this_it = it++;
00061         rb_yield(*this_it);
00062     }
00063     return self;
00064 }
00065 
00066 /* call-seq:
00067  *  set.delete_if { |obj| ... }         => set
00068  *
00069  * Deletes all objects for which the block returns true
00070  */
00071 static VALUE value_set_delete_if(VALUE self)
00072 {
00073     ValueSet& set = get_wrapped_set(self);
00074     for (ValueSet::iterator it = set.begin(); it != set.end();)
00075     {
00076         // Increment before calling yield() so that 
00077         // the current element can be deleted safely
00078         ValueSet::iterator this_it = it++;
00079         bool do_delete = RTEST(rb_yield(*this_it));
00080         if (do_delete)
00081             set.erase(this_it);
00082     }
00083     return self;
00084 }
00085 
00086 /* call-seq:
00087  *  set.include?(value)     => true or false
00088  *
00089  * Checks if +value+ is in +set+
00090  */
00091 static VALUE value_set_include_p(VALUE vself, VALUE vother)
00092 {
00093     ValueSet const& self  = get_wrapped_set(vself);
00094     return self.find(vother) == self.end() ? Qfalse : Qtrue;
00095 }
00096 
00097 /* call-seq:
00098  *  set.to_value_set                => set
00099  */
00100 static VALUE value_set_to_value_set(VALUE self) { return self; }
00101 
00102 /* call-seq:
00103  *  set.dup => other_set
00104  *
00105  * Duplicates this set, without duplicating the pointed-to objects
00106  */
00107 static VALUE value_set_dup(VALUE vself, VALUE vother)
00108 {
00109     ValueSet const& self  = get_wrapped_set(vself);
00110     VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
00111     ValueSet& result = get_wrapped_set(vresult);
00112     for (ValueSet::const_iterator it = self.begin(); it != self.end(); ++it)
00113         result.insert(result.end(), *it);
00114 
00115     return vresult;
00116 }
00117 
00118 /* call-seq:
00119  *  set.include_all?(other)             => true or false
00120  *
00121  * Checks if all elements of +other+ are in +set+
00122  */
00123 static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
00124 {
00125     ValueSet const& self  = get_wrapped_set(vself);
00126     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00127         rb_raise(rb_eArgError, "expected a ValueSet");
00128     ValueSet const& other = get_wrapped_set(vother);
00129     return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
00130 }
00131 
00132 /* call-seq:
00133  *  set.union(other)            => union_set
00134  *  set | other                 => union_set
00135  *
00136  * Computes the union of +set+ and +other+. This operation is O(N + M)
00137  * is +other+ is a ValueSet
00138  */
00139 static VALUE value_set_union(VALUE vself, VALUE vother)
00140 {
00141     ValueSet const& self  = get_wrapped_set(vself);
00142     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00143         rb_raise(rb_eArgError, "expected a ValueSet");
00144     ValueSet const& other = get_wrapped_set(vother);
00145     
00146     VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
00147     ValueSet& result = get_wrapped_set(vresult);
00148     std::set_union(self.begin(), self.end(), other.begin(), other.end(), 
00149             std::inserter(result, result.end()));
00150     return vresult;
00151 }
00152 
00153 /* call-seq:
00154  *  set.merge(other)            => set
00155  *
00156  * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
00157  */
00158 static VALUE value_set_merge(VALUE vself, VALUE vother)
00159 {
00160     ValueSet& self  = get_wrapped_set(vself);
00161     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00162         rb_raise(rb_eArgError, "expected a ValueSet");
00163     ValueSet const& other = get_wrapped_set(vother);
00164     
00165     self.insert(other.begin(), other.end());
00166     return vself;
00167 }
00168 
00169 /* call-seq:
00170  *   set.intersection!(other)   => set
00171  *
00172  * Computes the intersection of +set+ and +other+, and modifies +self+ to be
00173  * that interesection. This operation is O(N + M) if +other+ is a ValueSet
00174  */
00175 static VALUE value_set_intersection_bang(VALUE vself, VALUE vother)
00176 {
00177     ValueSet& self  = get_wrapped_set(vself);
00178     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00179         rb_raise(rb_eArgError, "expected a ValueSet");
00180     ValueSet const& other = get_wrapped_set(vother);
00181     
00182     ValueSet result;
00183     std::set_intersection(self.begin(), self.end(), other.begin(), other.end(), 
00184             std::inserter(result, result.end()));
00185     self.swap(result);
00186     return vself;
00187 }
00188 
00189 /* call-seq:
00190  *   set.intersection(other)    => intersection_set
00191  *   set & other                => intersection_set
00192  *
00193  * Computes the intersection of +set+ and +other+. This operation
00194  * is O(N + M) if +other+ is a ValueSet
00195  */
00196 static VALUE value_set_intersection(VALUE vself, VALUE vother)
00197 {
00198     ValueSet const& self  = get_wrapped_set(vself);
00199     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00200         rb_raise(rb_eArgError, "expected a ValueSet");
00201     ValueSet const& other = get_wrapped_set(vother);
00202     
00203     VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
00204     ValueSet& result = get_wrapped_set(vresult);
00205     std::set_intersection(self.begin(), self.end(), other.begin(), other.end(), 
00206             std::inserter(result, result.end()));
00207     return vresult;
00208 }
00209 
00210 /* call-seq:
00211  *  set.intersects?(other)      => true or false
00212  *
00213  * Returns true if there is elements in +set+ that are also in +other
00214  */
00215 static VALUE value_set_intersects(VALUE vself, VALUE vother)
00216 {
00217     ValueSet const& self  = get_wrapped_set(vself);
00218     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00219         rb_raise(rb_eArgError, "expected a ValueSet");
00220     ValueSet const& other = get_wrapped_set(vother);
00221 
00222     ValueSet::const_iterator 
00223         self_it   = self.begin(),
00224         self_end  = self.end(),
00225         other_it  = other.begin(),
00226         other_end = other.end();
00227 
00228     while(self_it != self_end && other_it != other_end)
00229     {
00230         if (*self_it < *other_it)
00231             ++self_it;
00232         else if (*other_it < *self_it)
00233             ++other_it;
00234         else
00235             return Qtrue;
00236     }
00237     return Qfalse;
00238 }
00239 
00240 /* call-seq:
00241  *   set.difference!(other)     => set
00242  *
00243  * Modifies +set+ so that it is the set of all elements of +set+ not in +other+.
00244  * This operation is O(N + M).
00245  */
00246 static VALUE value_set_difference_bang(VALUE vself, VALUE vother)
00247 {
00248     ValueSet& self  = get_wrapped_set(vself);
00249     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00250         rb_raise(rb_eArgError, "expected a ValueSet");
00251     ValueSet const& other = get_wrapped_set(vother);
00252     
00253     ValueSet result;
00254     std::set_difference(self.begin(), self.end(), other.begin(), other.end(), 
00255             std::inserter(result, result.end()));
00256     if (result.size() != self.size())
00257         self.swap(result);
00258     return vself;
00259 }
00260 
00261 /* call-seq:
00262  *   set.difference(other)      => difference_set
00263  *   set - other                => difference_set
00264  *
00265  * Computes the set of all elements of +set+ not in +other+. This operation
00266  * is O(N + M).
00267  */
00268 static VALUE value_set_difference(VALUE vself, VALUE vother)
00269 {
00270     ValueSet const& self  = get_wrapped_set(vself);
00271     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00272         rb_raise(rb_eArgError, "expected a ValueSet");
00273     ValueSet const& other = get_wrapped_set(vother);
00274     
00275     VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
00276     ValueSet& result = get_wrapped_set(vresult);
00277     std::set_difference(self.begin(), self.end(), other.begin(), other.end(), 
00278             std::inserter(result, result.end()));
00279     return vresult;
00280 }
00281 
00282 /* call-seq:
00283  *  set.insert(value)           => true or false
00284  * 
00285  * Inserts +value+ into +set+. Returns true if the value did not exist
00286  * in the set yet (it has actually been inserted), and false otherwise.
00287  * This operation is O(log N)
00288  */
00289 static VALUE value_set_insert(VALUE vself, VALUE v)
00290 {
00291     ValueSet& self  = get_wrapped_set(vself);
00292     bool exists = self.insert(v).second;
00293     return exists ? Qtrue : Qfalse;
00294 }
00295 /* call-seq:
00296  *  set.delete(value)           => true or false
00297  * 
00298  * Removes +value+ from +set+. Returns true if the value did exist
00299  * in the set yet (it has actually been removed), and false otherwise.
00300  */
00301 static VALUE value_set_delete(VALUE vself, VALUE v)
00302 {
00303     ValueSet& self  = get_wrapped_set(vself);
00304     size_t count = self.erase(v);
00305     return count > 0 ? Qtrue : Qfalse;
00306 }
00307 
00308 /* call-seq:
00309  *  set == other                => true or false
00310  *
00311  * Equality
00312  */
00313 static VALUE value_set_equal(VALUE vself, VALUE vother)
00314 {
00315     ValueSet const& self  = get_wrapped_set(vself);
00316     if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
00317         return Qfalse;
00318     ValueSet const& other = get_wrapped_set(vother);
00319     return (self == other) ? Qtrue : Qfalse;
00320 }
00321 
00322 /* call-seq:
00323  *  set.clear                   => set
00324  *
00325  * Remove all elements of this set
00326  */
00327 static VALUE value_set_clear(VALUE self)
00328 {
00329     get_wrapped_set(self).clear();
00330     return self;
00331 }
00332 
00333 /* call-seq:
00334  *  set.initialize_copy(other)  => set
00335  *
00336  * Initializes +set+ with the values in +other+. Needed by #dup
00337  */
00338 static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
00339 {
00340     get_wrapped_set(vself) = get_wrapped_set(vother);
00341     return vself;
00342 }
00343 
00344 
00345 
00346 
00347 
00348 
00349 
00350 /* call-seq:
00351  *  to_value_set    => value_set
00352  *
00353  * Converts this array into a ValueSet object
00354  */
00355 static VALUE array_to_value_set(VALUE self)
00356 {
00357     VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
00358     ValueSet& result = get_wrapped_set(vresult);
00359 
00360     long size  = RARRAY_LEN(self);
00361     for (int i = 0; i < size; ++i)
00362         result.insert(rb_ary_entry(self, i));
00363 
00364     return vresult;
00365 }
00366 
00367 #ifndef RUBINIUS
00368 static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
00369 {
00370     ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
00371     result.insert(i);
00372     return Qnil;
00373 }
00374 
00375 /* call-seq:
00376  *  enum.to_value_set           => value_set
00377  *
00378  * Builds a ValueSet object from this enumerable
00379  */
00380 static VALUE enumerable_to_value_set(VALUE self)
00381 {
00382     VALUE vresult = rb_funcall2(cValueSet, id_new, 0, NULL);
00383     ValueSet& result = get_wrapped_set(vresult);
00384 
00385     rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
00386     return vresult;
00387 }
00388 #endif
00389 
00390 /*
00391  * Document-class: ValueSet
00392  *
00393  * ValueSet is a wrapper around the C++ set<> template. set<> is an ordered container,
00394  * for which union(), intersection() and difference() is done in linear time. For performance
00395  * reasons, in the case of ValueSet, the values are ordered by their VALUE, which roughly is
00396  * their object_id.
00397  */
00398 
00399 extern "C" void Init_value_set()
00400 {
00401 #ifndef RUBINIUS
00402     rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);
00403 #endif
00404     rb_define_method(rb_cArray, "to_value_set", RUBY_METHOD_FUNC(array_to_value_set), 0);
00405 
00406     cValueSet = rb_define_class("ValueSet", rb_cObject);
00407     id_new = rb_intern("new");
00408     rb_define_alloc_func(cValueSet, value_set_alloc);
00409     rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
00410     rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
00411     rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
00412     rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
00413     rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
00414     rb_define_method(cValueSet, "intersection!", RUBY_METHOD_FUNC(value_set_intersection_bang), 1);
00415     rb_define_method(cValueSet, "intersects?", RUBY_METHOD_FUNC(value_set_intersects), 1);
00416     rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
00417     rb_define_method(cValueSet, "difference!", RUBY_METHOD_FUNC(value_set_difference_bang), 1);
00418     rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
00419     rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
00420     rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
00421     rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
00422     rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
00423     rb_define_method(cValueSet, "dup", RUBY_METHOD_FUNC(value_set_dup), 0);
00424     rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
00425     rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
00426     rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
00427     rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
00428     rb_define_method(cValueSet, "delete_if", RUBY_METHOD_FUNC(value_set_delete_if), 0);
00429 }
00430 
00431 


utilrb
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Sat Jun 8 2019 18:49:20