skiplist 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ === 0.0.1 2010-Aug-13
2
+
3
+ * Initial release
@@ -0,0 +1,14 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ ext/skiplist/extconf.rb
6
+ ext/skiplist/skiplist_mlink.c
7
+ lib/skiplist.rb
8
+ lib/skiplist/loop.rb
9
+ lib/skiplist/sentinelelement.rb
10
+ script/console
11
+ script/destroy
12
+ script/generate
13
+ test/test_helper.rb
14
+ test/test_skiplist.rb
@@ -0,0 +1,49 @@
1
+ = skiplist
2
+
3
+ * http://github.com/metanest/ruby-skiplist
4
+
5
+ == DESCRIPTION:
6
+
7
+ Lock-free skip list implementation by ruby.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIX (list of features or problems)
12
+
13
+ == SYNOPSIS:
14
+
15
+ FIX (code sample of usage)
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * ruby 1.9
20
+
21
+ == INSTALL:
22
+
23
+ * (sudo) gem install
24
+
25
+ == LICENSE:
26
+
27
+ (other than loop.rb )
28
+ (The MIT License)
29
+
30
+ Copyright (c) 2010 KISHIMOTO, Makoto
31
+
32
+ Permission is hereby granted, free of charge, to any person obtaining
33
+ a copy of this software and associated documentation files (the
34
+ 'Software'), to deal in the Software without restriction, including
35
+ without limitation the rights to use, copy, modify, merge, publish,
36
+ distribute, sublicense, and/or sell copies of the Software, and to
37
+ permit persons to whom the Software is furnished to do so, subject to
38
+ the following conditions:
39
+
40
+ The above copyright notice and this permission notice shall be
41
+ included in all copies or substantial portions of the Software.
42
+
43
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
44
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
45
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
46
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
47
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
48
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
49
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/skiplist'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 'skiplist' do
14
+ self.developer 'KISHIMOTO, Makoto', 'ksmakoto@dd.iij4u.or.jp'
15
+ # self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
+ self.rubyforge_name = self.name # TODO this is default value
17
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
18
+
19
+ self.spec_extras = {
20
+ :extensions => ['ext/skiplist/extconf.rb'],
21
+ }
22
+ end
23
+
24
+ require 'newgem/tasks'
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ # remove_task :default
29
+ # task :default => [:spec, :features]
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile "skiplist/skiplist_mlink"
@@ -0,0 +1,150 @@
1
+ /* vi:set ts=3 sw=3:
2
+ * vim:set sts=0 noet:
3
+ */
4
+ /*
5
+ * Copyright (c) 2010 KISHIMOTO, Makoto
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+ #include <ruby.h>
26
+
27
+ static __inline__ int
28
+ cas(VALUE *addr, VALUE oldp, VALUE newp)
29
+ {
30
+ return __sync_bool_compare_and_swap(addr, oldp, newp);
31
+ }
32
+
33
+ struct mlink {
34
+ VALUE link;
35
+ };
36
+
37
+ static void
38
+ mlink_mark(struct mlink *lnkp)
39
+ {
40
+ VALUE p = lnkp->link & ~1;
41
+
42
+ rb_gc_mark(p);
43
+ }
44
+
45
+ static VALUE
46
+ mlink_alloc(VALUE klass)
47
+ {
48
+ struct mlink *lnkp;
49
+ VALUE obj = Data_Make_Struct(klass, struct mlink, mlink_mark, -1, lnkp);
50
+
51
+ lnkp->link = 0;
52
+
53
+ return obj;
54
+ }
55
+
56
+ static VALUE
57
+ mlink_initialize(VALUE obj, VALUE link)
58
+ {
59
+ struct mlink *lnkp;
60
+
61
+ if (link & 1) {
62
+ rb_raise(rb_eArgError, "link must not be a Fixnum");
63
+ }
64
+
65
+ Data_Get_Struct(obj, struct mlink, lnkp);
66
+
67
+ lnkp->link = link;
68
+
69
+ return Qnil;
70
+ }
71
+
72
+ static VALUE
73
+ mlink_compare_and_set(VALUE obj, VALUE oldlink, VALUE newlink, VALUE oldmark, VALUE newmark)
74
+ {
75
+ struct mlink *lnkp;
76
+ VALUE olink, nlink;
77
+
78
+ if ((oldlink & 1) || (newlink & 1)) {
79
+ rb_raise(rb_eArgError, "link must not be a Fixnum");
80
+ }
81
+ if (((oldmark != Qfalse) && (oldmark != Qtrue)) ||
82
+ ((newmark != Qfalse) && (newmark != Qtrue))) {
83
+ rb_raise(rb_eArgError, "mark must be a boolean");
84
+ }
85
+
86
+ Data_Get_Struct(obj, struct mlink, lnkp);
87
+
88
+ olink = oldlink | !!oldmark;
89
+ nlink = newlink | !!newmark;
90
+
91
+ return cas(&lnkp->link, olink, nlink) ? Qtrue : Qfalse ;
92
+ }
93
+
94
+ static VALUE
95
+ mlink_get(VALUE obj)
96
+ {
97
+ struct mlink *lnkp;
98
+ VALUE link, mark;
99
+
100
+ Data_Get_Struct(obj, struct mlink, lnkp);
101
+
102
+ link = lnkp->link;
103
+ mark = link & 1 ? Qtrue : Qfalse ;
104
+ link &= ~1;
105
+
106
+ return rb_ary_new3(2, link, mark);
107
+ }
108
+
109
+ static VALUE
110
+ mlink_get_link(VALUE obj)
111
+ {
112
+ struct mlink *lnkp;
113
+
114
+ Data_Get_Struct(obj, struct mlink, lnkp);
115
+
116
+ return lnkp->link & ~1;
117
+ }
118
+
119
+ static VALUE
120
+ mlink_print_debug(VALUE obj)
121
+ {
122
+ VALUE link_mark, arg[1], link, mark;
123
+
124
+ link_mark = mlink_get(obj);
125
+ arg[0] = INT2FIX(0);
126
+ link = rb_ary_aref(1, arg, link_mark);
127
+ arg[0] = INT2FIX(1);
128
+ mark = rb_ary_aref(1, arg, link_mark);
129
+
130
+ rb_funcall(obj, rb_intern("puts"), 1,
131
+ rb_funcall(rb_str_new2("#<MLink: @mark = %s, @link = 0x%014x>"), rb_intern("%"), 1,
132
+ rb_ary_new3(2, mark, rb_funcall(link, rb_intern("object_id"), 0)) ));
133
+
134
+ return Qnil;
135
+ }
136
+
137
+ void
138
+ Init_skiplist_mlink(void)
139
+ {
140
+ VALUE cSkipList = rb_define_class("SkipList", rb_cObject);
141
+ VALUE cMLink = rb_define_class_under(cSkipList, "MLink", rb_cObject);
142
+
143
+ rb_define_alloc_func(cMLink, &mlink_alloc);
144
+
145
+ rb_define_method(cMLink, "initialize", &mlink_initialize, 1);
146
+ rb_define_method(cMLink, "compare_and_set", &mlink_compare_and_set, 4);
147
+ rb_define_method(cMLink, "get", &mlink_get, 0);
148
+ rb_define_method(cMLink, "get_link", &mlink_get_link, 0);
149
+ rb_define_method(cMLink, "print_debug", &mlink_print_debug, 0);
150
+ }
@@ -0,0 +1,375 @@
1
+ # coding:utf-8
2
+ # vi:set ts=3 sw=3:
3
+ # vim:set sts=0 noet:
4
+
5
+ $:.unshift(File.dirname(__FILE__)) unless
6
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
7
+
8
+ require "skiplist/loop"
9
+ require "skiplist/sentinelelement"
10
+ require "skiplist/skiplist_mlink"
11
+
12
+ =begin
13
+ Copyright (c) 2010 KISHIMOTO, Makoto
14
+
15
+ Permission is hereby granted, free of charge, to any person obtaining a copy
16
+ of this software and associated documentation files (the "Software"), to deal
17
+ in the Software without restriction, including without limitation the rights
18
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19
+ copies of the Software, and to permit persons to whom the Software is
20
+ furnished to do so, subject to the following conditions:
21
+
22
+ The above copyright notice and this permission notice shall be included in
23
+ all copies or substantial portions of the Software.
24
+
25
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
+ THE SOFTWARE.
32
+ =end
33
+
34
+ #
35
+ #= Lock-Free Skip List
36
+ #
37
+ #Authors:: KISHIMOTO, Makoto
38
+ #Version:: 0.0.1 2010-Aug-13
39
+ #Copyright:: Copyright (c) 2010 KISHIMOTO, Makoto
40
+ #License:: (other than loop.rb ) X License
41
+ #
42
+ #=== References
43
+ #
44
+ #- The Art of Multiprocessor Programming, Chap. 14
45
+ #
46
+ class SkipList
47
+ VERSION = '0.0.1'
48
+
49
+ #
50
+ # Node of SkipList, inner use only
51
+ #
52
+ class Node
53
+ attr_accessor :toplevel, :key, :val
54
+
55
+ def initialize toplevel, key, val
56
+ @toplevel = toplevel
57
+ @key = key
58
+ @val = val
59
+ @links = Array.new(@toplevel + 1)
60
+ end
61
+
62
+ def print_debug
63
+ puts "object_id = 0x%014x" % [object_id]
64
+ puts "@toplevel = #{@toplevel}"
65
+ puts "@key = #{@key}"
66
+ puts "@val = #{@val}"
67
+ puts "@links = "
68
+ @links.each_index{|i|
69
+ print "[#{i}] "
70
+ @links[i].print_debug
71
+ }
72
+ end
73
+
74
+ def [] level
75
+ @links[level]
76
+ end
77
+
78
+ def []= level, node
79
+ @links[level] = node
80
+ end
81
+ end
82
+
83
+ attr_reader :size
84
+
85
+ #
86
+ # Create a SkipList object.
87
+ #
88
+ # level_max :: If this list will have approximately N elements, you sholud set this log_2 N.
89
+ #
90
+ def initialize level_max, cmp_op=:<=>, max_element=nil
91
+ if level_max < 0 then
92
+ raise ArgumentError.new "level_max must not be negative"
93
+ end
94
+ @level_max = level_max
95
+ @cmp_op = cmp_op
96
+ max = if max_element then max_element else SentinelElement::MAX end
97
+ @tail = Node.new @level_max, max, nil
98
+ (0).upto(@level_max){|i|
99
+ @tail[i] = MLink.new nil
100
+ }
101
+ @head = Node.new @level_max, nil, nil
102
+ (0).upto(@level_max){|i|
103
+ @head[i] = MLink.new @tail
104
+ }
105
+ @randgen = Random.new
106
+ @size_lock = Mutex.new
107
+ @size = 0
108
+ end
109
+
110
+ # for debug use
111
+ def print_debug
112
+ puts "@level_max = #{@level_max}"
113
+ puts "@cmp_op = #{@cmp_op}"
114
+ puts "@randgen = #{@randgen}"
115
+ puts "@size = #{@size}"
116
+ puts ""
117
+ puts "Nodes"
118
+ puts ""
119
+ p = @head
120
+ while p do
121
+ p.print_debug
122
+ puts ""
123
+ p = p[0].get_link
124
+ end
125
+ end
126
+
127
+ # this returns one of 0..ex, approx of 0 is 1/2, 1 is 1/4, 2 is 1/8, ...
128
+ def rand2exp ex
129
+ mask = 1 << (ex + 1)
130
+ r = 1 + @randgen.rand(mask - 1)
131
+ mask >>= 1
132
+ i = 0
133
+ while r & mask == 0 do
134
+ mask >>= 1
135
+ i += 1
136
+ end
137
+ i
138
+ end
139
+ private :rand2exp
140
+
141
+ #
142
+ # call-seq:
143
+ # lst.empty? -> true or false
144
+ #
145
+ # Returns <code>true</code> if <i>lst</i> contains no elements.
146
+ #
147
+ def empty?
148
+ @head[0].get_link.equal? @tail
149
+ end
150
+
151
+ #
152
+ # call-seq:
153
+ # lst.to_a -> array
154
+ #
155
+ # Converts <i>lst</i> to a array of <code>[</code> <i>key, value</i>
156
+ # <code>]</code> arrays.
157
+ #
158
+ # lst = SkipList.new 5
159
+ # lst["foo"] = 1
160
+ # lst["bar"] = 2
161
+ # lst["baz"] = 3
162
+ # lst.to_a #=> [["bar", 2], ["baz", 3], ["foo", 1]]
163
+ #
164
+ def to_a
165
+ arr = []
166
+ p, m = @head[0].get
167
+ while p do
168
+ if not m then
169
+ arr.push [p.key, p.val]
170
+ end
171
+ p, m = p[0].get
172
+ end
173
+ arr.pop
174
+ arr
175
+ end
176
+
177
+ # for inner use
178
+ def find key, before_list, after_list
179
+ Loop.loop {|tag|
180
+ pp = nil
181
+ p = @head
182
+ @level_max.downto(0){|level|
183
+ pp = p[level].get_link
184
+ loop {
185
+ ppp, mark = pp[level].get
186
+ while mark do
187
+ snip = p[level].compare_and_set pp, ppp, false, false
188
+ unless snip then
189
+ tag.next
190
+ end
191
+ #pp = ppp # ?
192
+ pp = p[level].get_link
193
+ ppp, mark = pp[level].get
194
+ end
195
+ if pp.key < key then
196
+ p = pp
197
+ pp = ppp
198
+ else
199
+ break
200
+ end
201
+ }
202
+ before_list[level] = p
203
+ after_list[level] = pp
204
+ }
205
+ if pp.key == key then
206
+ tag.break pp
207
+ else
208
+ tag.break nil
209
+ end
210
+ }
211
+ end
212
+ private :find
213
+
214
+ #
215
+ # call-seq:
216
+ # lst[key] = val -> val
217
+ #
218
+ # Insert new node that key is <i>key</i> and value is <i>val</i>.
219
+ # If already exist the node with key == <i>key</i>, assign new <i>val</i>.
220
+ # This method returns <i>val</i>.
221
+ #
222
+ # lst = SkipList.new 5
223
+ # lst["foo"] = 1
224
+ # lst["bar"] = 2
225
+ # lst["baz"] = 3
226
+ # lst.to_a #=> [["bar", 2], ["baz", 3], ["foo", 1]]
227
+ #
228
+ def []= key, val
229
+ before_list = Array.new(@level_max + 1)
230
+ after_list = Array.new(@level_max + 1)
231
+ loop {
232
+ if p = find(key, before_list, after_list) then
233
+ p.val = val
234
+ break
235
+ end
236
+ toplevel = rand2exp @level_max
237
+ node = Node.new toplevel, key, val
238
+ (0).upto(toplevel){|level|
239
+ node[level] = MLink.new after_list[level]
240
+ }
241
+ unless before_list[0][0].compare_and_set after_list[0], node, false, false then
242
+ next
243
+ end
244
+ @size_lock.synchronize {
245
+ @size += 1
246
+ }
247
+ (1).upto(toplevel){|level|
248
+ loop {
249
+ if before_list[level][level].compare_and_set after_list[level], node, false, false then
250
+ break
251
+ end
252
+ find key, before_list, after_list
253
+ }
254
+ }
255
+ break
256
+ }
257
+ val
258
+ end
259
+
260
+ #
261
+ # call-seq:
262
+ # lst[key] -> value
263
+ #
264
+ # Element reference.
265
+ #
266
+ # lst = SkipList.new 5
267
+ # lst["foo"] = 1
268
+ # lst["bar"] = 2
269
+ # lst["baz"] = 3
270
+ # lst["foo"] #=> 1
271
+ # lst["bar"] #=> 2
272
+ # lst["baz"] #=> 3
273
+ #
274
+ def [] key
275
+ pp = nil
276
+ p = @head
277
+ @level_max.downto(0){|level|
278
+ pp = p[level].get_link # ?
279
+ loop {
280
+ ppp, mark = pp[level].get
281
+ while mark do
282
+ #pp = ppp # ?
283
+ pp = pp[level].get_link
284
+ ppp, mark = pp[level].get
285
+ end
286
+ if pp.key < key then
287
+ p = pp
288
+ pp = ppp
289
+ else
290
+ break
291
+ end
292
+ }
293
+ }
294
+ if pp.key == key then
295
+ pp.val
296
+ else
297
+ nil
298
+ end
299
+ end
300
+
301
+ #
302
+ # call-seq:
303
+ # lst.delete[key] -> value
304
+ #
305
+ # Element deletion. Returns a value of deleted element.
306
+ #
307
+ # lst = SkipList.new 5
308
+ # lst["foo"] = 1
309
+ # lst["foo"] #=> 1
310
+ # lst.delete["foo"] #=> 1
311
+ # lst["foo"] #=> nil
312
+ # lst.delete["bar"] #=> nil
313
+ #
314
+ def delete key
315
+ before_list = Array.new(@level_max + 1)
316
+ after_list = Array.new(@level_max + 1)
317
+ unless p = find(key, before_list, after_list) then
318
+ return nil
319
+ end
320
+ p.toplevel.downto(1){|level|
321
+ pp, mark = p[level].get
322
+ until mark do
323
+ p[level].compare_and_set pp, pp, false, true
324
+ pp, mark = p[level].get
325
+ end
326
+ }
327
+ pp, mark = p[0].get
328
+ loop {
329
+ i_marked_it = p[0].compare_and_set pp, pp, false, true
330
+ pp, mark = p[0].get
331
+ if i_marked_it then
332
+ @size_lock.synchronize {
333
+ @size -= 1
334
+ }
335
+ #find key, before_list, after_list
336
+ break p.val
337
+ elsif mark then
338
+ break nil
339
+ end
340
+ }
341
+ end
342
+ end
343
+
344
+ #
345
+
346
+ if $0 == __FILE__ then
347
+ puts "------------------------"
348
+ list = SkipList.new 5
349
+ list["foo"] = "foo"
350
+ list["bar"] = "bar"
351
+ list["baz"] = "baz"
352
+ list.print_debug
353
+ puts "------------------------"
354
+ list = SkipList.new 5
355
+ list["foo"] = "foo"
356
+ list["bar"] = "bar"
357
+ list["baz"] = "baz"
358
+ list.delete "foo"
359
+ list.print_debug
360
+ puts "------------------------"
361
+ list = SkipList.new 5
362
+ list["foo"] = "foo"
363
+ list["bar"] = "bar"
364
+ list["baz"] = "baz"
365
+ list.delete "bar"
366
+ list.print_debug
367
+ puts "------------------------"
368
+ list = SkipList.new 5
369
+ list["foo"] = "foo"
370
+ list["bar"] = "bar"
371
+ list["baz"] = "baz"
372
+ list.delete "baz"
373
+ list.print_debug
374
+ puts "------------------------"
375
+ end
@@ -0,0 +1,35 @@
1
+ # coding:utf-8
2
+ # vi:set ts=3 sw=3:
3
+ # vim:set sts=0 noet:
4
+
5
+ # by Nobuyoshi Nakada [ruby-dev:41909]
6
+
7
+ class Loop
8
+ def loop
9
+ begin
10
+ t, val = catch(self){
11
+ yield self
12
+ true
13
+ }
14
+ end while t
15
+ val
16
+ end
17
+
18
+ def next val=nil
19
+ throw self, [true, val]
20
+ end
21
+
22
+ def break val=nil
23
+ throw self, [false, val]
24
+ end
25
+
26
+ def self.loop &block
27
+ new.loop(&block)
28
+ end
29
+
30
+ private
31
+
32
+ def self.new
33
+ super
34
+ end
35
+ end
@@ -0,0 +1,66 @@
1
+ # coding:utf-8
2
+ # vi:set ts=3 sw=3:
3
+ # vim:set sts=0 noet:
4
+
5
+ =begin
6
+ Copyright (c) 2010 KISHIMOTO, Makoto
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+ =end
26
+
27
+ class SentinelElement
28
+ include Comparable
29
+
30
+ MAX = new
31
+ MIN = new
32
+
33
+ private
34
+
35
+ def self.new
36
+ super
37
+ end
38
+ end
39
+
40
+ class << SentinelElement::MAX
41
+ def <=> other
42
+ if equal? other then
43
+ 0
44
+ else
45
+ 1
46
+ end
47
+ end
48
+
49
+ def coerce other
50
+ [MIN, self]
51
+ end
52
+ end
53
+
54
+ class << SentinelElement::MIN
55
+ def <=> other
56
+ if equal? other then
57
+ 0
58
+ else
59
+ -1
60
+ end
61
+ end
62
+
63
+ def coerce other
64
+ [MAX, self]
65
+ end
66
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/skiplist.rb'}"
9
+ puts "Loading skiplist gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/skiplist'
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestSkiplist < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skiplist
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - KISHIMOTO, Makoto
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-13 00:00:00 +09:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rubyforge
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 0
31
+ - 4
32
+ version: 2.0.4
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 2
45
+ - 6
46
+ - 1
47
+ version: 2.6.1
48
+ type: :development
49
+ version_requirements: *id002
50
+ description: Lock-free skip list implementation by ruby.
51
+ email:
52
+ - ksmakoto@dd.iij4u.or.jp
53
+ executables: []
54
+
55
+ extensions:
56
+ - ext/skiplist/extconf.rb
57
+ extra_rdoc_files:
58
+ - History.txt
59
+ - Manifest.txt
60
+ files:
61
+ - History.txt
62
+ - Manifest.txt
63
+ - README.rdoc
64
+ - Rakefile
65
+ - ext/skiplist/extconf.rb
66
+ - ext/skiplist/skiplist_mlink.c
67
+ - lib/skiplist.rb
68
+ - lib/skiplist/loop.rb
69
+ - lib/skiplist/sentinelelement.rb
70
+ - script/console
71
+ - script/destroy
72
+ - script/generate
73
+ - test/test_helper.rb
74
+ - test/test_skiplist.rb
75
+ has_rdoc: true
76
+ homepage: http://github.com/metanest/ruby-skiplist
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README.rdoc
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project: skiplist
104
+ rubygems_version: 1.3.7
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Lock-free skip list implementation by ruby.
108
+ test_files:
109
+ - test/test_helper.rb
110
+ - test/test_skiplist.rb