зеркало из https://github.com/github/bert.git
smarter C encoder and remove all references to List
This commit is contained in:
Родитель
63ce966c3a
Коммит
8a20b33539
|
@ -25,7 +25,7 @@ Ruby encoder / Ruby decoder
|
|||
BERT large 4.190000 0.620000 4.810000 ( 4.959149)
|
||||
BERT complex 19.380000 0.080000 19.460000 ( 20.402862)
|
||||
|
||||
Simple C encoder / Ruby decoder
|
||||
Simple C decoder / Ruby encoder
|
||||
41503465479e8762916d6997d91639f0d7308a13
|
||||
|
||||
BERT tiny 0.030000 0.000000 0.030000 ( 0.033826)
|
||||
|
@ -39,3 +39,10 @@ Smarter Ruby decoder
|
|||
BERT small 0.810000 0.010000 0.820000 ( 0.831905)
|
||||
BERT large 4.340000 0.600000 4.940000 ( 5.064875)
|
||||
BERT complex 18.460000 0.070000 18.530000 ( 19.096184)
|
||||
|
||||
Smarter C decoder
|
||||
|
||||
BERT tiny 0.030000 0.000000 0.030000 ( 0.035685)
|
||||
BERT small 0.350000 0.010000 0.360000 ( 0.358929)
|
||||
BERT large 2.410000 0.560000 2.970000 ( 3.056593)
|
||||
BERT complex 7.910000 0.040000 7.950000 ( 8.236641)
|
||||
|
|
|
@ -17,12 +17,19 @@
|
|||
|
||||
static VALUE mBERT;
|
||||
static VALUE cDecode;
|
||||
static VALUE cTuple;
|
||||
void Init_decode();
|
||||
|
||||
VALUE method_decode(VALUE klass, VALUE rString);
|
||||
|
||||
VALUE read_any_raw(unsigned char **pData);
|
||||
|
||||
// printers
|
||||
|
||||
void p(VALUE val) {
|
||||
rb_funcall(rb_mKernel, rb_intern("p"), 1, val);
|
||||
}
|
||||
|
||||
// checkers
|
||||
|
||||
void check_int(int num) {
|
||||
|
@ -67,7 +74,105 @@ unsigned int read_4(unsigned char **pData) {
|
|||
return val;
|
||||
}
|
||||
|
||||
// tuples, lists
|
||||
// tuples
|
||||
|
||||
VALUE read_tuple(unsigned char **pData, int arity);
|
||||
|
||||
VALUE read_dict_pair(unsigned char **pData) {
|
||||
if(read_1(pData) != ERL_SMALL_TUPLE) {
|
||||
rb_raise(rb_eStandardError, "Invalid dict pair, not a small tuple");
|
||||
}
|
||||
|
||||
int arity = read_1(pData);
|
||||
|
||||
if(arity != 2) {
|
||||
rb_raise(rb_eStandardError, "Invalid dict pair, not a 2-tuple");
|
||||
}
|
||||
|
||||
return read_tuple(pData, arity);
|
||||
}
|
||||
|
||||
VALUE read_dict(unsigned char **pData) {
|
||||
int type = read_1(pData);
|
||||
if(!(type == ERL_LIST || type == ERL_NIL)) {
|
||||
rb_raise(rb_eStandardError, "Invalid dict spec, not an erlang list");
|
||||
}
|
||||
|
||||
int length = 0;
|
||||
if(type == ERL_LIST) {
|
||||
length = read_4(pData);
|
||||
}
|
||||
|
||||
VALUE cHash = rb_const_get(rb_cObject, rb_intern("Hash"));
|
||||
VALUE hash = rb_funcall(cHash, rb_intern("new"), 0);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < length; ++i) {
|
||||
VALUE pair = read_dict_pair(pData);
|
||||
VALUE first = rb_ary_entry(pair, 0);
|
||||
VALUE last = rb_ary_entry(pair, 1);
|
||||
rb_funcall(hash, rb_intern("store"), 2, first, last);
|
||||
}
|
||||
|
||||
if(type == ERL_LIST) {
|
||||
read_1(pData);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
VALUE read_complex_type(unsigned char **pData, int arity) {
|
||||
VALUE type = read_any_raw(pData);
|
||||
ID id = SYM2ID(type);
|
||||
if(id == rb_intern("nil")) {
|
||||
return Qnil;
|
||||
} else if(id == rb_intern("true")) {
|
||||
return Qtrue;
|
||||
} else if(id == rb_intern("false")) {
|
||||
return Qfalse;
|
||||
} else if(id == rb_intern("time")) {
|
||||
VALUE megasecs = read_any_raw(pData);
|
||||
VALUE msecs = rb_funcall(megasecs, rb_intern("*"), 1, INT2NUM(1000000));
|
||||
VALUE secs = read_any_raw(pData);
|
||||
VALUE microsecs = read_any_raw(pData);
|
||||
VALUE stamp = rb_funcall(msecs, rb_intern("+"), 1, secs);
|
||||
return rb_funcall(rb_cTime, rb_intern("at"), 2, stamp, microsecs);
|
||||
} else if(id == rb_intern("regex")) {
|
||||
VALUE source = read_any_raw(pData);
|
||||
VALUE opts = read_any_raw(pData);
|
||||
int flags = 0;
|
||||
if(rb_ary_includes(opts, ID2SYM(rb_intern("caseless"))))
|
||||
flags = flags | 1;
|
||||
if(rb_ary_includes(opts, ID2SYM(rb_intern("extended"))))
|
||||
flags = flags | 2;
|
||||
if(rb_ary_includes(opts, ID2SYM(rb_intern("multiline"))))
|
||||
flags = flags | 4;
|
||||
return rb_funcall(rb_cRegexp, rb_intern("new"), 2, source, INT2NUM(flags));
|
||||
} else if(id == rb_intern("dict")) {
|
||||
return read_dict(pData);
|
||||
} else {
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
VALUE read_tuple(unsigned char **pData, int arity) {
|
||||
if(arity > 0) {
|
||||
VALUE tag = read_any_raw(pData);
|
||||
if(SYM2ID(tag) == rb_intern("bert")) {
|
||||
return read_complex_type(pData, arity);
|
||||
} else {
|
||||
VALUE tuple = rb_funcall(cTuple, rb_intern("new"), 1, INT2NUM(arity));
|
||||
rb_ary_store(tuple, 0, tag);
|
||||
int i;
|
||||
for(i = 1; i < arity; ++i) {
|
||||
rb_ary_store(tuple, i, read_any_raw(pData));
|
||||
}
|
||||
return tuple;
|
||||
}
|
||||
} else {
|
||||
return rb_funcall(cTuple, rb_intern("new"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE read_small_tuple(unsigned char **pData) {
|
||||
if(read_1(pData) != ERL_SMALL_TUPLE) {
|
||||
|
@ -75,15 +180,7 @@ VALUE read_small_tuple(unsigned char **pData) {
|
|||
}
|
||||
|
||||
int arity = read_1(pData);
|
||||
|
||||
VALUE array = rb_ary_new2(arity);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < arity; ++i) {
|
||||
rb_ary_store(array, i, read_any_raw(pData));
|
||||
}
|
||||
|
||||
return array;
|
||||
return read_tuple(pData, arity);
|
||||
}
|
||||
|
||||
VALUE read_large_tuple(unsigned char **pData) {
|
||||
|
@ -92,17 +189,11 @@ VALUE read_large_tuple(unsigned char **pData) {
|
|||
}
|
||||
|
||||
int arity = read_4(pData);
|
||||
|
||||
VALUE array = rb_ary_new2(arity);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < arity; ++i) {
|
||||
rb_ary_store(array, i, read_any_raw(pData));
|
||||
}
|
||||
|
||||
return array;
|
||||
return read_tuple(pData, arity);
|
||||
}
|
||||
|
||||
// lists
|
||||
|
||||
VALUE read_list(unsigned char **pData) {
|
||||
if(read_1(pData) != ERL_LIST) {
|
||||
rb_raise(rb_eStandardError, "Invalid Type, not an erlang list");
|
||||
|
@ -110,8 +201,7 @@ VALUE read_list(unsigned char **pData) {
|
|||
|
||||
int size = read_4(pData);
|
||||
|
||||
VALUE list_class = rb_const_get(mBERT, rb_intern("List"));
|
||||
VALUE array = rb_funcall(list_class, rb_intern("new"), 1, INT2NUM(size));
|
||||
VALUE array = rb_ary_new2(size);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < size; ++i) {
|
||||
|
@ -154,8 +244,7 @@ VALUE read_string(unsigned char **pData) {
|
|||
unsigned char buf[length + 1];
|
||||
read_string_raw(buf, pData, length);
|
||||
|
||||
VALUE list_class = rb_const_get(mBERT, rb_intern("List"));
|
||||
VALUE array = rb_funcall(list_class, rb_intern("new"), 1, INT2NUM(length));
|
||||
VALUE array = rb_ary_new2(length);
|
||||
|
||||
int i = 0;
|
||||
for(i; i < length; ++i) {
|
||||
|
@ -279,8 +368,7 @@ VALUE read_nil(unsigned char **pData) {
|
|||
rb_raise(rb_eStandardError, "Invalid Type, not a nil list");
|
||||
}
|
||||
|
||||
VALUE list_class = rb_const_get(mBERT, rb_intern("List"));
|
||||
return rb_funcall(list_class, rb_intern("new"), 0);
|
||||
return rb_ary_new2(0);
|
||||
}
|
||||
|
||||
// read_any_raw
|
||||
|
@ -347,6 +435,7 @@ VALUE method_impl(VALUE klass) {
|
|||
void Init_decode() {
|
||||
mBERT = rb_const_get(rb_cObject, rb_intern("BERT"));
|
||||
cDecode = rb_define_class_under(mBERT, "Decode", rb_cObject);
|
||||
cTuple = rb_const_get(mBERT, rb_intern("Tuple"));
|
||||
rb_define_singleton_method(cDecode, "decode", method_decode, 1);
|
||||
rb_define_singleton_method(cDecode, "impl", method_impl, 0);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,6 @@ module BERT
|
|||
"<<" + bytes.join(',') + ">>"
|
||||
end
|
||||
|
||||
class List < Array
|
||||
def inspect
|
||||
"l#{super}"
|
||||
end
|
||||
end
|
||||
|
||||
class Tuple < Array
|
||||
def inspect
|
||||
"t#{super}"
|
||||
|
|
|
@ -24,8 +24,8 @@ module BERT
|
|||
when Symbol then write_symbol(obj)
|
||||
when Fixnum, Bignum then write_fixnum(obj)
|
||||
when Float then write_float(obj)
|
||||
when BERT::List then write_list(obj)
|
||||
when Array then write_tuple(obj)
|
||||
when Tuple then write_tuple(obj)
|
||||
when Array then write_list(obj)
|
||||
when String then write_binary(obj)
|
||||
else
|
||||
fail(obj)
|
||||
|
|
|
@ -16,27 +16,27 @@ module BERT
|
|||
def self.convert(item)
|
||||
case item
|
||||
when Hash
|
||||
pairs = List[]
|
||||
item.each_pair { |k, v| pairs << [convert(k), convert(v)] }
|
||||
[:bert, :dict, pairs]
|
||||
pairs = []
|
||||
item.each_pair { |k, v| pairs << t[convert(k), convert(v)] }
|
||||
t[:bert, :dict, pairs]
|
||||
when Tuple
|
||||
item.map { |x| convert(x) }
|
||||
Tuple.new(item.map { |x| convert(x) })
|
||||
when Array
|
||||
List.new(item.map { |x| convert(x) })
|
||||
item.map { |x| convert(x) }
|
||||
when nil
|
||||
[:bert, :nil]
|
||||
t[:bert, :nil]
|
||||
when TrueClass
|
||||
[:bert, :true]
|
||||
t[:bert, :true]
|
||||
when FalseClass
|
||||
[:bert, :false]
|
||||
t[:bert, :false]
|
||||
when Time
|
||||
[:bert, :time, item.to_i / 1_000_000, item.to_i % 1_000_000, item.usec]
|
||||
t[:bert, :time, item.to_i / 1_000_000, item.to_i % 1_000_000, item.usec]
|
||||
when Regexp
|
||||
options = List[]
|
||||
options = []
|
||||
options << :caseless if item.options & Regexp::IGNORECASE > 0
|
||||
options << :extended if item.options & Regexp::EXTENDED > 0
|
||||
options << :multiline if item.options & Regexp::MULTILINE > 0
|
||||
[:bert, :regex, item.source, options]
|
||||
t[:bert, :regex, item.source, options]
|
||||
else
|
||||
item
|
||||
end
|
||||
|
|
|
@ -1,64 +1,76 @@
|
|||
require 'test_helper'
|
||||
|
||||
class DecoderTest < Test::Unit::TestCase
|
||||
context "BERT Decoder complex type converter" do
|
||||
# should "convert nil" do
|
||||
# before = t[:bert, :nil]
|
||||
# after = nil
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "convert nested nil" do
|
||||
# before = [t[:bert, :nil], [t[:bert, :nil]]]
|
||||
# after = [nil, [nil]]
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "convert hashes" do
|
||||
# before = t[:bert, :dict, [[:foo, 'bar']]]
|
||||
# after = {:foo => 'bar'}
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "convert empty hashes" do
|
||||
# before = t[:bert, :dict, []]
|
||||
# after = {}
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "convert nested hashes" do
|
||||
# before = t[:bert, :dict, [[:foo, t[:bert, :dict, [[:baz, 'bar']]]]]]
|
||||
# after = {:foo => {:baz => 'bar'}}
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
BERT_NIL = [131,104,2,100,0,4,98,101,114,116,100,0,3,110,105,108].pack('c*')
|
||||
BERT_TRUE = [131,104,2,100,0,4,98,101,114,116,100,0,4,116,114,117,101].pack('c*')
|
||||
BERT_FALSE = [131,104,2,100,0,4,98,101,114,116,100,0,5,102,97,108,115,101].pack('c*')
|
||||
|
||||
should "convert true" do
|
||||
# {bert, true}
|
||||
bert = [131,104,2,100,0,4,98,101,114,116,100,0,4,116,114,117,101].pack('c*')
|
||||
assert_equal true, BERT::Decoder.decode(bert)
|
||||
context "BERT Decoder complex type converter" do
|
||||
should "convert nil" do
|
||||
assert_equal nil, BERT::Decoder.decode(BERT_NIL)
|
||||
end
|
||||
|
||||
# should "convert false" do
|
||||
# before = t[:bert, :false]
|
||||
# after = false
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "convert times" do
|
||||
# before = t[:bert, :time, 1254, 976067, 0]
|
||||
# after = Time.at(1254976067)
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "convert regexen" do
|
||||
# before = t[:bert, :regex, '^c(a)t$', [:caseless, :extended]]
|
||||
# after = /^c(a)t$/ix
|
||||
# assert_equal after, BERT::Decoder.convert(before)
|
||||
# end
|
||||
#
|
||||
# should "leave other stuff alone" do
|
||||
# before = [1, 2.0, [:foo, 'bar']]
|
||||
# assert_equal before, BERT::Decoder.convert(before)
|
||||
# end
|
||||
should "convert nested nil" do
|
||||
bert = [131,108,0,0,0,2,104,2,100,0,4,98,101,114,116,100,0,3,110,105,
|
||||
108,108,0,0,0,1,104,2,100,0,4,98,101,114,116,100,0,3,110,105,
|
||||
108,106,106].pack('c*')
|
||||
assert_equal [nil, [nil]], BERT::Decoder.decode(bert)
|
||||
end
|
||||
|
||||
should "convert hashes" do
|
||||
bert = [131,104,3,100,0,4,98,101,114,116,100,0,4,100,105,99,116,108,
|
||||
0,0,0,1,104,2,100,0,3,102,111,111,109,0,0,0,3,98,97,114,
|
||||
106].pack('c*')
|
||||
after = {:foo => 'bar'}
|
||||
assert_equal after, BERT::Decoder.decode(bert)
|
||||
end
|
||||
|
||||
should "convert empty hashes" do
|
||||
bert = [131,104,3,100,0,4,98,101,114,116,100,0,4,100,105,99,116,
|
||||
106].pack('c*')
|
||||
after = {}
|
||||
assert_equal after, BERT::Decoder.decode(bert)
|
||||
end
|
||||
|
||||
should "convert nested hashes" do
|
||||
bert = [131,104,3,100,0,4,98,101,114,116,100,0,4,100,105,99,116,108,0,
|
||||
0,0,1,104,2,100,0,3,102,111,111,104,3,100,0,4,98,101,114,116,
|
||||
100,0,4,100,105,99,116,108,0,0,0,1,104,2,100,0,3,98,97,122,109,
|
||||
0,0,0,3,98,97,114,106,106].pack('c*')
|
||||
after = {:foo => {:baz => 'bar'}}
|
||||
assert_equal after, BERT::Decoder.decode(bert)
|
||||
end
|
||||
|
||||
should "convert true" do
|
||||
assert_equal true, BERT::Decoder.decode(BERT_TRUE)
|
||||
end
|
||||
|
||||
should "convert false" do
|
||||
assert_equal false, BERT::Decoder.decode(BERT_FALSE)
|
||||
end
|
||||
|
||||
should "convert times" do
|
||||
bert = [131,104,5,100,0,4,98,101,114,116,100,0,4,116,105,109,101,98,0,
|
||||
0,4,230,98,0,14,228,195,97,0].pack('c*')
|
||||
after = Time.at(1254976067)
|
||||
assert_equal after, BERT::Decoder.decode(bert)
|
||||
end
|
||||
|
||||
should "convert regexen" do
|
||||
bert = [131,104,4,100,0,4,98,101,114,116,100,0,5,114,101,103,101,120,
|
||||
109,0,0,0,7,94,99,40,97,41,116,36,108,0,0,0,2,100,0,8,99,97,
|
||||
115,101,108,101,115,115,100,0,8,101,120,116,101,110,100,101,
|
||||
100,106].pack('c*')
|
||||
after = /^c(a)t$/ix
|
||||
assert_equal after, BERT::Decoder.decode(bert)
|
||||
end
|
||||
|
||||
should "leave other stuff alone" do
|
||||
bert = [131,108,0,0,0,3,97,1,99,50,46,48,48,48,48,48,48,48,48,48,48,48,
|
||||
48,48,48,48,48,48,48,48,48,101,43,48,48,0,0,0,0,0,108,0,0,0,2,
|
||||
100,0,3,102,111,111,109,0,0,0,3,98,97,114,106,106].pack('c*')
|
||||
after = [1, 2.0, [:foo, 'bar']]
|
||||
assert_equal after, BERT::Decoder.decode(bert)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,7 +27,7 @@ class EncoderTest < Test::Unit::TestCase
|
|||
should "convert hash to tuple with array of tuples" do
|
||||
arr = BERT::Encoder.convert({:foo => 'bar'})
|
||||
assert arr.is_a?(Array)
|
||||
assert arr[2].is_a?(BERT::List)
|
||||
assert arr[2].is_a?(Array)
|
||||
assert arr[2][0].is_a?(Array)
|
||||
end
|
||||
|
||||
|
@ -38,13 +38,13 @@ class EncoderTest < Test::Unit::TestCase
|
|||
|
||||
should "convert array to erl list" do
|
||||
list = BERT::Encoder.convert([1, 2])
|
||||
assert list.is_a?(BERT::List)
|
||||
assert list.is_a?(Array)
|
||||
end
|
||||
|
||||
should "convert an array in a tuple" do
|
||||
arrtup = BERT::Encoder.convert(t[:foo, [1, 2]])
|
||||
assert arrtup.is_a?(Array)
|
||||
assert arrtup[1].is_a?(BERT::List)
|
||||
assert arrtup[1].is_a?(Array)
|
||||
end
|
||||
|
||||
should "convert true" do
|
||||
|
@ -74,9 +74,9 @@ class EncoderTest < Test::Unit::TestCase
|
|||
should "properly convert types" do
|
||||
ruby = t[:user, {:name => 'TPW'}, [/cat/i, 9.9], nil, true, false, :true, :false]
|
||||
cruby = BERT::Encoder.convert(ruby)
|
||||
assert cruby.instance_of?(Array)
|
||||
assert cruby.instance_of?(BERT::Tuple)
|
||||
assert cruby[0].instance_of?(Symbol)
|
||||
assert cruby[1].instance_of?(Array)
|
||||
assert cruby[1].instance_of?(BERT::Tuple)
|
||||
end
|
||||
|
||||
should "leave other stuff alone" do
|
||||
|
|
Загрузка…
Ссылка в новой задаче