strokedb 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +7 -0
- data/CREDITS +13 -0
- data/README +44 -0
- data/bin/sdbc +2 -0
- data/lib/config/config.rb +161 -0
- data/lib/data_structures/inverted_list.rb +297 -0
- data/lib/data_structures/point_query.rb +24 -0
- data/lib/data_structures/skiplist.rb +302 -0
- data/lib/document/associations.rb +107 -0
- data/lib/document/callback.rb +11 -0
- data/lib/document/coercions.rb +57 -0
- data/lib/document/delete.rb +28 -0
- data/lib/document/document.rb +684 -0
- data/lib/document/meta.rb +261 -0
- data/lib/document/slot.rb +199 -0
- data/lib/document/util.rb +27 -0
- data/lib/document/validations.rb +704 -0
- data/lib/document/versions.rb +106 -0
- data/lib/document/virtualize.rb +82 -0
- data/lib/init.rb +57 -0
- data/lib/stores/chainable_storage.rb +57 -0
- data/lib/stores/inverted_list_index/inverted_list_file_storage.rb +56 -0
- data/lib/stores/inverted_list_index/inverted_list_index.rb +49 -0
- data/lib/stores/remote_store.rb +172 -0
- data/lib/stores/skiplist_store/chunk.rb +119 -0
- data/lib/stores/skiplist_store/chunk_storage.rb +21 -0
- data/lib/stores/skiplist_store/file_chunk_storage.rb +44 -0
- data/lib/stores/skiplist_store/memory_chunk_storage.rb +37 -0
- data/lib/stores/skiplist_store/skiplist_store.rb +217 -0
- data/lib/stores/store.rb +5 -0
- data/lib/sync/chain_sync.rb +38 -0
- data/lib/sync/diff.rb +126 -0
- data/lib/sync/lamport_timestamp.rb +81 -0
- data/lib/sync/store_sync.rb +79 -0
- data/lib/sync/stroke_diff/array.rb +102 -0
- data/lib/sync/stroke_diff/default.rb +21 -0
- data/lib/sync/stroke_diff/hash.rb +186 -0
- data/lib/sync/stroke_diff/string.rb +116 -0
- data/lib/sync/stroke_diff/stroke_diff.rb +9 -0
- data/lib/util/blankslate.rb +42 -0
- data/lib/util/ext/blank.rb +50 -0
- data/lib/util/ext/enumerable.rb +36 -0
- data/lib/util/ext/fixnum.rb +16 -0
- data/lib/util/ext/hash.rb +22 -0
- data/lib/util/ext/object.rb +8 -0
- data/lib/util/ext/string.rb +35 -0
- data/lib/util/inflect.rb +217 -0
- data/lib/util/java_util.rb +9 -0
- data/lib/util/lazy_array.rb +54 -0
- data/lib/util/lazy_mapping_array.rb +64 -0
- data/lib/util/lazy_mapping_hash.rb +46 -0
- data/lib/util/serialization.rb +29 -0
- data/lib/util/trigger_partition.rb +136 -0
- data/lib/util/util.rb +38 -0
- data/lib/util/xml.rb +6 -0
- data/lib/view/view.rb +55 -0
- data/script/console +70 -0
- data/strokedb.rb +75 -0
- metadata +148 -0
data/lib/util/inflect.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
# from the English gem (http://english.rubyforge.org/)
|
2
|
+
# http://english.rubyforge.org/rdoc/classes/English/Inflect.html
|
3
|
+
#
|
4
|
+
# last updated from http://english.rubyforge.org/svn/trunk/lib/english/inflect.rb on 3-31-2008
|
5
|
+
|
6
|
+
module English
|
7
|
+
|
8
|
+
# = English Nouns Number Inflection.
|
9
|
+
#
|
10
|
+
# This module provides english singular <-> plural noun inflections.
|
11
|
+
module Inflect
|
12
|
+
|
13
|
+
@singular_of = {}
|
14
|
+
@plural_of = {}
|
15
|
+
|
16
|
+
@singular_rules = []
|
17
|
+
@plural_rules = []
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# Define a general exception.
|
21
|
+
def word(singular, plural=nil)
|
22
|
+
plural = singular unless plural
|
23
|
+
singular_word(singular, plural)
|
24
|
+
plural_word(singular, plural)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Define a singularization exception.
|
28
|
+
def singular_word(singular, plural)
|
29
|
+
@singular_of[plural] = singular
|
30
|
+
end
|
31
|
+
|
32
|
+
# Define a pluralization exception.
|
33
|
+
def plural_word(singular, plural)
|
34
|
+
@plural_of[singular] = plural
|
35
|
+
end
|
36
|
+
|
37
|
+
# Define a general rule.
|
38
|
+
def rule(singular, plural)
|
39
|
+
singular_rule(singular, plural)
|
40
|
+
plural_rule(singular, plural)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Define a singularization rule.
|
44
|
+
def singular_rule(singular, plural)
|
45
|
+
@singular_rules << [singular, plural]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Define a plurualization rule.
|
49
|
+
def plural_rule(singular, plural)
|
50
|
+
@plural_rules << [singular, plural]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Read prepared singularization rules.
|
54
|
+
def singularization_rules
|
55
|
+
return @singularization_rules if @singularization_rules
|
56
|
+
sorted = @singular_rules.sort_by{ |s, p| "#{p}".size }.reverse
|
57
|
+
@singularization_rules = sorted.collect do |s, p|
|
58
|
+
[ /#{p}$/, "#{s}" ]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Read prepared pluralization rules.
|
63
|
+
def pluralization_rules
|
64
|
+
return @pluralization_rules if @pluralization_rules
|
65
|
+
sorted = @plural_rules.sort_by{ |s, p| "#{s}".size }.reverse
|
66
|
+
@pluralization_rules = sorted.collect do |s, p|
|
67
|
+
[ /#{s}$/, "#{p}" ]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
def plural_of
|
73
|
+
@plural_of
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
def singular_of
|
78
|
+
@singular_of
|
79
|
+
end
|
80
|
+
|
81
|
+
# Convert an English word from plurel to singular.
|
82
|
+
#
|
83
|
+
# "boys".singular #=> boy
|
84
|
+
# "tomatoes".singular #=> tomato
|
85
|
+
#
|
86
|
+
def singular(word)
|
87
|
+
if result = singular_of[word]
|
88
|
+
return result.dup
|
89
|
+
end
|
90
|
+
result = word.dup
|
91
|
+
singularization_rules.each do |(match, replacement)|
|
92
|
+
break if result.gsub!(match, replacement)
|
93
|
+
end
|
94
|
+
return result
|
95
|
+
end
|
96
|
+
|
97
|
+
# Alias for #singular (a Railism).
|
98
|
+
#
|
99
|
+
alias_method(:singularize, :singular)
|
100
|
+
|
101
|
+
# Convert an English word from singular to plurel.
|
102
|
+
#
|
103
|
+
# "boy".plural #=> boys
|
104
|
+
# "tomato".plural #=> tomatoes
|
105
|
+
#
|
106
|
+
def plural(word)
|
107
|
+
if result = plural_of[word]
|
108
|
+
return result.dup
|
109
|
+
end
|
110
|
+
#return self.dup if /s$/ =~ self # ???
|
111
|
+
result = word.dup
|
112
|
+
pluralization_rules.each do |(match, replacement)|
|
113
|
+
break if result.gsub!(match, replacement)
|
114
|
+
end
|
115
|
+
return result
|
116
|
+
end
|
117
|
+
|
118
|
+
# Alias for #plural (a Railism).
|
119
|
+
alias_method(:pluralize, :plural)
|
120
|
+
end
|
121
|
+
|
122
|
+
# One argument means singular and plural are the same.
|
123
|
+
|
124
|
+
word 'equipment'
|
125
|
+
word 'information'
|
126
|
+
word 'money'
|
127
|
+
word 'species'
|
128
|
+
word 'series'
|
129
|
+
word 'fish'
|
130
|
+
word 'sheep'
|
131
|
+
word 'moose'
|
132
|
+
word 'hovercraft'
|
133
|
+
|
134
|
+
# Two arguments defines a singular and plural exception.
|
135
|
+
|
136
|
+
word 'Swiss' , 'Swiss'
|
137
|
+
word 'life' , 'lives'
|
138
|
+
word 'wife' , 'wives'
|
139
|
+
word 'virus' , 'viri'
|
140
|
+
word 'octopus' , 'octopi'
|
141
|
+
word 'goose' , 'geese'
|
142
|
+
word 'criterion' , 'criteria'
|
143
|
+
word 'alias' , 'aliases'
|
144
|
+
word 'status' , 'statuses'
|
145
|
+
word 'axis' , 'axes'
|
146
|
+
word 'crisis' , 'crises'
|
147
|
+
word 'testis' , 'testes'
|
148
|
+
word 'child' , 'children'
|
149
|
+
word 'person' , 'people'
|
150
|
+
word 'potato' , 'potatoes'
|
151
|
+
word 'tomato' , 'tomatoes'
|
152
|
+
word 'buffalo' , 'buffaloes'
|
153
|
+
word 'torpedo' , 'torpedoes'
|
154
|
+
word 'quiz' , 'quizes'
|
155
|
+
word 'matrix' , 'matrices'
|
156
|
+
word 'vertex' , 'vetices'
|
157
|
+
word 'index' , 'indices'
|
158
|
+
word 'ox' , 'oxen'
|
159
|
+
word 'mouse' , 'mice'
|
160
|
+
word 'louse' , 'lice'
|
161
|
+
word 'thesis' , 'theses'
|
162
|
+
word 'thief' , 'thieves'
|
163
|
+
word 'analysis' , 'analyses'
|
164
|
+
|
165
|
+
# One-way singularization exception (convert plural to singular).
|
166
|
+
|
167
|
+
singular_word 'cactus', 'cacti'
|
168
|
+
|
169
|
+
# General rules.
|
170
|
+
|
171
|
+
rule 'hive' , 'hives'
|
172
|
+
rule 'rf' , 'rves'
|
173
|
+
rule 'af' , 'aves'
|
174
|
+
rule 'ero' , 'eroes'
|
175
|
+
rule 'man' , 'men'
|
176
|
+
rule 'ch' , 'ches'
|
177
|
+
rule 'sh' , 'shes'
|
178
|
+
rule 'ss' , 'sses'
|
179
|
+
rule 'ta' , 'tum'
|
180
|
+
rule 'ia' , 'ium'
|
181
|
+
rule 'ra' , 'rum'
|
182
|
+
rule 'ay' , 'ays'
|
183
|
+
rule 'ey' , 'eys'
|
184
|
+
rule 'oy' , 'oys'
|
185
|
+
rule 'uy' , 'uys'
|
186
|
+
rule 'y' , 'ies'
|
187
|
+
rule 'x' , 'xes'
|
188
|
+
rule 'lf' , 'lves'
|
189
|
+
rule 'us' , 'uses'
|
190
|
+
rule '' , 's'
|
191
|
+
|
192
|
+
# One-way singular rules.
|
193
|
+
|
194
|
+
singular_rule 'of' , 'ofs' # proof
|
195
|
+
singular_rule 'o' , 'oes' # hero, heroes
|
196
|
+
singular_rule 'f' , 'ves'
|
197
|
+
|
198
|
+
# One-way plural rules.
|
199
|
+
|
200
|
+
plural_rule 'fe' , 'ves' # safe, wife
|
201
|
+
plural_rule 's' , 'ses'
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
class String
|
208
|
+
def singular
|
209
|
+
English::Inflect.singular(self)
|
210
|
+
end
|
211
|
+
alias_method(:singularize, :singular)
|
212
|
+
|
213
|
+
def plural
|
214
|
+
English::Inflect.plural(self)
|
215
|
+
end
|
216
|
+
alias_method(:pluralize, :plural)
|
217
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
# Lazy loads items from array.
|
3
|
+
#
|
4
|
+
# Lazy arrays are backed by Proc returning regular array
|
5
|
+
# on first call retrieving it from @load_with_proc.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# ary = LazyArray.new.load_with { Time.now.to_s.split(/\s/) }
|
10
|
+
#
|
11
|
+
# On first attempt to access <tt>ary</tt> (including <tt>inspect</tt>) it will
|
12
|
+
# evaluate load_with's Proc and update own content with its result:
|
13
|
+
#
|
14
|
+
# ary
|
15
|
+
# # ==> ["Mon", "Mar", "17", "10:35:52", "+0200", "2008"]
|
16
|
+
#
|
17
|
+
class LazyArray < BlankSlate
|
18
|
+
def initialize(*args)
|
19
|
+
@load_with_proc = proc {|v| v}
|
20
|
+
@array = Array.new(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Proc to execute lazy loading
|
24
|
+
def load_with(&block)
|
25
|
+
@load_with_proc = block
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Make it look like array for outer world
|
30
|
+
def class
|
31
|
+
Array
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing sym, *args, &blk
|
35
|
+
if @array.respond_to? sym
|
36
|
+
load!
|
37
|
+
@array.__send__ sym, *args, &blk
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def load!
|
46
|
+
if @load_with_proc
|
47
|
+
@array.clear
|
48
|
+
@array.concat @load_with_proc.call(@array)
|
49
|
+
@load_with_proc = nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
# Lazy loads items from array applying procs on each read and write.
|
3
|
+
#
|
4
|
+
# Example:
|
5
|
+
#
|
6
|
+
# @ary[i] = 10
|
7
|
+
#
|
8
|
+
# applies "unmap proc" to new item value.
|
9
|
+
#
|
10
|
+
# @ary.at(i)
|
11
|
+
#
|
12
|
+
# applies "map proc" to value just have been read.
|
13
|
+
#
|
14
|
+
# StrokeDB uses this class to "follow" links to other documents
|
15
|
+
# found in slots in a lazy manner.
|
16
|
+
#
|
17
|
+
# player:
|
18
|
+
# model: [@#8b195509-f9c4-4fea-90c9-425b38bdda3e.ea5eda78-d410-44be-8b14-f4e33f6fa047]
|
19
|
+
# generation: 4
|
20
|
+
#
|
21
|
+
# when model collection item is fetched, reference followed and turned into document
|
22
|
+
# instance with mapping proc of lazy mapping array.
|
23
|
+
class LazyMappingArray < BlankSlate(Array)
|
24
|
+
def initialize(*args)
|
25
|
+
@map_proc = proc {|v| v}
|
26
|
+
@unmap_proc = proc {|v| v}
|
27
|
+
super(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def map_with(&block)
|
31
|
+
@map_proc = block
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def unmap_with(&block)
|
36
|
+
@unmap_proc = block
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def class
|
41
|
+
Array
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing sym, *args, &blk
|
45
|
+
super if sym.to_s =~ /^__/
|
46
|
+
mname = "__#{::BlankSlate::MethodMapping[sym.to_s] || sym}"
|
47
|
+
|
48
|
+
case sym
|
49
|
+
when :push, :unshift, :<<, :[]=, :index, :-
|
50
|
+
last = args.pop
|
51
|
+
last = last.is_a?(Array) ? last.map{|v| @unmap_proc.call(v) } : @unmap_proc.call(last)
|
52
|
+
args.push last
|
53
|
+
|
54
|
+
__send__(mname, *args, &blk)
|
55
|
+
|
56
|
+
when :[], :slice, :at, :map, :shift, :pop, :include?, :last, :first, :zip, :each, :inject, :each_with_index
|
57
|
+
__map{|v| @map_proc.call(v) }.__send__(sym, *args, &blk)
|
58
|
+
|
59
|
+
else
|
60
|
+
__send__(mname, *args, &blk)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
class LazyMappingHash < BlankSlate(Hash)
|
3
|
+
def initialize(original = {}, decoder = nil, encoder = nil)
|
4
|
+
@decoder = decoder || proc {|v| v}
|
5
|
+
@encoder = encoder || proc {|v| v}
|
6
|
+
super(default)
|
7
|
+
original.each {|k,v| self.__squarebracket_set(k,v) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def map_with(&block)
|
11
|
+
@encoder = block
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def unmap_with(&block)
|
16
|
+
@decoder = block
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def class
|
21
|
+
Hash
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing sym, *args, &blk
|
25
|
+
super if sym.to_s =~ /^__/
|
26
|
+
mname = "__#{::BlankSlate::MethodMapping[sym.to_s] || sym}"
|
27
|
+
|
28
|
+
case sym
|
29
|
+
when :keys, :values
|
30
|
+
__send__(mname, *args, &blk).map{|v| @encoder.call(v) }
|
31
|
+
|
32
|
+
when :each
|
33
|
+
self.__each do |k,v|
|
34
|
+
yield @encoder.call(k), @encoder.call(v)
|
35
|
+
end
|
36
|
+
|
37
|
+
when :[], :[]=
|
38
|
+
args.map!{|v| @decoder.call(v) }
|
39
|
+
@encoder.call __send__(mname, *args, &blk)
|
40
|
+
|
41
|
+
else
|
42
|
+
__send__(mname, *args, &blk)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
module JsonSerializationMethod
|
3
|
+
def serialize(x)
|
4
|
+
x.to_json
|
5
|
+
end
|
6
|
+
def deserialize(x)
|
7
|
+
JSON.parse(x)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module MarshalSerializationMethod
|
12
|
+
def serialize(x)
|
13
|
+
x = x.to_raw if x.respond_to?(:to_raw)
|
14
|
+
Marshal.dump(x)
|
15
|
+
end
|
16
|
+
def deserialize(x)
|
17
|
+
Marshal.load(x)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def self.serialization_method=(method_name)
|
23
|
+
StrokeDB.extend StrokeDB.const_get("#{method_name.to_s.camelize}SerializationMethod")
|
24
|
+
end
|
25
|
+
|
26
|
+
self.serialization_method = :marshal
|
27
|
+
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Enumerable
|
2
|
+
class TriggerPartitionContext
|
3
|
+
def initialize(enum, &block)
|
4
|
+
@enum = enum
|
5
|
+
@cont = block
|
6
|
+
end
|
7
|
+
def fill(&block)
|
8
|
+
@fill = block
|
9
|
+
self
|
10
|
+
end
|
11
|
+
def emit
|
12
|
+
partitions = []
|
13
|
+
cont = @cont
|
14
|
+
fill = @fill
|
15
|
+
p = @enum.inject(nil) do |part, elem|
|
16
|
+
if part && cont.call(part, elem)
|
17
|
+
fill.call(part, elem)
|
18
|
+
part
|
19
|
+
else
|
20
|
+
partitions << part if part
|
21
|
+
yield(elem)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
partitions << p if p
|
25
|
+
partitions
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def trigger_partition(&block)
|
29
|
+
TriggerPartitionContext.new(self, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
class TriggerPartitions
|
33
|
+
def self.partition(list)
|
34
|
+
partitions = []
|
35
|
+
p = list.inject(nil) do |part, elem|
|
36
|
+
if part && continue?(part, elem)
|
37
|
+
fill(part, elem)
|
38
|
+
part
|
39
|
+
else
|
40
|
+
partitions << part if part
|
41
|
+
emit(elem)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
partitions << p if p
|
45
|
+
partitions
|
46
|
+
end
|
47
|
+
def self.continue?(p, e)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
def self.emit(e)
|
51
|
+
[e]
|
52
|
+
end
|
53
|
+
def self.fill(p, e)
|
54
|
+
p << e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if __FILE__ == $0
|
60
|
+
arr = [1,2,3,4,5, -1, -4, -3, 5, 6, 7, 8, -6, -7]
|
61
|
+
parr = arr.trigger_partition do |partition, element|
|
62
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
63
|
+
end.fill do |p, e|
|
64
|
+
p << e
|
65
|
+
end.emit do |e|
|
66
|
+
[e]
|
67
|
+
end
|
68
|
+
|
69
|
+
p arr
|
70
|
+
p parr
|
71
|
+
|
72
|
+
# Class might be faster
|
73
|
+
class SignPartitions < Enumerable::TriggerPartitions
|
74
|
+
def self.continue?(partition, element)
|
75
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
p Enumerable::TriggerPartitions.partition(arr)
|
80
|
+
p SignPartitions.partition(arr)
|
81
|
+
|
82
|
+
require 'benchmark'
|
83
|
+
include Benchmark
|
84
|
+
n = 1000
|
85
|
+
bm(32) do |x|
|
86
|
+
x.report("#{n} times:" ) do
|
87
|
+
n.times do
|
88
|
+
arr.trigger_partition do |partition, element|
|
89
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
90
|
+
end.fill do |p, e|
|
91
|
+
p << e
|
92
|
+
end.emit do |e|
|
93
|
+
[e]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
arrL = arr*28
|
98
|
+
x.report("#{n} times (x28 larger data):" ) do
|
99
|
+
n.times do
|
100
|
+
arrL.trigger_partition do |partition, element|
|
101
|
+
partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0
|
102
|
+
end.fill do |p, e|
|
103
|
+
p << e
|
104
|
+
end.emit do |e|
|
105
|
+
[e]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
# 35% faster
|
110
|
+
x.report("#{n} times (SignPartitions):" ) do
|
111
|
+
(n/5).times do
|
112
|
+
SignPartitions.partition(arrL)
|
113
|
+
SignPartitions.partition(arrL)
|
114
|
+
SignPartitions.partition(arrL)
|
115
|
+
SignPartitions.partition(arrL)
|
116
|
+
SignPartitions.partition(arrL)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
# + 17% faster (relative to SignPartitions)
|
120
|
+
x.report("#{n} times (raw code):" ) do
|
121
|
+
n.times do
|
122
|
+
parts = []
|
123
|
+
p = arrL.inject(nil) do |partition, element|
|
124
|
+
if partition && (partition[0] > 0 && element > 0 || partition[0] < 0 && element < 0)
|
125
|
+
partition << element
|
126
|
+
partition
|
127
|
+
else
|
128
|
+
parts << partition if partition
|
129
|
+
[element]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
parts << p if p
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/util/util.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
module Util
|
3
|
+
|
4
|
+
class ::Object
|
5
|
+
# Uses references to documents (compared to to_raw using hashes instead)
|
6
|
+
def to_optimized_raw
|
7
|
+
case self
|
8
|
+
when Array
|
9
|
+
map{|v| v.to_optimized_raw }
|
10
|
+
when Hash
|
11
|
+
new_hash = {}
|
12
|
+
each_pair{|k,v| new_hash[k.to_optimized_raw] = v.to_optimized_raw}
|
13
|
+
new_hash
|
14
|
+
else
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
unless RUBY_PLATFORM =~ /java/
|
21
|
+
require 'uuidtools'
|
22
|
+
def self.random_uuid
|
23
|
+
::UUID.random_create.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class CircularReferenceCondition < Exception ; end
|
28
|
+
class << self
|
29
|
+
def catch_circular_reference(value,name = 'StrokeDB.reference_stack')
|
30
|
+
stack = Thread.current[name] ||= []
|
31
|
+
raise CircularReferenceCondition if stack.find{|v| value == v}
|
32
|
+
stack << value
|
33
|
+
yield
|
34
|
+
stack.pop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/util/xml.rb
ADDED
data/lib/view/view.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module StrokeDB
|
2
|
+
View = Meta.new(:uuid => VIEW_UUID) do
|
3
|
+
attr_accessor :map_with_proc
|
4
|
+
attr_reader :reduce_with_proc
|
5
|
+
|
6
|
+
on_initialization do |view|
|
7
|
+
view.map_with_proc = proc {|doc, *args| doc }
|
8
|
+
end
|
9
|
+
|
10
|
+
def reduce_with(&block)
|
11
|
+
@reduce_with_proc = block
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def map_with(&block)
|
16
|
+
@map_with_proc = block
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def emit(*args)
|
21
|
+
ViewCut.new(store, :view => self, :args => args, :timestamp_state => LTS.zero.counter).emit
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
ViewCut = Meta.new(:uuid => VIEWCUT_UUID) do
|
26
|
+
|
27
|
+
on_new_document do |cut|
|
28
|
+
cut.instance_eval do
|
29
|
+
if view.is_a?(View)
|
30
|
+
@map_with_proc = view.map_with_proc
|
31
|
+
@reduce_with_proc = view.reduce_with_proc
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
before_save do |cut|
|
37
|
+
view = cut.view
|
38
|
+
view.last_cut = cut if view[:last_cut].nil? or (cut[:previous] && view.last_cut == cut.previous)
|
39
|
+
view.save!
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def emit
|
44
|
+
mapped = []
|
45
|
+
store.each(:after_timestamp => timestamp_state, :include_versions => view[:include_versions]) do |doc|
|
46
|
+
mapped << @map_with_proc.call(doc,*args)
|
47
|
+
end
|
48
|
+
documents = (@reduce_with_proc ? mapped.select {|doc| @reduce_with_proc.call(doc,*args) } : mapped).map{|d| d.is_a?(Document) ? d.extend(VersionedDocument) : d}
|
49
|
+
ViewCut.new(store, :documents => documents, :view => view, :args => args, :timestamp_state => store.timestamp.counter, :previous => timestamp_state == 0 ? nil : self)
|
50
|
+
end
|
51
|
+
def to_a
|
52
|
+
documents
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|