gem_with_extension_example 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/infinity_check_c/InfinityCheckC.c +44 -0
- data/ext/infinity_check_c/extconf.rb +5 -0
- data/lib/gem_with_extension_example.rb +4 -0
- data/lib/gem_with_extension_example/base.rb +111 -0
- data/lib/gem_with_extension_example/grid.rb +178 -0
- data/lib/gem_with_extension_example/infinity_check_c.bundle +0 -0
- data/lib/gem_with_extension_example/timer.rb +169 -0
- data/lib/gem_with_extension_example/version.rb +9 -0
- metadata +65 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
// Include the Ruby headers and goodies
|
2
|
+
#include "ruby.h"
|
3
|
+
#include "math.h"
|
4
|
+
#include "complex.h"
|
5
|
+
|
6
|
+
// Defining a space for information and references about the module to be stored internally
|
7
|
+
VALUE InfinityCheckC = Qnil;
|
8
|
+
|
9
|
+
// Prototype for the initialization method - Ruby calls this, not you
|
10
|
+
void Init_infinity_check_c();
|
11
|
+
|
12
|
+
// Prototype for our method - methods are prefixed by 'method_' here
|
13
|
+
VALUE method_infinity_check_c(VALUE self, VALUE limit, VALUE cr, VALUE ci, VALUE zr, VALUE zi);
|
14
|
+
|
15
|
+
// The initialization method for this module
|
16
|
+
void Init_infinity_check_c()
|
17
|
+
{
|
18
|
+
InfinityCheckC = rb_define_module("InfinityCheckC");
|
19
|
+
rb_define_method(InfinityCheckC, "infinity_check_c", method_infinity_check_c, 5);
|
20
|
+
}
|
21
|
+
|
22
|
+
VALUE method_infinity_check_c(VALUE self, VALUE limit, VALUE cr, VALUE ci, VALUE zr, VALUE zi)
|
23
|
+
{
|
24
|
+
float complex c = NUM2DBL(cr) + NUM2DBL(ci) * I;
|
25
|
+
float complex z = NUM2DBL(zr) + NUM2DBL(zi) * I;
|
26
|
+
int iteration_limit = FIX2INT(limit);
|
27
|
+
int i = -1;
|
28
|
+
int j;
|
29
|
+
|
30
|
+
for (j = 0; j < iteration_limit; j++)
|
31
|
+
{
|
32
|
+
z = z * z + c;
|
33
|
+
double a = cabs(z);
|
34
|
+
|
35
|
+
if (a > 4.0f)
|
36
|
+
{
|
37
|
+
break;
|
38
|
+
}
|
39
|
+
|
40
|
+
i++;
|
41
|
+
}
|
42
|
+
|
43
|
+
return INT2FIX(i);
|
44
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.push File.expand_path("..", __FILE__)
|
3
|
+
|
4
|
+
require "version"
|
5
|
+
require 'complex'
|
6
|
+
|
7
|
+
# C extensions
|
8
|
+
require "infinity_check_c"
|
9
|
+
include InfinityCheckC
|
10
|
+
|
11
|
+
module GemWithExtensionExample
|
12
|
+
class PlotFractal
|
13
|
+
PRETTY_PLOT = false
|
14
|
+
|
15
|
+
if PRETTY_PLOT
|
16
|
+
MAX_ITERATION_COUNT = 10
|
17
|
+
else
|
18
|
+
MAX_ITERATION_COUNT = 10000
|
19
|
+
end
|
20
|
+
|
21
|
+
DIVERGE_LIMIT = 4.0
|
22
|
+
DIVERGE_LIMIT_SQUARED = DIVERGE_LIMIT * DIVERGE_LIMIT
|
23
|
+
|
24
|
+
CLASSIC_JULIA_SET = Complex(-1.0,-0.25)
|
25
|
+
|
26
|
+
if PRETTY_PLOT
|
27
|
+
MAP_SET = " ·::++++xxxxxx "
|
28
|
+
else
|
29
|
+
MAP_SET = " · "
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.mandelbrot(grid)
|
33
|
+
(0...grid.height).each do |y|
|
34
|
+
(0...grid.width).each do |x|
|
35
|
+
z = grid[x,y]
|
36
|
+
count = infinity_check_ruby(MAX_ITERATION_COUNT, z, z)
|
37
|
+
print get_render_character(count)
|
38
|
+
end
|
39
|
+
puts ""
|
40
|
+
end
|
41
|
+
end
|
42
|
+
def self.mandelbrot_C(grid)
|
43
|
+
(0...grid.height).each do |y|
|
44
|
+
(0...grid.width).each do |x|
|
45
|
+
z = grid[x,y]
|
46
|
+
i = z.imaginary
|
47
|
+
r = z.real
|
48
|
+
count = infinity_check_c(MAX_ITERATION_COUNT, r, i, r, i)
|
49
|
+
print get_render_character(count)
|
50
|
+
end
|
51
|
+
puts ""
|
52
|
+
end
|
53
|
+
end
|
54
|
+
def self.julia(grid)
|
55
|
+
(0...grid.height).each do |y|
|
56
|
+
(0...grid.width).each do |x|
|
57
|
+
z = grid[x,y]
|
58
|
+
i = infinity_check_ruby(MAX_ITERATION_COUNT, CLASSIC_JULIA_SET, z)
|
59
|
+
print get_render_character(i)
|
60
|
+
end
|
61
|
+
puts ""
|
62
|
+
end
|
63
|
+
end
|
64
|
+
def self.julia_C(grid)
|
65
|
+
(0...grid.height).each do |y|
|
66
|
+
(0...grid.width).each do |x|
|
67
|
+
z = grid[x,y]
|
68
|
+
count = infinity_check_c(MAX_ITERATION_COUNT, CLASSIC_JULIA_SET.real, CLASSIC_JULIA_SET.imaginary, z.real, z.imaginary)
|
69
|
+
print get_render_character(count)
|
70
|
+
end
|
71
|
+
puts ""
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
@@lookup = []
|
77
|
+
|
78
|
+
def self.build_lookup
|
79
|
+
limit = MAX_ITERATION_COUNT
|
80
|
+
step = Float(MAX_ITERATION_COUNT) / MAP_SET.length
|
81
|
+
MAP_SET.length.times do
|
82
|
+
@@lookup << Integer(limit)
|
83
|
+
limit -= step
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
self.build_lookup # populate limit table
|
88
|
+
|
89
|
+
def self.get_render_character(a)
|
90
|
+
c = nil
|
91
|
+
i = 0
|
92
|
+
a = MAX_ITERATION_COUNT - a
|
93
|
+
@@lookup.each do |limit|
|
94
|
+
c = MAP_SET[i]
|
95
|
+
i += 1
|
96
|
+
break if a > limit
|
97
|
+
end
|
98
|
+
return c
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.infinity_check_ruby(limit, c, z)
|
102
|
+
i = -1
|
103
|
+
limit.times do
|
104
|
+
z = z * z + c
|
105
|
+
break if z.abs > DIVERGE_LIMIT
|
106
|
+
i += 1
|
107
|
+
end
|
108
|
+
return i
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'complex'
|
2
|
+
|
3
|
+
class Grid
|
4
|
+
attr_reader :width, :height
|
5
|
+
|
6
|
+
def initialize(width, height, default_value = nil)
|
7
|
+
@width = width
|
8
|
+
@height = height
|
9
|
+
@default_value = default_value
|
10
|
+
@grid = create(width, height, default_value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](x,y)
|
14
|
+
if (x < 0 or x >= @width) or (y < 0 or y >= @height)
|
15
|
+
throw Error("Grid index out of bounds. [%d][%d] not in range ([0 through %d][0 through %d])" % [x, y, width - 1, height - 1])
|
16
|
+
end
|
17
|
+
@grid[x][y]
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(x,y,a)
|
21
|
+
if (x < 0 or x >= @width) or (y < 0 or y >= @height)
|
22
|
+
throw Error("Grid index out of bounds. [%d][%d] not in range ([0 through %d][0 through %d])" % [x, y, width - 1, height - 1])
|
23
|
+
end
|
24
|
+
@grid[x][y] = a
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear(value=nil)
|
28
|
+
(0...@width).each do |xi|
|
29
|
+
(0...@height).each do |yi|
|
30
|
+
@grid[xi][yi] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
s = ""
|
37
|
+
@grid.each{|c| s << c.to_s << "\n"}
|
38
|
+
return s
|
39
|
+
end
|
40
|
+
|
41
|
+
def each_col
|
42
|
+
@grid.each{|c| yield c.dup}
|
43
|
+
end
|
44
|
+
|
45
|
+
def each
|
46
|
+
@grid.each do |c|
|
47
|
+
c.each{|i| yield i}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generate a two dimensional grid of float pairs, evenly
|
52
|
+
# distributed across width x height samples
|
53
|
+
# ranging from x0 to x1 and y0 to y1
|
54
|
+
def fill_complex(x0, y0, x1, y1)
|
55
|
+
x_range = x1 - x0
|
56
|
+
y_range = y1 - y0
|
57
|
+
|
58
|
+
width_limit = Float(@width - 1)
|
59
|
+
height_limit = Float(@height - 1)
|
60
|
+
|
61
|
+
(0...@width).each do |xi|
|
62
|
+
x_unit = Float(xi) / width_limit
|
63
|
+
x = x0 + (x_unit * x_range)
|
64
|
+
|
65
|
+
(0...@height).each do |yi|
|
66
|
+
y_unit = Float(yi) / height_limit
|
67
|
+
y = y0 + (y_unit * y_range)
|
68
|
+
@grid[xi][yi] = Complex(x,y)
|
69
|
+
#@grid[xi][yi] = [x,y]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def fill_test()
|
75
|
+
t = 0
|
76
|
+
@grid.each_with_index do |c, x|
|
77
|
+
c.each_with_index{|i, y| @grid[x][y] = t; t += 1}
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
#------------------------------------------
|
82
|
+
private
|
83
|
+
|
84
|
+
def create(width, height, default_value)
|
85
|
+
grid = Array.new(width){[]}
|
86
|
+
(0...width).each do |xi|
|
87
|
+
grid[xi] = Array.new(height, default_value)
|
88
|
+
end
|
89
|
+
return grid
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
RUN_TEST = false
|
95
|
+
|
96
|
+
if RUN_TEST
|
97
|
+
grid = Grid.new(4, 5, [0.0,0.0])
|
98
|
+
|
99
|
+
puts "-" * 9
|
100
|
+
p grid
|
101
|
+
|
102
|
+
puts "-" * 9
|
103
|
+
p grid[0,0]
|
104
|
+
p grid[1,1]
|
105
|
+
|
106
|
+
puts "-" * 9
|
107
|
+
grid[0,0] = [5.0,2.0]
|
108
|
+
grid[1,1] = [7.0,9.0]
|
109
|
+
|
110
|
+
p grid[0,0]
|
111
|
+
p grid[1,1]
|
112
|
+
|
113
|
+
puts "-" * 9
|
114
|
+
p grid
|
115
|
+
|
116
|
+
puts "-" * 9
|
117
|
+
grid.fill_complex(-2.0, -1.0, 1.0, 1.0)
|
118
|
+
puts "-" * 9
|
119
|
+
p grid
|
120
|
+
|
121
|
+
grid.clear(0)
|
122
|
+
puts "-" * 9
|
123
|
+
p grid
|
124
|
+
|
125
|
+
grid.fill_test
|
126
|
+
puts "-" * 9
|
127
|
+
p grid
|
128
|
+
|
129
|
+
puts "-" * 9
|
130
|
+
grid.each{|c| p c}
|
131
|
+
|
132
|
+
puts "-" * 9
|
133
|
+
grid.each_col{|c| p c}
|
134
|
+
|
135
|
+
puts "-" * 9
|
136
|
+
p grid
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
|
Binary file
|
@@ -0,0 +1,169 @@
|
|
1
|
+
$:.push File.expand_path("..", __FILE__)
|
2
|
+
#require 'util'
|
3
|
+
#require File.expand_path('../util', __FILE__)
|
4
|
+
#require '/Users/sean/dev/gems/gem_with_extension_example/lib/gem_with_extension_example/util.rb'
|
5
|
+
|
6
|
+
class Timer
|
7
|
+
# ToDo
|
8
|
+
# Mode Flags:
|
9
|
+
# :side_by_side (on by default)
|
10
|
+
# :consecutive_runs (using redis)(off by default)
|
11
|
+
|
12
|
+
DIGITS_OF_PRESCISION = 6
|
13
|
+
@@max_name_length = 0
|
14
|
+
@@max_whole_digits = 1
|
15
|
+
@@timer_list = []
|
16
|
+
@@mode = :side_by_side
|
17
|
+
attr_reader :elapsed
|
18
|
+
|
19
|
+
#private :digits, :update_digit_count
|
20
|
+
|
21
|
+
def initialize(name)
|
22
|
+
@name = name
|
23
|
+
clear
|
24
|
+
@@max_name_length = name.length if name.length > @@max_name_length
|
25
|
+
@@timer_list << self
|
26
|
+
end
|
27
|
+
class << self
|
28
|
+
def set_mode(mode)
|
29
|
+
@@mode = mode #:side_by_side, :simple
|
30
|
+
end
|
31
|
+
def to_s
|
32
|
+
# Process pair comparison
|
33
|
+
pair_comparison = @@timer_list.count == 2
|
34
|
+
speed_multiple = nil
|
35
|
+
greater_index = nil
|
36
|
+
if pair_comparison
|
37
|
+
if @@timer_list[0].elapsed > @@timer_list[1].elapsed
|
38
|
+
greater_index = 1
|
39
|
+
speed_multiple = @@timer_list[0].elapsed / @@timer_list[1].elapsed
|
40
|
+
else
|
41
|
+
greater_index = 0
|
42
|
+
speed_multiple = @@timer_list[1].elapsed / @@timer_list[0].elapsed
|
43
|
+
end
|
44
|
+
end
|
45
|
+
total_time = @@timer_list.inject(0.0) { |result, t| result + t.elapsed }
|
46
|
+
|
47
|
+
# construct output string
|
48
|
+
s = ""
|
49
|
+
@@timer_list.each_with_index do |t, i|
|
50
|
+
s << t.to_s
|
51
|
+
s << "%8.3f%s" % [((t.elapsed) / total_time * 100.0), '%'] if @@timer_list.count > 1
|
52
|
+
if pair_comparison and (@@mode == :side_by_side) and (i == greater_index)
|
53
|
+
s << ", %.1f times faster." % speed_multiple
|
54
|
+
end
|
55
|
+
s << "\n"
|
56
|
+
end
|
57
|
+
if !(@@mode == :side_by_side and pair_comparison) and @@timer_list.count > 1
|
58
|
+
total_whole_digits = digits(total_time.to_i)
|
59
|
+
digit_overflow = total_whole_digits - @@max_whole_digits
|
60
|
+
leading_spaces = (@@max_name_length + 2) - digit_overflow
|
61
|
+
|
62
|
+
s << (" " * (@@max_name_length + 2))
|
63
|
+
s << ("-" * (DIGITS_OF_PRESCISION + @@max_whole_digits + 2))
|
64
|
+
s << "\n"
|
65
|
+
s << (" " * leading_spaces) if leading_spaces > 0
|
66
|
+
s << "%#{DIGITS_OF_PRESCISION + total_whole_digits + 1}.#{DIGITS_OF_PRESCISION}fs" % total_time
|
67
|
+
s << "\n"
|
68
|
+
end
|
69
|
+
s
|
70
|
+
end
|
71
|
+
def digits(n)
|
72
|
+
if n > 9
|
73
|
+
d = Math.log10(n).to_i + 1
|
74
|
+
elsif n < -9
|
75
|
+
d = Math.log10(n * -1).to_i + 1
|
76
|
+
else
|
77
|
+
d = 1
|
78
|
+
end
|
79
|
+
d
|
80
|
+
end
|
81
|
+
end
|
82
|
+
def clear
|
83
|
+
@state = :stopped
|
84
|
+
@time = []
|
85
|
+
@elapsed = 0.0
|
86
|
+
end
|
87
|
+
def self.clear
|
88
|
+
@@max_name_length = 0
|
89
|
+
@@max_whole_digits = 1
|
90
|
+
@@timer_list = []
|
91
|
+
end
|
92
|
+
def digits(n)
|
93
|
+
self.class.digits(n)
|
94
|
+
end
|
95
|
+
def update_digit_count
|
96
|
+
whole_digits = digits(@elapsed.to_i)
|
97
|
+
@@max_whole_digits = whole_digits if whole_digits > @@max_whole_digits
|
98
|
+
end
|
99
|
+
def to_s
|
100
|
+
"% #{@@max_name_length}s: %#{DIGITS_OF_PRESCISION + @@max_whole_digits + 1}.#{DIGITS_OF_PRESCISION}fs" % [@name, @elapsed]
|
101
|
+
end
|
102
|
+
def +(o)
|
103
|
+
o = o.elapsed if o.is_a?(self.class)
|
104
|
+
@elapsed += o
|
105
|
+
update_digit_count
|
106
|
+
end
|
107
|
+
def /(o)
|
108
|
+
o = o.elapsed if o.is_a?(self.class)
|
109
|
+
@elapsed /= o
|
110
|
+
update_digit_count
|
111
|
+
end
|
112
|
+
def start
|
113
|
+
if @state == :stopped
|
114
|
+
@state = :running
|
115
|
+
@start = Time.now
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def stop
|
119
|
+
if @state == :running
|
120
|
+
stop = Time.now
|
121
|
+
@elapsed += (stop - @start)
|
122
|
+
update_digit_count
|
123
|
+
@state = :stopped
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
if __FILE__ == $0
|
129
|
+
#Timer.set_mode(:simple)
|
130
|
+
19.times do
|
131
|
+
test_count = Random.rand(4) + 1
|
132
|
+
timer_list = []
|
133
|
+
|
134
|
+
# Allocate Timers
|
135
|
+
test_count.times do |n|
|
136
|
+
timer_name = ("A".ord + n).chr
|
137
|
+
timer_list[n] = Timer.new(timer_name)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Use Timers
|
141
|
+
test_count.times do |n|
|
142
|
+
timer_list[n].start
|
143
|
+
timer_list[n].stop
|
144
|
+
timer_list[n] += Random.rand * 133 # fake out the timer
|
145
|
+
end
|
146
|
+
|
147
|
+
# Show Timers
|
148
|
+
puts ""
|
149
|
+
puts Timer
|
150
|
+
Timer.clear
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
|
157
|
+
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
|
169
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module GemWithExtensionExample
|
2
|
+
# Use semantic versioning: http://semver.org/
|
3
|
+
|
4
|
+
# PATCH 0.0.x level changes for implementation level detail changes, such as small bug fixes
|
5
|
+
# MINOR 0.x.0 level changes for any backwards compatible API changes, such as new functionality/features
|
6
|
+
# MAJOR x.0.0 level changes for backwards incompatible
|
7
|
+
|
8
|
+
VERSION = "0.0.0"
|
9
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gem_with_extension_example
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sean Vikoren
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-10 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake-compiler
|
16
|
+
requirement: &2165428740 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2165428740
|
25
|
+
description: This gem is intended to function as a starting point for developing gems
|
26
|
+
that contain C optimizations.
|
27
|
+
email:
|
28
|
+
- sean@vikoren.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- ext/infinity_check_c/InfinityCheckC.c
|
34
|
+
- ext/infinity_check_c/extconf.rb
|
35
|
+
- lib/gem_with_extension_example/base.rb
|
36
|
+
- lib/gem_with_extension_example/grid.rb
|
37
|
+
- lib/gem_with_extension_example/timer.rb
|
38
|
+
- lib/gem_with_extension_example/version.rb
|
39
|
+
- lib/gem_with_extension_example.rb
|
40
|
+
- lib/gem_with_extension_example/infinity_check_c.bundle
|
41
|
+
homepage: ''
|
42
|
+
licenses: []
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project: gem_with_extension_example
|
61
|
+
rubygems_version: 1.8.11
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: An example gem with a C extention.
|
65
|
+
test_files: []
|