json-bloomfilter 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json-bloomfilter (0.0.2)
4
+ json-bloomfilter (0.0.3)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/README.md CHANGED
@@ -4,6 +4,8 @@ A bloomfilter implementation in both Ruby and Javascript that can be serialised
4
4
 
5
5
  ## Release notes
6
6
 
7
+ * **0.0.3** Added Ruby tests
8
+ * **0.0.2** First implementation of both Ruby and JS filters
7
9
  * **0.0.1** Skeleton
8
10
 
9
11
  ## License
data/Rakefile CHANGED
@@ -54,7 +54,7 @@ namespace :js do
54
54
  coffee_script += File.read(filename) + "\n"
55
55
  end
56
56
 
57
- js_file = "js/bloomfilter.js"
57
+ js_file = "js/json-bloomfilter.js"
58
58
  directory_name = File.dirname js_file
59
59
  FileUtils.mkdir_p(directory_name) unless File.exists? directory_name
60
60
  puts "\t\t->#{js_file}"
@@ -68,8 +68,8 @@ namespace :js do
68
68
  filename = args[:filename]
69
69
  compressor = YUI::JavaScriptCompressor.new
70
70
 
71
- js_file = "js/bloomfilter.js"
72
- min_file = "js/bloomfilter.min.js"
71
+ js_file = "js/json-bloomfilter.js"
72
+ min_file = "js/json-bloomfilter.min.js"
73
73
 
74
74
  puts "\t\t->#{min_file}"
75
75
  directory_name = File.dirname min_file
@@ -1,46 +1,43 @@
1
- JsonBloomfilter.BitArray =
2
- size: null
3
- field: null
4
-
5
- ELEMENT_WIDTH: 32
6
-
7
- new: (size, field = null) ->
8
- @size = size
9
- arrayLength = Math.floor(((size - 1) / @ELEMENT_WIDTH) + 1)
10
- @field = field || []
11
- @field[i] = 0 for i in [0..arrayLength] unless field
12
- this
13
-
14
- add: (position) ->
15
- @set(position, 1)
16
-
17
- remove: (position) ->
18
- @set(position, 0)
19
-
20
- set: (position, value) ->
21
- aPos = @arrayPosition(position)
22
- bChange = @bitChange(position)
23
- if value == 1
24
- @field[aPos] |= bChange
25
- else if @field[aPos] & bChange != 0
26
- @field[aPos] ^= bChange
27
- true
28
-
29
- get: (position) ->
30
- aPos = @arrayPosition(position)
31
- bChange = @bitChange(position)
32
- if (@field[aPos] & bChange) > 0
33
- return 1
34
- else
35
- return 0
36
-
37
- arrayPosition: (position) ->
38
- Math.floor(position / @ELEMENT_WIDTH)
39
-
40
- bitChange: (position) ->
41
- Math.abs(1 << position % @ELEMENT_WIDTH)
42
-
43
- toString: ->
44
- output = ""
45
- output += @get(i) for i in [0..@size-1]
46
- output
1
+ JsonBloomfilter.BitArray = (size, field = null) ->
2
+ @ELEMENT_WIDTH = 32
3
+ @size = size
4
+ @field = field || []
5
+
6
+ arrayLength = Math.floor(((size - 1) / @ELEMENT_WIDTH) + 1)
7
+ @field[i] = 0 for i in [0..arrayLength] unless field
8
+
9
+ this
10
+
11
+ JsonBloomfilter.BitArray.prototype.add = (position) ->
12
+ @set(position, 1)
13
+
14
+ JsonBloomfilter.BitArray.prototype.remove = (position) ->
15
+ @set(position, 0)
16
+
17
+ JsonBloomfilter.BitArray.prototype.set = (position, value) ->
18
+ aPos = @arrayPosition(position)
19
+ bChange = @bitChange(position)
20
+ if value == 1
21
+ @field[aPos] |= bChange
22
+ else if @field[aPos] & bChange != 0
23
+ @field[aPos] ^= bChange
24
+ true
25
+
26
+ JsonBloomfilter.BitArray.prototype.get = (position) ->
27
+ aPos = @arrayPosition(position)
28
+ bChange = @bitChange(position)
29
+ if (@field[aPos] & bChange) > 0
30
+ return 1
31
+ else
32
+ return 0
33
+
34
+ JsonBloomfilter.BitArray.prototype.arrayPosition = (position) ->
35
+ Math.floor(position / @ELEMENT_WIDTH)
36
+
37
+ JsonBloomfilter.BitArray.prototype.bitChange = (position) ->
38
+ Math.abs(1 << position % @ELEMENT_WIDTH)
39
+
40
+ JsonBloomfilter.BitArray.prototype.toString = ->
41
+ output = ""
42
+ output += @get(i) for i in [0..@size-1]
43
+ output
@@ -1,40 +1,38 @@
1
- JsonBloomfilter =
2
- bits: null
3
- options:
1
+ JsonBloomfilter = (options = {}) ->
2
+ @options =
4
3
  size: 100,
5
4
  hashes: 4,
6
5
  seed: (new Date().getTime() / 1000),
7
6
  bits: null
8
7
 
9
- new: (options = {}) ->
10
- @options[key] = value for key, value of options
11
- @bits = @BitArray.new(@options["size"], @options["bits"])
12
- this
8
+ @options[key] = value for key, value of options
9
+ @bits = new JsonBloomfilter.BitArray(@options["size"], @options["bits"])
10
+ this
13
11
 
14
- add: (key) ->
15
- @bits.add(index) for index in @indexesFor(key)
16
- return
12
+ JsonBloomfilter.prototype.add = (key) ->
13
+ @bits.add(index) for index in @indexesFor(key)
14
+ return
17
15
 
18
- test: (key) ->
19
- for index in @indexesFor(key)
20
- return false if @bits.get(index) == 0
21
- true
16
+ JsonBloomfilter.prototype.test = (key) ->
17
+ for index in @indexesFor(key)
18
+ return false if @bits.get(index) == 0
19
+ true
22
20
 
23
- clear: ->
24
- @bits = @BitArray.new(@options["size"], null)
25
- return
21
+ JsonBloomfilter.prototype.clear = ->
22
+ @bits = @BitArray.new(@options["size"], null)
23
+ return
26
24
 
27
- toHash: ->
28
- hash = {}
29
- hash[key] = value for key, value of @options
30
- hash["bits"] = @bits.field
31
- hash
25
+ JsonBloomfilter.prototype.toHash = ->
26
+ hash = {}
27
+ hash[key] = value for key, value of @options
28
+ hash["bits"] = @bits.field
29
+ hash
32
30
 
33
- toJson: ->
34
- JSON.stringify @toHash()
31
+ JsonBloomfilter.prototype.toJson = ->
32
+ JSON.stringify @toHash()
35
33
 
36
- indexesFor: (key) ->
37
- indexes = []
38
- for index in [0..@options["hashes"]-1]
39
- indexes.push (@Zlib.crc32("#{key}:#{index+@options["seed"]}") % @options["size"])
40
- indexes
34
+ JsonBloomfilter.prototype.indexesFor = (key) ->
35
+ indexes = []
36
+ for index in [0..@options["hashes"]-1]
37
+ indexes.push (JsonBloomfilter.Zlib.crc32("#{key}:#{index+@options["seed"]}") % @options["size"])
38
+ indexes
data/coffee/zlib.coffee CHANGED
@@ -28,4 +28,4 @@ JsonBloomfilter.Zlib =
28
28
  while i < string.length
29
29
  bytes.push string.charCodeAt(i)
30
30
  ++i
31
- bytes
31
+ bytes
@@ -0,0 +1 @@
1
+ var JsonBloomfilter;JsonBloomfilter=function(options){var key,value;if(options==null){options={}}this.options={size:100,hashes:4,seed:new Date().getTime()/1000,bits:null};for(key in options){value=options[key];this.options[key]=value}this.bits=new JsonBloomfilter.BitArray(this.options.size,this.options.bits);return this};JsonBloomfilter.prototype.add=function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];this.bits.add(index)}};JsonBloomfilter.prototype.test=function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];if(this.bits.get(index)===0){return false}}return true};JsonBloomfilter.prototype.clear=function(){this.bits=this.BitArray["new"](this.options.size,null)};JsonBloomfilter.prototype.toHash=function(){var hash,key,value,_ref;hash={};_ref=this.options;for(key in _ref){value=_ref[key];hash[key]=value}hash.bits=this.bits.field;return hash};JsonBloomfilter.prototype.toJson=function(){return JSON.stringify(this.toHash())};JsonBloomfilter.prototype.indexesFor=function(key){var index,indexes,_i,_ref;indexes=[];for(index=_i=0,_ref=this.options.hashes-1;0<=_ref?_i<=_ref:_i>=_ref;index=0<=_ref?++_i:--_i){indexes.push(JsonBloomfilter.Zlib.crc32(""+key+":"+(index+this.options.seed))%this.options.size)}return indexes};JsonBloomfilter.BitArray=function(size,field){var arrayLength,i,_i;if(field==null){field=null}this.ELEMENT_WIDTH=32;this.size=size;this.field=field||[];arrayLength=Math.floor(((size-1)/this.ELEMENT_WIDTH)+1);if(!field){for(i=_i=0;0<=arrayLength?_i<=arrayLength:_i>=arrayLength;i=0<=arrayLength?++_i:--_i){this.field[i]=0}}return this};JsonBloomfilter.BitArray.prototype.add=function(position){return this.set(position,1)};JsonBloomfilter.BitArray.prototype.remove=function(position){return this.set(position,0)};JsonBloomfilter.BitArray.prototype.set=function(position,value){var aPos,bChange;aPos=this.arrayPosition(position);bChange=this.bitChange(position);if(value===1){this.field[aPos]|=bChange}else{if(this.field[aPos]&bChange!==0){this.field[aPos]^=bChange}}return true};JsonBloomfilter.BitArray.prototype.get=function(position){var aPos,bChange;aPos=this.arrayPosition(position);bChange=this.bitChange(position);if((this.field[aPos]&bChange)>0){return 1}else{return 0}};JsonBloomfilter.BitArray.prototype.arrayPosition=function(position){return Math.floor(position/this.ELEMENT_WIDTH)};JsonBloomfilter.BitArray.prototype.bitChange=function(position){return Math.abs(1<<position%this.ELEMENT_WIDTH)};JsonBloomfilter.BitArray.prototype.toString=function(){var i,output,_i,_ref;output="";for(i=_i=0,_ref=this.size-1;0<=_ref?_i<=_ref:_i>=_ref;i=0<=_ref?++_i:--_i){output+=this.get(i)}return output};JsonBloomfilter.Zlib={CRC32_TABLE:new Array(0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918000,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117),crc32:function(string){var bytes,crc,i,iTop,n;bytes=this.bytesFor(string);crc=0;n=0;crc=crc^(-1);i=0;iTop=bytes.length;while(i<iTop){n=(crc^bytes[i])&255;crc=(crc>>>8)^this.CRC32_TABLE[n];i++}crc=crc^(-1);if(crc<0){crc+=4294967296}return crc},bytesFor:function(string){var bytes,i;bytes=[];i=0;while(i<string.length){bytes.push(string.charCodeAt(i));++i}return bytes}};
@@ -1,28 +1,28 @@
1
- require_relative "bitarray"
1
+ require_relative "bloomfilter/bitarray"
2
2
  require "json"
3
3
 
4
4
  class JsonBloomfilter
5
5
  DEFAULTS = { "size" => 100, "hashes" => 4, "seed" => Time.new.to_i, "bits" => nil }
6
6
 
7
7
  def initialize options = {}
8
- @options = DEFAULTS.merge options
8
+ @options = merge_defaults_with options
9
9
  @bits = BitArray.new(@options["size"], @options["bits"])
10
10
  end
11
11
 
12
12
  def add key
13
- indexes_for(key).each { |index| @bits[index] = 1 }
13
+ indexes_for(key).each { |index| @bits.add(index) }
14
14
  nil
15
15
  end
16
16
 
17
17
  def test key
18
18
  indexes_for(key).each do |index|
19
- return false if @bits[index] == 0
19
+ return false if @bits.get(index) == 0
20
20
  end
21
21
  true
22
22
  end
23
23
 
24
24
  def clear
25
- @bits = BitArray.new(@options["size"], 0)
25
+ @bits = BitArray.new(@options["size"])
26
26
  end
27
27
 
28
28
  def to_hash
@@ -40,4 +40,8 @@ class JsonBloomfilter
40
40
  Zlib.crc32("#{key}:#{index+@options["seed"]}") % @options["size"]
41
41
  end
42
42
  end
43
+
44
+ def merge_defaults_with options
45
+ DEFAULTS.merge Hash[options.map {|k, v| ["#{k}", v] }]
46
+ end
43
47
  end
@@ -0,0 +1,51 @@
1
+ # Adapted from
2
+ # https://github.com/peterc/bitarray
3
+
4
+ class JsonBloomfilter
5
+ class BitArray
6
+ attr_reader :size
7
+ attr_reader :field
8
+ include Enumerable
9
+
10
+ ELEMENT_WIDTH = 32
11
+
12
+ def initialize(size, field = nil)
13
+ @size = size
14
+ @field = field || Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
15
+ end
16
+
17
+ def add position
18
+ self[position] = 1
19
+ end
20
+
21
+ def remove position
22
+ self[position] = 0
23
+ end
24
+
25
+ # Set a bit (1/0)
26
+ def []=(position, value)
27
+ raise ArgumentError.new("Position out of bound (#{position} for max #{@size})") if position >= @size
28
+ if value == 1
29
+ @field[position / ELEMENT_WIDTH] |= 1 << (position % ELEMENT_WIDTH)
30
+ elsif (@field[position / ELEMENT_WIDTH]) & (1 << (position % ELEMENT_WIDTH)) != 0
31
+ @field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
32
+ end
33
+ end
34
+
35
+ # Read a bit (1/0)
36
+ def get position
37
+ raise ArgumentError.new("Position out of bound (#{position} for max #{@size})") if position >= @size
38
+ @field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
39
+ end
40
+
41
+ # Iterate over each bit
42
+ def each(&block)
43
+ @size.times { |position| yield self.get(position) }
44
+ end
45
+
46
+ # Returns the field as a string like "0101010100111100," etc.
47
+ def to_s
48
+ inject("") { |a, b| a + b.to_s }
49
+ end
50
+ end
51
+ end
@@ -1,3 +1,3 @@
1
1
  class JsonBloomfilter
2
- VERSION = "0.0.2" unless defined? Trifle::VERSION
2
+ VERSION = "0.0.3" unless defined? Trifle::VERSION
3
3
  end
Binary file
@@ -0,0 +1,66 @@
1
+ require "spec_helper"
2
+
3
+ describe JsonBloomfilter::BitArray do
4
+
5
+ describe "#initialize" do
6
+ it "should require a size" do
7
+ expect(->{JsonBloomfilter::BitArray.new}).to raise_error(ArgumentError)
8
+ expect(->{JsonBloomfilter::BitArray.new(100)}).not_to raise_error(ArgumentError)
9
+ end
10
+ it "should take an optional bit field" do
11
+ field = [0,0,0,2]
12
+ ba = JsonBloomfilter::BitArray.new(100, field)
13
+ expect(ba.field).to be == field
14
+ end
15
+ end
16
+
17
+ describe "add" do
18
+ it "should set the bit to 1" do
19
+ ba = JsonBloomfilter::BitArray.new(10)
20
+ ba.add(9)
21
+ expect(ba.to_s).to be == "0000000001"
22
+ end
23
+
24
+ it "should throw an error on out of bound" do
25
+ ba = JsonBloomfilter::BitArray.new(10)
26
+ expect(->{ba.add(10)}).to raise_error
27
+ end
28
+ end
29
+
30
+ describe "remove" do
31
+ it "should set the bit to 0" do
32
+ ba = JsonBloomfilter::BitArray.new(10)
33
+ ba.add(9)
34
+ ba.remove(9)
35
+ expect(ba.to_s).to be == "0000000000"
36
+ end
37
+
38
+ it "should throw an error on out of bound" do
39
+ ba = JsonBloomfilter::BitArray.new(10)
40
+ expect(->{ba.remove(10)}).to raise_error
41
+ end
42
+ end
43
+
44
+ describe "get" do
45
+ it "should return the bit set" do
46
+ ba = JsonBloomfilter::BitArray.new(10)
47
+ ba.add(9)
48
+ expect(ba.get(9)).to be == 1
49
+ expect(ba.get(8)).to be == 0
50
+ end
51
+
52
+ it "should throw an error on out of bound" do
53
+ ba = JsonBloomfilter::BitArray.new(10)
54
+ expect(->{ba.get(10)}).to raise_error
55
+ end
56
+ end
57
+
58
+ describe "#to_s" do
59
+ it "should output the bit string" do
60
+ ba = JsonBloomfilter::BitArray.new(10)
61
+ ba.add(3)
62
+ ba.add(9)
63
+ expect(ba.to_s).to be == "0001000001"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,78 @@
1
+ require "spec_helper"
2
+
3
+ describe JsonBloomfilter do
4
+
5
+ describe "#initialize" do
6
+ it "should take the appropriate options" do
7
+ seed = Time.now.to_i - 24*60*60
8
+ bf = JsonBloomfilter.new size: 200, hashes: 10, seed: seed
9
+ expect(bf.to_hash["size"]).to be == 200
10
+ expect(bf.to_hash["hashes"]).to be == 10
11
+ expect(bf.to_hash["seed"]).to be == seed
12
+ end
13
+
14
+ it "should be initializable with a field serialized by another bloom filter" do
15
+ bf1 = JsonBloomfilter.new
16
+ bf1.add "foo"
17
+ bf2 = JsonBloomfilter.new bf1.to_hash
18
+ expect(bf2.test "foo").to be_true
19
+ end
20
+ end
21
+
22
+ context "with an instance" do
23
+ before :each do
24
+ @bf = JsonBloomfilter.new
25
+ @bf.add("foobar")
26
+ end
27
+
28
+ describe "#add, #test" do
29
+ it "should add a key" do
30
+ expect(@bf.test "foo").to be_false
31
+ @bf.add "foo"
32
+ expect(@bf.test "foo").to be_true
33
+ end
34
+
35
+ it "should not change anything if added twice" do
36
+ expect(@bf.test "foobar").to be_true
37
+ bits = @bf.to_hash["bits"]
38
+ @bf.add "foobar"
39
+ expect(@bf.test "foobar").to be_true
40
+ expect(@bf.to_hash["bits"]).to be == bits
41
+ end
42
+ end
43
+
44
+ describe "#clear" do
45
+ it "should clear the bit array" do
46
+ expect(@bf.to_hash["bits"]).not_to be == [0,0,0,0]
47
+ @bf.clear
48
+ expect(@bf.to_hash["bits"]).to be == [0,0,0,0]
49
+ end
50
+ end
51
+
52
+ describe "#to_hash" do
53
+ it "should return the serialisable hash" do
54
+ hash = @bf.to_hash
55
+ expect(hash).to be_a(Hash)
56
+
57
+ expect(hash).to have_key("seed")
58
+ expect(hash["seed"]).to be_a(Integer)
59
+
60
+ expect(hash).to have_key("hashes")
61
+ expect(hash["hashes"]).to be_a(Integer)
62
+
63
+ expect(hash).to have_key("size")
64
+ expect(hash["size"]).to be_a(Integer)
65
+
66
+ expect(hash).to have_key("bits")
67
+ expect(hash["bits"]).to be_a(Array)
68
+ end
69
+ end
70
+
71
+ describe "#to_json" do
72
+ it "should return the hash serialised" do
73
+ expect(@bf.to_json).to be == JSON.generate(@bf.to_hash)
74
+ end
75
+ end
76
+
77
+ end
78
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,2 @@
1
1
  require "json/bloomfilter"
2
+ require "json/bloomfilter/bitarray"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-bloomfilter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -116,6 +116,7 @@ executables: []
116
116
  extensions: []
117
117
  extra_rdoc_files: []
118
118
  files:
119
+ - .rspec
119
120
  - .rvmrc
120
121
  - Gemfile
121
122
  - Gemfile.lock
@@ -125,14 +126,15 @@ files:
125
126
  - coffee/bitarray.coffee
126
127
  - coffee/bloomfilter.coffee
127
128
  - coffee/zlib.coffee
128
- - js/bloomfilter.min.js
129
+ - js/json-bloomfilter.min.js
129
130
  - json-bloomfilter.gemspec
130
- - lib/json/bitarray.rb
131
131
  - lib/json/bloomfilter.rb
132
+ - lib/json/bloomfilter/bitarray.rb
132
133
  - lib/json/bloomfilter/version.rb
133
134
  - pkg/json-bloomfilter-0.0.1.gem
134
135
  - pkg/json-bloomfilter-0.0.2.gem
135
- - spec/json-bloomfilter_spec.rb
136
+ - spec/json/bloomfilter/bitarray_spec.rb
137
+ - spec/json/bloomfilter_spec.rb
136
138
  - spec/spec_helper.rb
137
139
  homepage: http://github.com/cbetta/json-bloomfilter
138
140
  licenses:
@@ -155,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
157
  version: '0'
156
158
  segments:
157
159
  - 0
158
- hash: 1888125834509649748
160
+ hash: 2570443821793762265
159
161
  requirements: []
160
162
  rubyforge_project:
161
163
  rubygems_version: 1.8.24
@@ -163,5 +165,6 @@ signing_key:
163
165
  specification_version: 3
164
166
  summary: A bloomfilter implementation in both Ruby and Javascript.
165
167
  test_files:
166
- - spec/json-bloomfilter_spec.rb
168
+ - spec/json/bloomfilter/bitarray_spec.rb
169
+ - spec/json/bloomfilter_spec.rb
167
170
  - spec/spec_helper.rb
@@ -1 +0,0 @@
1
- var JsonBloomfilter;JsonBloomfilter={bits:null,options:{size:100,hashes:4,seed:new Date().getTime()/1000,bits:null},"new":function(options){var key,value;if(options==null){options={}}for(key in options){value=options[key];this.options[key]=value}this.bits=this.BitArray["new"](this.options.size,this.options.bits);return this},add:function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];this.bits.add(index)}},test:function(key){var index,_i,_len,_ref;_ref=this.indexesFor(key);for(_i=0,_len=_ref.length;_i<_len;_i++){index=_ref[_i];if(this.bits.get(index)===0){return false}}return true},clear:function(){this.bits=this.BitArray["new"](this.options.size,null)},toHash:function(){var hash,key,value,_ref;hash={};_ref=this.options;for(key in _ref){value=_ref[key];hash[key]=value}hash.bits=this.bits.field;return hash},toJson:function(){return JSON.stringify(this.toHash())},indexesFor:function(key){var index,indexes,_i,_ref;indexes=[];for(index=_i=0,_ref=this.options.hashes-1;0<=_ref?_i<=_ref:_i>=_ref;index=0<=_ref?++_i:--_i){indexes.push(this.Zlib.crc32(""+key+":"+(index+this.options.seed))%this.options.size)}return indexes}};JsonBloomfilter.BitArray={size:null,field:null,ELEMENT_WIDTH:32,"new":function(size,field){var arrayLength,i,_i;if(field==null){field=null}this.size=size;arrayLength=Math.floor(((size-1)/this.ELEMENT_WIDTH)+1);this.field=field||[];if(!field){for(i=_i=0;0<=arrayLength?_i<=arrayLength:_i>=arrayLength;i=0<=arrayLength?++_i:--_i){this.field[i]=0}}return this},add:function(position){return this.set(position,1)},remove:function(position){return this.set(position,0)},set:function(position,value){var aPos,bChange;aPos=this.arrayPosition(position);bChange=this.bitChange(position);if(value===1){this.field[aPos]|=bChange}else{if(this.field[aPos]&bChange!==0){this.field[aPos]^=bChange}}return true},get:function(position){var aPos,bChange;aPos=this.arrayPosition(position);bChange=this.bitChange(position);if((this.field[aPos]&bChange)>0){return 1}else{return 0}},arrayPosition:function(position){return Math.floor(position/this.ELEMENT_WIDTH)},bitChange:function(position){return Math.abs(1<<position%this.ELEMENT_WIDTH)},toString:function(){var i,output,_i,_ref;output="";for(i=_i=0,_ref=this.size-1;0<=_ref?_i<=_ref:_i>=_ref;i=0<=_ref?++_i:--_i){output+=this.get(i)}return output}};JsonBloomfilter.Zlib={CRC32_TABLE:new Array(0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918000,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117),crc32:function(string){var bytes,crc,i,iTop,n;bytes=this.bytesFor(string);crc=0;n=0;crc=crc^(-1);i=0;iTop=bytes.length;while(i<iTop){n=(crc^bytes[i])&255;crc=(crc>>>8)^this.CRC32_TABLE[n];i++}crc=crc^(-1);if(crc<0){crc+=4294967296}return crc},bytesFor:function(string){var bytes,i;bytes=[];i=0;while(i<string.length){bytes.push(string.charCodeAt(i));++i}return bytes}};
data/lib/json/bitarray.rb DELETED
@@ -1,45 +0,0 @@
1
- # Adapted from
2
- # https://github.com/peterc/bitarray
3
-
4
- class BitArray
5
- attr_reader :size
6
- attr_reader :field
7
- include Enumerable
8
-
9
- ELEMENT_WIDTH = 32
10
-
11
- def initialize(size, field = nil)
12
- @size = size
13
- @field = field || Array.new(((size - 1) / ELEMENT_WIDTH) + 1, 0)
14
- end
15
-
16
- # Set a bit (1/0)
17
- def []=(position, value)
18
- if value == 1
19
- @field[position / ELEMENT_WIDTH] |= 1 << (position % ELEMENT_WIDTH)
20
- elsif (@field[position / ELEMENT_WIDTH]) & (1 << (position % ELEMENT_WIDTH)) != 0
21
- @field[position / ELEMENT_WIDTH] ^= 1 << (position % ELEMENT_WIDTH)
22
- end
23
- end
24
-
25
- # Read a bit (1/0)
26
- def [](position)
27
- @field[position / ELEMENT_WIDTH] & 1 << (position % ELEMENT_WIDTH) > 0 ? 1 : 0
28
- end
29
-
30
- # Iterate over each bit
31
- def each(&block)
32
- @size.times { |position| yield self[position] }
33
- end
34
-
35
- # Returns the field as a string like "0101010100111100," etc.
36
- def to_s
37
- inject("") { |a, b| a + b.to_s }
38
- end
39
-
40
- # Returns the total number of bits that are set
41
- # (The technique used here is about 6 times faster than using each or inject direct on the bitfield)
42
- def total_set
43
- @field.inject(0) { |a, byte| a += byte & 1 and byte >>= 1 until byte == 0; a }
44
- end
45
- end
@@ -1,9 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe JsonBloomfilter do
4
-
5
- it "should pass" do
6
- bf = JsonBloomfilter.new
7
- end
8
-
9
- end