Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
pkg
/.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

.DS_Store

Makefile
tuple.bundle
tuple.o
11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
language: ruby
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
- 2.0.0
- 2.1
- 2.2
os:
- linux
- osx
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
source 'https://rubygems.org'

gemspec
29 changes: 17 additions & 12 deletions README.rdoc → README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
= Tuple
# Tuple

Tuple provides fast, binary-sortable serialization for arrays of simple Ruby types. This
means you do not have to deserialize your tuples to store them. This leads to significant
Tuple provides fast, binary-sortable serialization for arrays of simple Ruby types.

This means you do not have to deserialize your tuples to store them. This leads to significant
performance benifits when using Tuples as keys for a BTree.

A Tuple is just an Array of any number of simple Ruby types. The following types are
supported (listed in ascending sort order):

1. NilClass
2. FalseClass
3. Integer (Fixnum or Bignum)
4. String
5. Symbol
6. True

== Usage:

## Usage

```ruby
require 'tuple'

data = Tuple.dump([1, -43, :foo, "bar", true, false, nil])
=> "\000\000\020\000\000\000\000\001..."
# => "\000\000\020\000\000\000\000\001..."
Tuple.load(data)
=> [1, -43, :foo, "bar", true, false, nil]
# => [1, -43, :foo, "bar", true, false, nil]
```

== Install:
## Install

sudo gem install ninjudd-tuple -s http://gems.github.com
```
gem install tuple
```

== License:
## License

Copyright (c) 2009 Justin Balthrop, Geni.com; Published under The MIT License, see LICENSE
Copyright (c) 2009 Justin Balthrop; Published under The MIT License, see LICENSE file.
71 changes: 27 additions & 44 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,56 +1,39 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'

begin
require 'jeweler'
Jeweler::Tasks.new do |s|
s.name = "tuple"
s.summary = %Q{Tuple serialization functions.}
s.email = "code@justinbalthrop.com"
s.homepage = "http://github.com/ninjudd/tuple"
s.description = "Fast, binary-sortable serialization for arrays of simple Ruby types."
s.authors = ["Justin Balthrop"]
s.files = ["README.rdoc", "VERSION.yml", "ext/tuple.c", "ext/extconf.rb", "test/test_helper.rb", "test/tuple_test.rb"]
s.extensions = ["ext/extconf.rb"]
s.require_paths = ["ext"]
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
end
require "rake/extensiontask"

Rake::TestTask.new do |t|
t.libs << "ext"
t.pattern = 'test/**/*_test.rb'
t.verbose = false
def gemspec
@clean_gemspec ||= eval(File.read(File.expand_path('../tuple.gemspec', __FILE__)))
end

Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'tuple'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
Rake::ExtensionTask.new('tuple', gemspec) do |ext|
ext.cross_compile = true
ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60']
ext.lib_dir = File.join('lib', 'tuple')

begin
require 'rcov/rcovtask'
Rcov::RcovTask.new do |t|
t.libs << 'test'
t.test_files = FileList['test/**/*_test.rb']
t.verbose = true
# inject 1.8/1.9 pure-ruby entry point when cross compiling only
ext.cross_compiling do |spec|
spec.files << 'lib/tuple/tuple.rb'
end
rescue LoadError

# Clean compiled extension
CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
end

Rake::TestTask.new(:test) do |test|
test.pattern = 'test/**/test_*.rb'
end

desc "Clean"
desc "Compile and then run tests"
task :default => [:compile, :test]

task :clean do
include FileUtils
Dir.chdir('ext') do
rm(Dir.glob('*') - ['tuple.c', 'extconf.rb'])

rm_rf("tmp")

Dir["*/**/*"].each do |path|
if path =~ /(\.o|\.bundle|\/Makefile)\z/
rm_f(path)
end
end
rm_rf 'pkg'
end

task :default => :test
1 change: 0 additions & 1 deletion VERSION

This file was deleted.

3 changes: 0 additions & 3 deletions ext/.gitignore

This file was deleted.

66 changes: 66 additions & 0 deletions ext/tuple/bignum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef BDIGIT
# if SIZEOF_INT*2 <= SIZEOF_LONG_LONG
# define BDIGIT unsigned int
# define SIZEOF_BDIGIT SIZEOF_INT
# elif SIZEOF_INT*2 <= SIZEOF_LONG
# define BDIGIT unsigned int
# define SIZEOF_BDIGIT SIZEOF_INT
# elif SIZEOF_SHORT*2 <= SIZEOF_LONG
# define BDIGIT unsigned short
# define SIZEOF_BDIGIT SIZEOF_SHORT
# else
# define BDIGIT unsigned short
# define SIZEOF_BDIGIT (SIZEOF_LONG/2)
# define SIZEOF_ACTUAL_BDIGIT SIZEOF_LONG
# endif
#endif

#ifndef SIZEOF_ACTUAL_BDIGIT
# define SIZEOF_ACTUAL_BDIGIT SIZEOF_BDIGIT
#endif

#define BIGNUM_EMBED_LEN_NUMBITS 3
#ifndef BIGNUM_EMBED_LEN_MAX
# if (SIZEOF_VALUE*3/SIZEOF_ACTUAL_BDIGIT) < (1 << BIGNUM_EMBED_LEN_NUMBITS)-1
# define BIGNUM_EMBED_LEN_MAX (SIZEOF_VALUE*3/SIZEOF_ACTUAL_BDIGIT)
# else
# define BIGNUM_EMBED_LEN_MAX ((1 << BIGNUM_EMBED_LEN_NUMBITS)-1)
# endif
#endif

struct RBignum {
struct RBasic basic;
union {
struct {
size_t len;
BDIGIT *digits;
} heap;
BDIGIT ary[BIGNUM_EMBED_LEN_MAX];
} as;
};

#define BIGNUM_SIGN_BIT FL_USER1
/* sign: positive:1, negative:0 */
#define BIGNUM_SIGN(b) ((RBASIC(b)->flags & BIGNUM_SIGN_BIT) != 0)
#define BIGNUM_SET_SIGN(b,sign) \
((sign) ? (RBASIC(b)->flags |= BIGNUM_SIGN_BIT) \
: (RBASIC(b)->flags &= ~BIGNUM_SIGN_BIT))
#define BIGNUM_POSITIVE_P(b) BIGNUM_SIGN(b)
#define BIGNUM_NEGATIVE_P(b) (!BIGNUM_SIGN(b))

#define BIGNUM_EMBED_FLAG FL_USER2
#define BIGNUM_EMBED_LEN_MASK (FL_USER5|FL_USER4|FL_USER3)
#define BIGNUM_EMBED_LEN_SHIFT (FL_USHIFT+BIGNUM_EMBED_LEN_NUMBITS)
#define BIGNUM_LEN(b) \
((RBASIC(b)->flags & BIGNUM_EMBED_FLAG) ? \
(long)((RBASIC(b)->flags >> BIGNUM_EMBED_LEN_SHIFT) & \
(BIGNUM_EMBED_LEN_MASK >> BIGNUM_EMBED_LEN_SHIFT)) : \
RBIGNUM(b)->as.heap.len)
/* LSB:BIGNUM_DIGITS(b)[0], MSB:BIGNUM_DIGITS(b)[BIGNUM_LEN(b)-1] */
#define BIGNUM_DIGITS(b) \
((RBASIC(b)->flags & BIGNUM_EMBED_FLAG) ? \
RBIGNUM(b)->as.ary : \
RBIGNUM(b)->as.heap.digits)
#define BIGNUM_LENINT(b) rb_long2int(BIGNUM_LEN(b))

#define RBIGNUM(obj) (R_CAST(RBignum)(obj))
8 changes: 7 additions & 1 deletion ext/extconf.rb → ext/tuple/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
$CFLAGS += ' -DRUBY_1_8_x'
when /\A1\.9/
$CFLAGS += ' -DRUBY_1_9_x'
when /\A2\.(0|1)/
$CFLAGS += ' -DRUBY_2_x_x'
$CFLAGS += ' -DRUBY_2_1_x'
when /\A2\.2/
$CFLAGS += ' -DRUBY_2_x_x'
$CFLAGS += ' -DRUBY_2_2_x'
else
raise "unsupported Ruby version: #{RUBY_VERSION}"
end

create_makefile('tuple')
create_makefile('tuple/tuple')
52 changes: 25 additions & 27 deletions ext/tuple.c → ext/tuple/tuple.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
#include "ruby.h"
#include <netinet/in.h>

#ifdef _WIN32
#include <stdint.h>

typedef uint8_t u_int8_t;
typedef uint32_t u_int32_t;
#else
#include <netinet/in.h>
#endif

#if defined(RUBY_2_2_x)
#include "bignum.h"
#endif

VALUE mTuple;
VALUE rb_cDate;
Expand Down Expand Up @@ -59,7 +71,7 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {

if (TYPE(tuple) != T_ARRAY) tuple = rb_ary_new4(1, &tuple);

#if defined(RUBY_1_9_x)
#if defined(RUBY_1_9_x) || defined(RUBY_2_x_x)
for (i = 0; i < RARRAY_LEN(tuple); i++) {
item = RARRAY_PTR(tuple)[i];
#elif defined(RUBY_1_8_x)
Expand Down Expand Up @@ -87,7 +99,10 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
digit = htonl(sign ? digit : UINT_MAX - digit);
rb_str_cat(data, (char*)&digit, sizeof(digit));
} else if (TYPE(item) == T_BIGNUM) {
#if defined(RUBY_1_9_x)
#if defined(RUBY_2_2_x)
sign = BIGNUM_SIGN(item);
len = BIGNUM_LEN(item);
#elif defined(RUBY_1_9_x) || defined(RUBY_2_x_x)
sign = RBIGNUM_SIGN(item);
len = RBIGNUM_LEN(item);
#elif defined(RUBY_1_8_x)
Expand All @@ -100,7 +115,9 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
header[3] = sign ? len : UCHAR_MAX - len;
rb_str_cat(data, (char*)&header, sizeof(header));

#if defined(RUBY_1_9_x)
#if defined(RUBY_2_2_x)
digits = BIGNUM_DIGITS(item);
#elif defined(RUBY_1_9_x) || defined(RUBY_2_x_x)
digits = RBIGNUM_DIGITS(item);
#elif defined(RUBY_1_8_x)
digits = BDIGITS(item);
Expand Down Expand Up @@ -158,7 +175,7 @@ static VALUE tuple_dump(VALUE self, VALUE tuple) {
}

static VALUE empty_bignum(int sign, int len) {
#if defined(RUBY_1_9_x)
#if defined(RUBY_1_9_x) || defined(RUBY_2_x_x)
return rb_big_new(len, sign);
#elif defined(RUBY_1_8_x)
/* Create an empty bignum with the right number of digits. */
Expand All @@ -174,27 +191,6 @@ static VALUE empty_bignum(int sign, int len) {
#error unsupported RUBY_VERSION
#endif
}
// static VALUE empty_bignum(int sign, int len) {
// /* Create an empty bignum with the right number of digits. */
// NEWOBJ(num, struct RBignum);
// OBJSETUP(num, rb_cBignum, T_BIGNUM);
// #if defined(RUBY_1_9_x)
// RBIGNUM_SET_SIGN(num, sign ? 1 : 0);
// // RBIGNUM_LEN(num) = len;
// // RBIGNUM_DIGITS(num) = ALLOC_N(BDIGIT, len);
// RBIGNUM(num)->len = len;
// num->digits = ALLOC_N(BDIGIT, len);
// #elif defined(RUBY_1_8_x)
// num->sign = sign ? 1 : 0;
// num->len = len;
// num->digits = ALLOC_N(BDIGIT, len);
// #else
// #error unsupported RUBY_VERSION
// #endif
//
// return (VALUE)num;
// }


static VALUE tuple_parse(void **data, int data_len) {
VALUE tuple = rb_ary_new();
Expand All @@ -220,7 +216,9 @@ static VALUE tuple_parse(void **data, int data_len) {
len = sign ? header[3] : (UCHAR_MAX - header[3]);

item = empty_bignum(sign, len);
#if defined(RUBY_1_9_x)
#if defined(RUBY_2_2_x)
digits = BIGNUM_DIGITS(item);
#elif defined(RUBY_1_9_x) || defined(RUBY_2_x_x)
digits = RBIGNUM_DIGITS(item);
#elif defined(RUBY_1_8_x)
digits = BDIGITS(item);
Expand Down
2 changes: 2 additions & 0 deletions lib/tuple.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
require "tuple/version"
require "tuple/tuple"
3 changes: 3 additions & 0 deletions lib/tuple/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Tuple
VERSION = "0.1.2"
end
32 changes: 32 additions & 0 deletions test/helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'rubygems'
require 'test/unit'
require 'tuple'

if not [].respond_to?(:shuffle)
class Array
def shuffle
t_self = self.dup
t_size = self.size
result=[]
t_size.times { result << t_self.slice!(rand(t_self.size)) }
result
end
end
end

class Time
def ==(other)
# Ignore microseconds for testing.
to_i == other.to_i
end
end

class TestTuple < Test::Unit::TestCase
def now
@now ||= Time.now
end

def today
@today ||= Date.today
end
end
Loading