Skip to content

Commit

Permalink
Merge pull request #4 from mauricio/thread-safe-jruby
Browse files Browse the repository at this point in the history
Thread safety for Java implementation some optimizations
  • Loading branch information
Dan McClain committed Sep 4, 2012
2 parents 489b927 + b163938 commit a30aba4
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 113 deletions.
193 changes: 99 additions & 94 deletions ext/pg_array_parser/PgArrayParserEngine.java
Original file line number Diff line number Diff line change
@@ -1,113 +1,118 @@
package pgarrayparser;

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.RubyString;
import org.jruby.RubyNil;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.anno.JRubyMethod;
import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.load.BasicLibraryService;

@JRubyClass(name = "PgArrayParser::PgArrayParserEngine")
public class PgArrayParserEngine extends RubyObject {
@JRubyClass(name = "PgArrayParser::PgArrayParserEngine")
public class PgArrayParserEngine extends RubyObject {

public PgArrayParserEngine(final Ruby runtime, RubyClass rubyClass) {
super(runtime, rubyClass);
super(runtime, rubyClass);
}

private Ruby runtime;
private int index;
private String arrayString;
@JRubyMethod(name = "parse_pg_array")
public IRubyObject parse_pg_array(ThreadContext context, IRubyObject value) {
runtime = context.getRuntime();
index = 1;
arrayString = value.asJavaString();
IRubyObject returnValue = readArray();
return returnValue;

public RubyArray parse_pg_array( ThreadContext context, IRubyObject value) {
String content = value.asJavaString();
return parseData(context, content, 0);
}

private RubyArray readArray()
private static RubyArray parseData( ThreadContext context, String content, int index)
{
RubyArray array = RubyArray.newArray(runtime, 1);

int openQuote = 0;
boolean escapeNext = false;
char currentChar;
StringBuilder word = new StringBuilder();

if(index < arrayString.length() && arrayString.charAt(index) == '}')
{
return array;
}

for(;index < arrayString.length(); ++index)
{
currentChar = arrayString.charAt(index);
if(openQuote < 1)
{
if(currentChar == ',' || currentChar == '}')
{
if(!escapeNext)
{
if(openQuote == 0 && word.length() == 4 && word.toString().equals("NULL"))
{
array.append(runtime.getNil());
}
else
{
array.append(RubyString.newString(runtime, word.toString()));
}
}
if(currentChar == '}')
{
return array;
RubyArray items = RubyArray.newArray(context.getRuntime());

for( int x = index; x < content.length(); x++ ) {

char token = content.charAt(x);

switch (token) {
case '{':
x = parseArrayContents( context, items, content, x + 1 );
break;
case '}':
return items;
}
escapeNext = false;
openQuote = 0;
word = new StringBuilder();
}
else if(currentChar == '"')
{
openQuote = 1;
}
else if(currentChar == '{')
{
index++;
array.append(readArray());
escapeNext = true;
}
else
{
word.append(String.valueOf(currentChar));
}
}
else if(escapeNext)
{
word.append(String.valueOf(currentChar));
escapeNext = false;
}
else if(currentChar == '\\')
{
escapeNext = true;

}
else if(currentChar == '"')
{
openQuote = -1;

return items;
}

private static int parseArrayContents( ThreadContext context, RubyArray items, String content, int index ) {

StringBuilder currentItem = new StringBuilder();
boolean isEscaping = false;
boolean isQuoted = false;
boolean wasQuoted = false;

int x = index;

for(; x < content.length(); x++ ) {

char token = content.charAt(x);

if ( isEscaping ) {
currentItem.append( token );
isEscaping = false;
} else {
if ( isQuoted ) {
switch (token) {
case '"':
isQuoted = false;
wasQuoted = true;
break;
case '\\':
isEscaping = true;
break;
default:
currentItem.append(token);
}
} else {
switch (token) {
case '\\':
isEscaping = true;
break;
case ',':
addItem(context, items, currentItem, wasQuoted);
currentItem = new StringBuilder();
wasQuoted = false;
break;
case '"':
isQuoted = true;
break;
case '{':
RubyArray internalItems = RubyArray.newArray(context.getRuntime());
x = parseArrayContents( context, internalItems, content, x + 1 );
items.add(internalItems);
break;
case '}':
addItem(context, items, currentItem, wasQuoted);
return x;
default:
currentItem.append(token);
}
}
}

}
else
{
word.append(String.valueOf(currentChar));

return x;
}

private static void addItem( ThreadContext context, RubyArray items, StringBuilder builder, boolean quoted ) {
String value = builder.toString();

if ( value.length() == 0 ) {
return;
}
}

return array;
if ( !quoted && "NULL".equalsIgnoreCase( value ) ) {
items.add(context.getRuntime().getNil());
} else {
items.add(RubyString.newString( context.getRuntime(), value ));
}
}
}

}
32 changes: 13 additions & 19 deletions ext/pg_array_parser/PgArrayParserEngineService.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
package pgarrayparser;

import java.lang.Long;
import java.io.IOException;

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.RubyModule;
import org.jruby.RubyObject;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.load.BasicLibraryService;

import java.io.IOException;

public class PgArrayParserEngineService implements BasicLibraryService {

public boolean basicLoad(Ruby runtime) throws IOException {
public boolean basicLoad(Ruby runtime) throws IOException {

RubyModule pgArrayParser = runtime.defineModule("PgArrayParser");
RubyClass pgArrayParserEngine = pgArrayParser.defineClassUnder("PgArrayParserEngine", runtime.getObject(), new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
return new PgArrayParserEngine(runtime, rubyClass);
}
});
RubyModule pgArrayParser = runtime.defineModule("PgArrayParser");
RubyClass pgArrayParserEngine = pgArrayParser.defineClassUnder("PgArrayParserEngine", runtime.getObject(), new ObjectAllocator() {
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
return new PgArrayParserEngine(runtime, rubyClass);
}
});

pgArrayParserEngine.defineAnnotatedMethods(PgArrayParserEngine.class);
return true;
}
}
pgArrayParserEngine.defineAnnotatedMethods(PgArrayParserEngine.class);
return true;
}
}
Binary file modified lib/pg_array_parser.jar
Binary file not shown.

0 comments on commit a30aba4

Please sign in to comment.