Skip to content

Commit

Permalink
Add a JRuby-based ext wrapping the net.jpountz.lz4 library.
Browse files Browse the repository at this point in the history
rake build:jruby will build the JRuby version of the gem. The
'mvn' command must be present on the build system.
  • Loading branch information
headius committed Nov 23, 2013
1 parent 58af0a5 commit bf22d47
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 1 deletion.
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ doc
# jeweler generated
pkg

# JRuby ext build artifacts
target
dependency-reduced-pom.xml

# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
#
# * Create a file at ~/.gitignore
Expand Down Expand Up @@ -56,10 +60,11 @@ ext/lz4ruby/lz4hc.?
# binaries
*.o
*.so
*.jar

# Development, test and temporaries
Gemfile
Gemfile.lock
*.gemspec
benchmarking/testdata/
tmp/
tmp/
12 changes: 12 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,24 @@ task "build:cross" => [:modify_gemspec_for_windows, :cross, :build] do
mv file, "#{file.ext}-x86-mingw32.gem"
end

task "build:jruby" => [:modify_gemspec_for_jruby, :compile_jruby, :build]

task :modify_gemspec_for_windows do
$gemspec.extensions = []
$gemspec.files.include("lib/?.?/*.so")
$gemspec.platform = "x86-mingw32"
end

task :modify_gemspec_for_jruby do
$gemspec.extensions = []
$gemspec.files.include("lib/?.?/*.jar")
$gemspec.platform = "java"
end

task :compile_jruby do
system 'mvn package'
end

def get_version
`cat VERSION`.chomp
end
3 changes: 3 additions & 0 deletions lib/lz4-jruby.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require 'lz4ruby.jar'

com.headius.jruby.lz4.LZ4Library.new.load(JRuby.runtime, false)
2 changes: 2 additions & 0 deletions lib/lz4-ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/(\d+\.\d+)/ =~ RUBY_VERSION
ver = $1
require "#{ver}/lz4ruby.so"
elsif RUBY_PLATFORM == 'java'
require 'lz4-jruby'
else
require 'lz4ruby'
end
Expand Down
63 changes: 63 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.headius.jruby.lz4</groupId>
<artifactId>lz4ruby</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>lz4ruby</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.jpountz.lz4</groupId>
<artifactId>lz4</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby</artifactId>
<version>1.7.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.0</version>
<configuration>
<relocations>
<relocation>
<pattern>net.jpountz</pattern>
<shadedPattern>com.headius.jruby.lz4.vendor.net.jpountz</shadedPattern>
</relocation>
</relocations>
<outputFile>${basedir}/lib/lz4ruby.jar</outputFile>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
64 changes: 64 additions & 0 deletions src/main/java/com/headius/jruby/lz4/LZ4Internal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.headius.jruby.lz4;

import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import org.jruby.RubyInteger;
import org.jruby.RubyString;
import org.jruby.anno.JRubyMethod;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;

public class LZ4Internal {
private static final LZ4Factory FACTORY = LZ4Factory.fastestInstance();

public static IRubyObject compress_internal(ThreadContext context, LZ4Compressor compressor, IRubyObject _header, IRubyObject _input, IRubyObject _in_size) {
RubyString input = _input.convertToString();
RubyString header = _header.convertToString();
RubyInteger in_size = _in_size.convertToInteger();

ByteList inputBL = input.getByteList();
int srcSize = (int)in_size.getLongValue();

ByteList headerBL = header.getByteList();
int headerSize = headerBL.getRealSize();

int bufSize = compressor.maxCompressedLength(srcSize);
byte[] buf = new byte[bufSize + headerSize];

System.arraycopy(headerBL.getUnsafeBytes(), headerBL.getBegin(), buf, 0, headerSize);

compressor.compress(inputBL.getUnsafeBytes(), inputBL.getBegin(), srcSize, buf, headerSize);

return RubyString.newStringNoCopy(context.runtime, buf);
}

@JRubyMethod(module = true)
public static IRubyObject compress(ThreadContext context, IRubyObject self, IRubyObject _header, IRubyObject _input, IRubyObject _in_size) {
return compress_internal(context, FACTORY.fastCompressor(), _header, _input, _in_size);
}

@JRubyMethod(module = true)
public static IRubyObject compressHC(ThreadContext context, IRubyObject self, IRubyObject _header, IRubyObject _input, IRubyObject _in_size) {
return compress_internal(context, FACTORY.highCompressor(), _header, _input, _in_size);
}

@JRubyMethod(required = 4, module = true)
public static IRubyObject uncompress(ThreadContext context, IRubyObject self, IRubyObject[] args) {
RubyString input = args[0].convertToString();
RubyInteger in_size = args[1].convertToInteger();
RubyInteger header_size = args[2].convertToInteger();
RubyInteger buf_size = args[3].convertToInteger();

ByteList inputBL = input.getByteList();
int inSize = (int)in_size.getLongValue();
int headerSize = (int)header_size.getLongValue();
int bufSize = (int)buf_size.getLongValue();

byte[] buf = new byte[bufSize];

FACTORY.decompressor().decompress(inputBL.getUnsafeBytes(), inputBL.getBegin() + headerSize, buf, 0, buf.length);

return RubyString.newStringNoCopy(context.runtime, buf);
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/headius/jruby/lz4/LZ4Library.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.headius.jruby.lz4;

import java.io.IOException;
import org.jruby.Ruby;
import org.jruby.RubyModule;
import org.jruby.runtime.load.Library;

public class LZ4Library implements Library {

public void load(Ruby runtime, boolean wrap) throws IOException {
RubyModule lz4Internal = runtime.defineModule("LZ4Internal");

lz4Internal.defineAnnotatedMethods(LZ4Internal.class);

lz4Internal.defineClassUnder("Error", runtime.getStandardError(), runtime.getStandardError().getAllocator());
}

}

0 comments on commit bf22d47

Please sign in to comment.