Skip to content

Commit ceeae16

Browse files
committed
Implements Concurrent::AtomicFixnum in pure Java.
1 parent 39ca9db commit ceeae16

File tree

3 files changed

+97
-43
lines changed

3 files changed

+97
-43
lines changed

ext/ConcurrentRubyExtService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class ConcurrentRubyExtService implements BasicLibraryService {
77
public boolean basicLoad(final Ruby runtime) throws IOException {
88
new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false);
99
new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false);
10+
new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false);
1011
return true;
1112
}
1213
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.concurrent_ruby.ext;
2+
3+
import java.io.IOException;
4+
import java.util.concurrent.atomic.AtomicLong;
5+
import org.jruby.Ruby;
6+
import org.jruby.RubyBoolean;
7+
import org.jruby.RubyClass;
8+
import org.jruby.RubyFixnum;
9+
import org.jruby.RubyModule;
10+
import org.jruby.RubyObject;
11+
import org.jruby.anno.JRubyClass;
12+
import org.jruby.anno.JRubyMethod;
13+
import org.jruby.runtime.ObjectAllocator;
14+
import org.jruby.runtime.ThreadContext;
15+
import org.jruby.runtime.builtin.IRubyObject;
16+
import org.jruby.runtime.load.Library;
17+
18+
public class JavaAtomicFixnumLibrary implements Library {
19+
20+
public void load(Ruby runtime, boolean wrap) throws IOException {
21+
RubyModule concurrentMod = runtime.defineModule("Concurrent");
22+
RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicFixnum", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR);
23+
24+
atomicCls.defineAnnotatedMethods(JavaAtomicFixnum.class);
25+
26+
}
27+
28+
private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() {
29+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
30+
return new JavaAtomicFixnum(runtime, klazz);
31+
}
32+
};
33+
34+
@JRubyClass(name = "JavaAtomicFixnum", parent = "Object")
35+
public static class JavaAtomicFixnum extends RubyObject {
36+
37+
private AtomicLong atomicLong;
38+
private ThreadContext context;
39+
40+
public JavaAtomicFixnum(Ruby runtime, RubyClass metaClass) {
41+
super(runtime, metaClass);
42+
}
43+
44+
@JRubyMethod
45+
public IRubyObject initialize(ThreadContext context) {
46+
this.atomicLong = new AtomicLong(0);
47+
this.context = context;
48+
return context.nil;
49+
}
50+
51+
@JRubyMethod
52+
public IRubyObject initialize(ThreadContext context, IRubyObject value) {
53+
this.atomicLong = new AtomicLong(rubyFixnumToLong(value));
54+
this.context = context;
55+
return context.nil;
56+
}
57+
58+
@JRubyMethod(name = "value")
59+
public IRubyObject getValue() {
60+
return new RubyFixnum(getRuntime(), atomicLong.get());
61+
}
62+
63+
@JRubyMethod(name = "value=")
64+
public IRubyObject setValue(IRubyObject newValue) {
65+
atomicLong.set(rubyFixnumToLong(newValue));
66+
return context.nil;
67+
}
68+
69+
@JRubyMethod(name = {"increment", "up"})
70+
public IRubyObject increment() {
71+
return new RubyFixnum(getRuntime(), atomicLong.incrementAndGet());
72+
}
73+
74+
@JRubyMethod(name = {"decrement", "down"})
75+
public IRubyObject decrement() {
76+
return new RubyFixnum(getRuntime(), atomicLong.decrementAndGet());
77+
}
78+
79+
@JRubyMethod(name = "compare_and_set")
80+
public IRubyObject compareAndSet(IRubyObject expect, IRubyObject update) {
81+
return RubyBoolean.newBoolean(getRuntime(), atomicLong.compareAndSet(rubyFixnumToLong(expect), rubyFixnumToLong(update)));
82+
}
83+
84+
private long rubyFixnumToLong(IRubyObject value) {
85+
if (value instanceof RubyFixnum) {
86+
RubyFixnum fixNum = (RubyFixnum) value;
87+
return fixNum.getLongValue();
88+
} else {
89+
throw getRuntime().newArgumentError("initial value must be a Fixnum");
90+
}
91+
}
92+
}
93+
}
94+

lib/concurrent/atomic/atomic_fixnum.rb

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,14 @@ def decrement
9797
alias_method :down, :decrement
9898

9999
# @!macro [attach] atomic_fixnum_method_compare_and_set
100-
#
100+
#
101101
# Atomically sets the value to the given updated value if the current
102102
# value == the expected value.
103103
#
104104
# @param [Fixnum] expect the expected value
105105
# @param [Fixnum] update the new value
106106
#
107-
# @return [Boolean] true if the value was updated else false
107+
# @return [Boolean] true if the value was updated else false
108108
def compare_and_set(expect, update)
109109
@mutex.lock
110110
if @value == expect
@@ -120,47 +120,6 @@ def compare_and_set(expect, update)
120120

121121
if RUBY_PLATFORM == 'java'
122122

123-
# @!macro atomic_fixnum
124-
class JavaAtomicFixnum
125-
126-
MIN_VALUE = Java::JavaLang::Long::MIN_VALUE
127-
MAX_VALUE = Java::JavaLang::Long::MAX_VALUE
128-
129-
# @!macro atomic_fixnum_method_initialize
130-
def initialize(init = 0)
131-
raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
132-
@atomic = java.util.concurrent.atomic.AtomicLong.new(init)
133-
end
134-
135-
# @!macro atomic_fixnum_method_value_get
136-
def value
137-
@atomic.get
138-
end
139-
140-
# @!macro atomic_fixnum_method_value_set
141-
def value=(value)
142-
raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
143-
@atomic.set(value)
144-
end
145-
146-
# @!macro atomic_fixnum_method_increment
147-
def increment
148-
@atomic.increment_and_get
149-
end
150-
alias_method :up, :increment
151-
152-
# @!macro atomic_fixnum_method_decrement
153-
def decrement
154-
@atomic.decrement_and_get
155-
end
156-
alias_method :down, :decrement
157-
158-
# @!macro atomic_fixnum_method_compare_and_set
159-
def compare_and_set(expect, update)
160-
@atomic.compare_and_set(expect, update)
161-
end
162-
end
163-
164123
# @!macro atomic_fixnum
165124
class AtomicFixnum < JavaAtomicFixnum
166125
end

0 commit comments

Comments
 (0)