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

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.
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