skiplist 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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