On 3/13/07, Trans <transfire / gmail.com> wrote:
Two approaches with a benchmark.

And as I surmised, there's a really quick way to do this with a
relatively simple extension (at least for ruby1.8, I haven't looked at
this on 1.9).

rick@frodo:/public/rubyscripts/getsinginst$ cat get_sing_inst.c
#include "ruby.h"

static VALUE singleton_instance(VALUE obj)
{
  if (BUILTIN_TYPE(obj) == T_CLASS && FL_TEST(obj, FL_SINGLETON)) {
      return rb_iv_get(obj, "__attached__");
  }
  rb_raise(rb_eTypeError, "not a singleton class");
}

void Init_get_sing_inst()
{
  rb_define_method(rb_cClass, "singleton_instance", singleton_instance, 0);

}

rick@frodo:/public/rubyscripts/getsinginst$ cat gsi.rb
require 'get_sing_inst'

h = {:a => 1}
sc = class << h
    def foo
    end

    self
   end

p sc.singleton_instance
p sc.singleton_instance.object_id == h.object_id

def instance_of_singleton_class_1(sc)
    ObjectSpace.each_object(sc) do |obj|
      return obj
    end
  end

  def instance_of_singleton_class_2(sc)
    obj = nil
    sc.class_eval do
      if instance_methods(false).include?("singleton_method_added")
        org = instance_method("singleton_method_added")
        remove_method("singleton_method_added")
      end
      define_method("singleton_method_added") do |m|
        obj = self
      end
      remove_method("singleton_method_added")
      define_method("singleton_method_added", org) if org
    end
    obj
  end

require "benchmark"

  Benchmark.bmbm do |bm|
    bm.report "ObjectSpace" do
      10000.times do instance_of_singleton_class_1(sc) end
    end
    bm.report "singleton_method_added" do
      10000.times do instance_of_singleton_class_2(sc) end
    end
    bm.report "primitive" do
      10000.times do sc.singleton_instance end
    end
  end


And now for the benchmark results,  note that I'm doing 10 times as
many interations as Trans did, 10000 vs. 1000, the primitive is on the
order of two orders of magnitude faster than either of the other
approaches.

rick@frodo:/public/rubyscripts/getsinginst$ ruby gsi.rb
{:a=>1}
true
Rehearsal ----------------------------------------------------------
ObjectSpace              3.270000   0.100000   3.370000 (  3.469175)
singleton_method_added   4.450000   0.110000   4.560000 (  4.580452)
primitive                0.040000   0.000000   0.040000 (  0.046098)
------------------------------------------------- total: 7.970000sec

                             user     system      total        real
ObjectSpace              2.300000   0.050000   2.350000 (  2.352730)
singleton_method_added   4.430000   0.070000   4.500000 (  4.510719)
primitive                0.040000   0.000000   0.040000 (  0.037970)


-- 
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/