hamster 1.0.1.pre.rc.1 → 1.0.1.pre.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hamster/groupable.rb +12 -0
  3. data/lib/hamster/hash.rb +32 -12
  4. data/lib/hamster/list.rb +68 -22
  5. data/lib/hamster/queue.rb +5 -6
  6. data/lib/hamster/set.rb +50 -14
  7. data/lib/hamster/stack.rb +2 -0
  8. data/lib/hamster/trie.rb +34 -14
  9. data/lib/hamster/tuple.rb +9 -24
  10. data/lib/hamster/vector.rb +29 -7
  11. data/lib/hamster/version.rb +1 -1
  12. data/spec/hamster/core_ext/array_spec.rb +4 -10
  13. data/spec/hamster/core_ext/enumerable_spec.rb +1 -0
  14. data/spec/hamster/experimental/mutable_set/add_qm_spec.rb +14 -22
  15. data/spec/hamster/experimental/mutable_set/add_spec.rb +20 -34
  16. data/spec/hamster/experimental/mutable_set/delete_qm_spec.rb +15 -24
  17. data/spec/hamster/experimental/mutable_set/delete_spec.rb +15 -25
  18. data/spec/hamster/experimental/mutable_stack/pop_spec.rb +21 -27
  19. data/spec/hamster/experimental/mutable_stack/push_spec.rb +11 -31
  20. data/spec/hamster/hash/all_spec.rb +21 -34
  21. data/spec/hamster/hash/any_spec.rb +0 -15
  22. data/spec/hamster/hash/clear_spec.rb +1 -8
  23. data/spec/hamster/hash/construction_spec.rb +3 -11
  24. data/spec/hamster/hash/copying_spec.rb +1 -8
  25. data/spec/hamster/hash/delete_spec.rb +1 -10
  26. data/spec/hamster/hash/each_spec.rb +1 -12
  27. data/spec/hamster/hash/empty_spec.rb +8 -8
  28. data/spec/hamster/hash/eql_spec.rb +30 -22
  29. data/spec/hamster/hash/except_spec.rb +1 -10
  30. data/spec/hamster/hash/fetch_spec.rb +1 -24
  31. data/spec/hamster/hash/filter_spec.rb +1 -16
  32. data/spec/hamster/hash/find_spec.rb +1 -14
  33. data/spec/hamster/hash/has_key_spec.rb +1 -10
  34. data/spec/hamster/hash/hash_spec.rb +1 -16
  35. data/spec/hamster/hash/immutable_spec.rb +0 -3
  36. data/spec/hamster/hash/inspect_spec.rb +1 -9
  37. data/spec/hamster/hash/keys_spec.rb +4 -5
  38. data/spec/hamster/hash/map_spec.rb +1 -16
  39. data/spec/hamster/hash/merge_spec.rb +5 -11
  40. data/spec/hamster/hash/new_spec.rb +21 -0
  41. data/spec/hamster/hash/put_spec.rb +13 -11
  42. data/spec/hamster/hash/reduce_spec.rb +7 -15
  43. data/spec/hamster/hash/remove_spec.rb +1 -16
  44. data/spec/hamster/hash/uniq_spec.rb +1 -8
  45. data/spec/hamster/hash/values_spec.rb +1 -6
  46. data/spec/hamster/immutable/copying_spec.rb +1 -8
  47. data/spec/hamster/immutable/immutable_spec.rb +1 -14
  48. data/spec/hamster/immutable/memoize_spec.rb +0 -1
  49. data/spec/hamster/list/add_spec.rb +1 -6
  50. data/spec/hamster/list/all_spec.rb +1 -28
  51. data/spec/hamster/list/any_spec.rb +1 -20
  52. data/spec/hamster/list/append_spec.rb +1 -11
  53. data/spec/hamster/list/at_spec.rb +1 -13
  54. data/spec/hamster/list/break_spec.rb +1 -13
  55. data/spec/hamster/list/cadr_spec.rb +1 -9
  56. data/spec/hamster/list/chunk_spec.rb +1 -9
  57. data/spec/hamster/list/clear_spec.rb +1 -9
  58. data/spec/hamster/list/combinations_spec.rb +1 -11
  59. data/spec/hamster/list/compact_spec.rb +1 -9
  60. data/spec/hamster/list/cons_spec.rb +1 -10
  61. data/spec/hamster/list/construction_spec.rb +1 -30
  62. data/spec/hamster/list/copying_spec.rb +1 -9
  63. data/spec/hamster/list/count_spec.rb +1 -15
  64. data/spec/hamster/list/cycle_spec.rb +1 -10
  65. data/spec/hamster/list/drop_spec.rb +1 -9
  66. data/spec/hamster/list/drop_while_spec.rb +1 -13
  67. data/spec/hamster/list/each_slice_spec.rb +1 -17
  68. data/spec/hamster/list/each_spec.rb +1 -17
  69. data/spec/hamster/list/each_with_index_spec.rb +1 -10
  70. data/spec/hamster/list/elem_index_spec.rb +1 -13
  71. data/spec/hamster/list/elem_indices_spec.rb +1 -11
  72. data/spec/hamster/list/empty_spec.rb +1 -13
  73. data/spec/hamster/list/eql_spec.rb +52 -62
  74. data/spec/hamster/list/find_index_spec.rb +1 -13
  75. data/spec/hamster/list/find_indices_spec.rb +1 -11
  76. data/spec/hamster/list/find_spec.rb +1 -17
  77. data/spec/hamster/list/flatten_spec.rb +1 -9
  78. data/spec/hamster/list/grep_spec.rb +1 -16
  79. data/spec/hamster/list/group_by_spec.rb +1 -20
  80. data/spec/hamster/list/head_spec.rb +1 -11
  81. data/spec/hamster/list/include_spec.rb +1 -13
  82. data/spec/hamster/list/init_spec.rb +1 -8
  83. data/spec/hamster/list/inits_spec.rb +1 -9
  84. data/spec/hamster/list/inspect_spec.rb +1 -11
  85. data/spec/hamster/list/intersperse_spec.rb +1 -9
  86. data/spec/hamster/list/join_spec.rb +1 -18
  87. data/spec/hamster/list/last_spec.rb +1 -11
  88. data/spec/hamster/list/map_spec.rb +1 -15
  89. data/spec/hamster/list/maximum_spec.rb +1 -20
  90. data/spec/hamster/list/merge_by_spec.rb +1 -19
  91. data/spec/hamster/list/merge_spec.rb +1 -20
  92. data/spec/hamster/list/minimum_spec.rb +1 -20
  93. data/spec/hamster/list/none_spec.rb +1 -18
  94. data/spec/hamster/list/one_spec.rb +1 -16
  95. data/spec/hamster/list/partition_spec.rb +1 -13
  96. data/spec/hamster/list/product_spec.rb +1 -11
  97. data/spec/hamster/list/reduce_spec.rb +0 -1
  98. data/spec/hamster/list/remove_spec.rb +1 -15
  99. data/spec/hamster/list/reverse_spec.rb +1 -11
  100. data/spec/hamster/list/size_spec.rb +1 -13
  101. data/spec/hamster/list/slice_spec.rb +1 -11
  102. data/spec/hamster/list/sorting_spec.rb +1 -14
  103. data/spec/hamster/list/span_spec.rb +1 -12
  104. data/spec/hamster/list/split_at_spec.rb +1 -9
  105. data/spec/hamster/list/sum_spec.rb +1 -11
  106. data/spec/hamster/list/tail_spec.rb +1 -11
  107. data/spec/hamster/list/tails_spec.rb +1 -9
  108. data/spec/hamster/list/take_spec.rb +1 -9
  109. data/spec/hamster/list/take_while_spec.rb +0 -1
  110. data/spec/hamster/list/to_a_spec.rb +1 -13
  111. data/spec/hamster/list/to_ary_spec.rb +0 -1
  112. data/spec/hamster/list/to_list_spec.rb +1 -9
  113. data/spec/hamster/list/to_set_spec.rb +2 -8
  114. data/spec/hamster/list/union_spec.rb +1 -11
  115. data/spec/hamster/list/uniq_spec.rb +1 -11
  116. data/spec/hamster/queue/clear_spec.rb +1 -9
  117. data/spec/hamster/queue/construction_spec.rb +1 -10
  118. data/spec/hamster/queue/dequeue_spec.rb +1 -11
  119. data/spec/hamster/queue/empty_spec.rb +1 -13
  120. data/spec/hamster/queue/enqueue_spec.rb +1 -11
  121. data/spec/hamster/queue/head_spec.rb +1 -11
  122. data/spec/hamster/queue/inspect_spec.rb +1 -9
  123. data/spec/hamster/queue/size_spec.rb +1 -11
  124. data/spec/hamster/queue/to_a_spec.rb +1 -11
  125. data/spec/hamster/queue/to_list_spec.rb +1 -11
  126. data/spec/hamster/set/add_spec.rb +1 -12
  127. data/spec/hamster/set/all_spec.rb +1 -18
  128. data/spec/hamster/set/any_spec.rb +1 -17
  129. data/spec/hamster/set/clear_spec.rb +9 -8
  130. data/spec/hamster/set/compact_spec.rb +1 -9
  131. data/spec/hamster/set/construction_spec.rb +1 -9
  132. data/spec/hamster/set/copying_spec.rb +1 -8
  133. data/spec/hamster/set/count_spec.rb +1 -13
  134. data/spec/hamster/set/delete_spec.rb +1 -10
  135. data/spec/hamster/set/difference_spec.rb +1 -11
  136. data/spec/hamster/set/empty_spec.rb +1 -11
  137. data/spec/hamster/set/exclusion_spec.rb +1 -11
  138. data/spec/hamster/set/filter_spec.rb +10 -17
  139. data/spec/hamster/set/find_spec.rb +1 -14
  140. data/spec/hamster/set/flatten_spec.rb +8 -10
  141. data/spec/hamster/set/group_by_spec.rb +8 -17
  142. data/spec/hamster/set/head_spec.rb +1 -12
  143. data/spec/hamster/set/immutable_spec.rb +1 -4
  144. data/spec/hamster/set/include_spec.rb +1 -9
  145. data/spec/hamster/set/inspect_spec.rb +1 -9
  146. data/spec/hamster/set/intersection_spec.rb +1 -11
  147. data/spec/hamster/set/join_spec.rb +1 -16
  148. data/spec/hamster/set/map_spec.rb +1 -16
  149. data/spec/hamster/set/marshal_spec.rb +1 -6
  150. data/spec/hamster/set/maximum_spec.rb +1 -18
  151. data/spec/hamster/set/minimum_spec.rb +1 -17
  152. data/spec/hamster/set/new_spec.rb +21 -0
  153. data/spec/hamster/set/none_spec.rb +1 -16
  154. data/spec/hamster/set/one_spec.rb +1 -14
  155. data/spec/hamster/set/partition_spec.rb +1 -13
  156. data/spec/hamster/set/product_spec.rb +1 -9
  157. data/spec/hamster/set/reduce_spec.rb +1 -26
  158. data/spec/hamster/set/remove_spec.rb +1 -16
  159. data/spec/hamster/set/size_spec.rb +1 -9
  160. data/spec/hamster/set/sorting_spec.rb +1 -3
  161. data/spec/hamster/set/subset_spec.rb +1 -9
  162. data/spec/hamster/set/sum_spec.rb +1 -9
  163. data/spec/hamster/set/superset_spec.rb +1 -9
  164. data/spec/hamster/set/to_a_spec.rb +1 -11
  165. data/spec/hamster/set/to_list_spec.rb +1 -11
  166. data/spec/hamster/set/to_set_spec.rb +1 -9
  167. data/spec/hamster/set/union_spec.rb +1 -11
  168. data/spec/hamster/set/uniq_spec.rb +1 -7
  169. data/spec/hamster/sorter/immutable_spec.rb +1 -4
  170. data/spec/hamster/stack/clear_spec.rb +1 -9
  171. data/spec/hamster/stack/construction_spec.rb +1 -10
  172. data/spec/hamster/stack/copying_spec.rb +1 -9
  173. data/spec/hamster/stack/empty_spec.rb +1 -9
  174. data/spec/hamster/stack/eql_spec.rb +1 -13
  175. data/spec/hamster/stack/immutable_spec.rb +1 -4
  176. data/spec/hamster/stack/inspect_spec.rb +1 -9
  177. data/spec/hamster/stack/peek_spec.rb +1 -11
  178. data/spec/hamster/stack/pop_spec.rb +1 -11
  179. data/spec/hamster/stack/push_spec.rb +1 -11
  180. data/spec/hamster/stack/size_spec.rb +1 -11
  181. data/spec/hamster/stack/to_a_spec.rb +1 -11
  182. data/spec/hamster/stack/to_list_spec.rb +1 -9
  183. data/spec/hamster/tuple/construction_spec.rb +30 -0
  184. data/spec/hamster/tuple/copying_spec.rb +1 -8
  185. data/spec/hamster/tuple/eql_spec.rb +57 -40
  186. data/spec/hamster/tuple/first_spec.rb +1 -6
  187. data/spec/hamster/tuple/immutable_spec.rb +1 -4
  188. data/spec/hamster/tuple/inspect_spec.rb +1 -6
  189. data/spec/hamster/tuple/last_spec.rb +1 -6
  190. data/spec/hamster/tuple/to_a_spec.rb +1 -9
  191. data/spec/hamster/tuple/to_ary_spec.rb +0 -1
  192. data/spec/hamster/undefined/erase_spec.rb +1 -12
  193. data/spec/hamster/vector/add_spec.rb +8 -0
  194. data/spec/hamster/vector/clear_spec.rb +1 -8
  195. data/spec/hamster/vector/copying_spec.rb +1 -8
  196. data/spec/hamster/vector/each_spec.rb +1 -11
  197. data/spec/hamster/vector/each_with_index_spec.rb +1 -9
  198. data/spec/hamster/vector/empty_spec.rb +7 -9
  199. data/spec/hamster/vector/eql_spec.rb +1 -12
  200. data/spec/hamster/vector/filter_spec.rb +8 -12
  201. data/spec/hamster/vector/first_spec.rb +1 -11
  202. data/spec/hamster/vector/get_spec.rb +1 -23
  203. data/spec/hamster/vector/include_spec.rb +1 -10
  204. data/spec/hamster/vector/map_spec.rb +8 -14
  205. data/spec/hamster/vector/new_spec.rb +48 -0
  206. data/spec/hamster/vector/reduce_spec.rb +1 -26
  207. data/spec/hamster/vector/set_spec.rb +8 -0
  208. data/spec/spec_helper.rb +0 -5
  209. metadata +35 -68
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a6d9d9d40fec03b2572ac9d6357672168a92beb
4
- data.tar.gz: 3cb07caf01439c766a95e1e95191df5385e71fc1
3
+ metadata.gz: a12201961b658581cc147e8a0c99fdc7003bf3b0
4
+ data.tar.gz: 3f24be00255e640a0afcefd374f6e3d16e619e5c
5
5
  SHA512:
6
- metadata.gz: 3b7b5121f99a8d3cb4d1c749b29c8207b902ca37f1065538b5890f4acf5c647d40bb21900ab50a48979c9abab6efe2dddc2269874dc9e7db44d5aaa6ab9d22fb
7
- data.tar.gz: 4fb92d1cbe3e221476930d7e20585acf9ebd53cb6892c4157667a6e1d3402c90804bfebe28f41d69577026d7904f266eb34dae94d41e42f2cf962757c5cecebb
6
+ metadata.gz: abd019d8bcc64d60d75d734a8ee0e08e549ab3662b2e1638f25afb331a3fa7981b0f45f571625bc61f2a36b17bbce44c0a862aa4586f95f9949949ddc26dc1c0
7
+ data.tar.gz: 283b36da83e8dda6ab822e430eb2503d7abdf7be6cb142e0c217052acbd2cafcac52c0833e2a156018436cf6cb86b947c7c10a76a5dcfa4b9ab8247a88d6d35d
@@ -0,0 +1,12 @@
1
+ module Hamster
2
+ module Groupable
3
+ def group_by_with(empty_group, &block)
4
+ return group_by { |item| item } unless block_given?
5
+ reduce(EmptyHash) do |hash, item|
6
+ key = yield(item)
7
+ group = hash.get(key) || empty_group
8
+ hash.put(key, group.conj(item))
9
+ end
10
+ end
11
+ end
12
+ end
@@ -6,7 +6,7 @@ require "hamster/trie"
6
6
  require "hamster/list"
7
7
 
8
8
  module Hamster
9
- def self.hash(pairs = {}, &block)
9
+ def self.hash(pairs = nil, &block)
10
10
  Hash.new(pairs, &block)
11
11
  end
12
12
 
@@ -15,16 +15,25 @@ module Hamster
15
15
  include Immutable
16
16
 
17
17
  class << self
18
- def new(pairs = {}, &block)
19
- @empty ||= super()
20
- pairs.reduce(block_given? ? super(&block) : @empty) { |hash, pair| hash.put(pair.first, pair.last) }
18
+ alias :alloc :new
19
+
20
+ def new(pairs = nil, &block)
21
+ if pairs.nil? && block.nil?
22
+ empty
23
+ elsif pairs.empty?
24
+ alloc(EmptyTrie, block)
25
+ else
26
+ alloc(Trie[pairs], block)
27
+ end
21
28
  end
22
29
 
23
- attr_reader :empty
30
+ def empty
31
+ @empty ||= self.alloc
32
+ end
24
33
  end
25
34
 
26
- def initialize(&block)
27
- @trie = EmptyTrie
35
+ def initialize(trie = EmptyTrie, block = nil)
36
+ @trie = trie
28
37
  @default = block
29
38
  end
30
39
 
@@ -143,7 +152,9 @@ module Hamster
143
152
  def_delegator :self, :find, :detect
144
153
 
145
154
  def merge(other)
146
- transform { @trie = other.reduce(@trie, &:put) }
155
+ transform do
156
+ other.each { |key, value| @trie = @trie.put(key, value) }
157
+ end
147
158
  end
148
159
  def_delegator :self, :merge, :+
149
160
 
@@ -156,7 +167,7 @@ module Hamster
156
167
  end
157
168
 
158
169
  def keys
159
- reduce(Hamster.set) { |keys, key, value| keys.add(key) }
170
+ Hamster::Set.alloc(@trie)
160
171
  end
161
172
 
162
173
  def values
@@ -167,10 +178,15 @@ module Hamster
167
178
  self.class.empty
168
179
  end
169
180
 
181
+ # Value-and-type equality
170
182
  def eql?(other)
171
183
  instance_of?(other.class) && @trie.eql?(other.instance_variable_get(:@trie))
172
184
  end
173
- def_delegator :self, :eql?, :==
185
+
186
+ # Value equality, will do type coercion
187
+ def ==(other)
188
+ self.eql?(other) || (other.respond_to?(:to_hash) && to_hash.eql?(other.to_hash))
189
+ end
174
190
 
175
191
  def hash
176
192
  keys.sort.reduce(0) do |hash, key|
@@ -186,7 +202,7 @@ module Hamster
186
202
  "{#{reduce([]) { |memo, key, value| memo << "#{key.inspect} => #{value.inspect}" }.join(", ")}}"
187
203
  end
188
204
 
189
- def marshal_dump
205
+ def to_hash
190
206
  output = {}
191
207
  each do |key, value|
192
208
  output[key] = value
@@ -194,6 +210,10 @@ module Hamster
194
210
  output
195
211
  end
196
212
 
213
+ def marshal_dump
214
+ to_hash
215
+ end
216
+
197
217
  def marshal_load(dictionary)
198
218
  @trie = dictionary.reduce EmptyTrie do |trie, key_value|
199
219
  trie.put(key_value.first, key_value.last)
@@ -201,5 +221,5 @@ module Hamster
201
221
  end
202
222
  end
203
223
 
204
- EmptyHash = Hamster::Hash.new
224
+ EmptyHash = Hamster::Hash.empty
205
225
  end
@@ -4,6 +4,7 @@ require "thread"
4
4
  require "hamster/core_ext/enumerable"
5
5
  require "hamster/undefined"
6
6
  require "hamster/enumerable"
7
+ require "hamster/groupable"
7
8
  require "hamster/tuple"
8
9
  require "hamster/sorter"
9
10
  require "hamster/hash"
@@ -144,6 +145,7 @@ module Hamster
144
145
  module List
145
146
  extend Forwardable
146
147
  include Enumerable
148
+ include Groupable
147
149
 
148
150
  CADR = /^c([ad]+)r$/
149
151
 
@@ -151,7 +153,16 @@ module Hamster
151
153
  def_delegator :self, :empty?, :null?
152
154
 
153
155
  def size
154
- reduce(0) { |memo, item| memo.next }
156
+ result, list = 0, self
157
+ until list.empty?
158
+ if list.cached_size?
159
+ return result + list.size
160
+ else
161
+ result += 1
162
+ end
163
+ list = list.tail
164
+ end
165
+ result
155
166
  end
156
167
  def_delegator :self, :size, :length
157
168
 
@@ -159,6 +170,8 @@ module Hamster
159
170
  Sequence.new(item, self)
160
171
  end
161
172
  def_delegator :self, :cons, :>>
173
+ def_delegator :self, :cons, :conj
174
+ def_delegator :self, :cons, :conjoin
162
175
 
163
176
  def add(item)
164
177
  append(Hamster.list(item))
@@ -387,11 +400,7 @@ module Hamster
387
400
  end
388
401
 
389
402
  def group_by(&block)
390
- return group_by { |item| item } unless block_given?
391
- reduce(EmptyHash) do |hash, item|
392
- key = yield(item)
393
- hash.put(key, (hash.get(key) || EmptyList).cons(item))
394
- end
403
+ group_by_with(EmptyList, &block)
395
404
  end
396
405
  def_delegator :self, :group_by, :group
397
406
 
@@ -466,6 +475,7 @@ module Hamster
466
475
  end
467
476
  end
468
477
 
478
+ # Value-and-type equality
469
479
  def eql?(other)
470
480
  list = self
471
481
  loop do
@@ -478,7 +488,12 @@ module Hamster
478
488
  other = other.tail
479
489
  end
480
490
  end
481
- def_delegator :self, :eql?, :==
491
+
492
+ # Value equality, will do type coercion on arrays and array-like objects
493
+ def ==(other)
494
+ self.eql?(other) ||
495
+ other.respond_to?(:to_ary) && to_ary.eql?(other.to_ary)
496
+ end
482
497
 
483
498
  def hash
484
499
  reduce(0) { |hash, item| (hash << 5) - hash + item.hash }
@@ -505,23 +520,28 @@ module Hamster
505
520
  super || !!name.to_s.match(CADR)
506
521
  end
507
522
 
523
+ def cached_size?
524
+ false
525
+ end
526
+
508
527
  private
509
528
 
510
529
  def method_missing(name, *args, &block)
511
- return accessor(Regexp.last_match[1]) if name.to_s.match(CADR)
512
- super
513
- end
514
-
515
- # Perform compositions of <tt>car</tt> and <tt>cdr</tt> operations. Their names consist of a 'c', followed by at
516
- # least one 'a' or 'd', and finally an 'r'. The series of 'a's and 'd's in each function's name is chosen to
517
- # identify the series of car and cdr operations that is performed by the function. The order in which the 'a's and
518
- # 'd's appear is the inverse of the order in which the corresponding operations are performed.
519
- def accessor(sequence)
520
- sequence.reverse.each_char.reduce(self) do |memo, char|
521
- case char
522
- when "a" then memo.head
523
- when "d" then memo.tail
524
- end
530
+ if name.to_s.match(CADR)
531
+ # Perform compositions of car and cdr operations. Their names consist of a 'c',
532
+ # followed by at least one 'a' or 'd', and finally an 'r'. The series of 'a's and
533
+ # 'd's in the method name identify the series of car and cdr operations performed.
534
+ # The order in which the 'a's and 'd's appear is the inverse of the order in which
535
+ # the corresponding operations are performed.
536
+ code = "def #{name}; self."
537
+ code << Regexp.last_match[1].reverse.chars.map do |char|
538
+ {'a' => 'head', 'd' => 'tail'}[char]
539
+ end.join('.')
540
+ code << '; end'
541
+ List.class_eval(code)
542
+ send(name, *args, &block)
543
+ else
544
+ super
525
545
  end
526
546
  end
527
547
  end
@@ -544,11 +564,20 @@ module Hamster
544
564
  def initialize(head, tail = EmptyList)
545
565
  @head = head
546
566
  @tail = tail
567
+ @size = tail.cached_size? ? tail.size + 1 : nil
547
568
  end
548
569
 
549
570
  def empty?
550
571
  false
551
572
  end
573
+
574
+ def size
575
+ @size || super
576
+ end
577
+
578
+ def cached_size?
579
+ @size != nil
580
+ end
552
581
  end
553
582
 
554
583
  # Lazy list stream
@@ -569,13 +598,22 @@ module Hamster
569
598
 
570
599
  def initialize(&block)
571
600
  @block = block
572
- @lock = Mutex.new
601
+ @lock = Mutex.new
602
+ @size = nil
573
603
  end
574
604
 
575
605
  def_delegator :target, :head
576
606
  def_delegator :target, :tail
577
607
  def_delegator :target, :empty?
578
608
 
609
+ def size
610
+ @size ||= super
611
+ end
612
+
613
+ def cached_size?
614
+ @size != nil
615
+ end
616
+
579
617
  protected
580
618
 
581
619
  def vivify
@@ -616,6 +654,14 @@ module Hamster
616
654
  def empty?
617
655
  true
618
656
  end
657
+
658
+ def size
659
+ 0
660
+ end
661
+
662
+ def cached_size?
663
+ true
664
+ end
619
665
  end
620
666
  end
621
667
  end
@@ -38,6 +38,8 @@ module Hamster
38
38
  end
39
39
  def_delegator :self, :enqueue, :<<
40
40
  def_delegator :self, :enqueue, :add
41
+ def_delegator :self, :enqueue, :conj
42
+ def_delegator :self, :enqueue, :conjoin
41
43
 
42
44
  def dequeue
43
45
  front = @front
@@ -66,20 +68,17 @@ module Hamster
66
68
  def_delegator :self, :eql?, :==
67
69
 
68
70
  def to_a
69
- to_list.to_a
71
+ @front.to_a.concat(@rear.to_a.tap { |a| a.reverse! })
70
72
  end
71
73
  def_delegator :self, :to_a, :entries
72
-
73
- def to_ary
74
- to_list.to_ary
75
- end
74
+ def_delegator :self, :to_a, :to_ary
76
75
 
77
76
  def to_list
78
77
  @front.append(@rear.reverse)
79
78
  end
80
79
 
81
80
  def inspect
82
- to_list.inspect
81
+ to_a.inspect
83
82
  end
84
83
  end
85
84
 
@@ -2,19 +2,33 @@ require "forwardable"
2
2
  require "hamster/immutable"
3
3
  require "hamster/undefined"
4
4
  require "hamster/enumerable"
5
+ require "hamster/groupable"
5
6
  require "hamster/sorter"
6
7
  require "hamster/trie"
7
8
  require "hamster/list"
8
9
 
9
10
  module Hamster
10
11
  def self.set(*items)
11
- items.reduce(EmptySet) { |set, item| set.add(item) }
12
+ Set.new(*items)
12
13
  end
13
14
 
14
15
  class Set
15
16
  extend Forwardable
16
17
  include Immutable
17
18
  include Enumerable
19
+ include Groupable
20
+
21
+ class << self
22
+ alias :alloc :new
23
+
24
+ def new(*items)
25
+ items.empty? ? empty : alloc(Trie[items.map! { |x| [x, nil] }])
26
+ end
27
+
28
+ def empty
29
+ @empty ||= self.alloc
30
+ end
31
+ end
18
32
 
19
33
  def initialize(trie = EmptyTrie)
20
34
  @trie = trie
@@ -34,6 +48,8 @@ module Hamster
34
48
  transform_unless(include?(item)) { @trie = @trie.put(item, nil) }
35
49
  end
36
50
  def_delegator :self, :add, :<<
51
+ def_delegator :self, :add, :conj
52
+ def_delegator :self, :add, :conjoin
37
53
 
38
54
  def delete(item)
39
55
  trie = @trie.delete(item)
@@ -55,12 +71,12 @@ module Hamster
55
71
  def filter
56
72
  return self unless block_given?
57
73
  trie = @trie.filter { |entry| yield(entry.key) }
58
- return EmptySet if trie.empty?
74
+ return self.class.empty if trie.empty?
59
75
  transform_unless(trie.equal?(@trie)) { @trie = trie }
60
76
  end
61
77
 
62
78
  def include?(object)
63
- any? { |item| item.eql?(object) }
79
+ @trie.key?(object)
64
80
  end
65
81
 
66
82
  def head
@@ -100,8 +116,12 @@ module Hamster
100
116
  def_delegator :self, :intersection, :&
101
117
 
102
118
  def difference(other)
103
- trie = @trie.filter { |entry| !other.include?(entry.key) }
104
- transform_unless(trie.equal?(@trie)) { @trie = trie }
119
+ trie = if (@trie.size <= other.size) && (other.is_a?(Hamster::Set) || (defined?(::Set) && other.is_a?(::Set)))
120
+ @trie.filter { |entry| !other.include?(entry.key) }
121
+ else
122
+ other.reduce(@trie) { |trie, item| trie.delete(item) }
123
+ end
124
+ trie.empty? ? self.class.empty : self.class.alloc(trie)
105
125
  end
106
126
  def_delegator :self, :difference, :diff
107
127
  def_delegator :self, :difference, :subtract
@@ -121,27 +141,29 @@ module Hamster
121
141
  end
122
142
 
123
143
  def flatten
124
- reduce(EmptySet) do |set, item|
144
+ reduce(self.class.empty) do |set, item|
125
145
  next set.union(item.flatten) if item.is_a?(Set)
126
146
  set.add(item)
127
147
  end
128
148
  end
129
149
 
130
150
  def group_by(&block)
131
- return group_by { |item| item } unless block_given?
132
- reduce(EmptyHash) do |hash, item|
133
- key = yield(item)
134
- hash.put(key, (hash.get(key) || EmptySet).add(item))
135
- end
151
+ group_by_with(self.class.empty, &block)
136
152
  end
137
153
  def_delegator :self, :group_by, :group
138
154
 
139
155
  def clear
140
- EmptySet
156
+ self.class.empty
141
157
  end
142
158
 
143
159
  def eql?(other)
144
- instance_of?(other.class) && @trie.eql?(other.instance_variable_get(:@trie))
160
+ return false if not instance_of?(other.class)
161
+ other_trie = other.instance_variable_get(:@trie)
162
+ return false if @trie.size != other_trie.size
163
+ @trie.each do |entry|
164
+ return false if !other_trie.key?(entry.key)
165
+ end
166
+ true
145
167
  end
146
168
  def_delegator :self, :eql?, :==
147
169
 
@@ -161,7 +183,21 @@ module Hamster
161
183
  def inspect
162
184
  "{#{to_a.inspect[1..-2]}}"
163
185
  end
186
+
187
+ def marshal_dump
188
+ output = {}
189
+ each do |key|
190
+ output[key] = nil
191
+ end
192
+ output
193
+ end
194
+
195
+ def marshal_load(dictionary)
196
+ @trie = dictionary.reduce(EmptyTrie) do |trie, key_value|
197
+ trie.put(key_value.first, nil)
198
+ end
199
+ end
164
200
  end
165
201
 
166
- EmptySet = Hamster::Set.new
202
+ EmptySet = Hamster::Set.empty
167
203
  end