@@ -198,16 +198,21 @@ class IMAP
198
198
# - #full?: Returns whether the set contains every possible value, including
199
199
# <tt>*</tt>.
200
200
#
201
+ # <i>Denormalized properties:</i>
202
+ # - #has_duplicates?: Returns whether the ordered entries repeat any
203
+ # numbers.
204
+ # - #count_duplicates: Returns the count of repeated numbers in the ordered
205
+ # entries.
206
+ # - #count_with_duplicates: Returns the count of numbers in the ordered
207
+ # entries, including any repeated numbers.
208
+ #
201
209
# === Methods for Iterating
202
210
#
211
+ # <i>Normalized (sorted and coalesced):</i>
203
212
# - #each_element: Yields each number and range in the set, sorted and
204
213
# coalesced, and returns +self+.
205
214
# - #elements (aliased as #to_a): Returns an Array of every number and range
206
215
# in the set, sorted and coalesced.
207
- # - #each_entry: Yields each number and range in the set, unsorted and
208
- # without deduplicating numbers or coalescing ranges, and returns +self+.
209
- # - #entries: Returns an Array of every number and range in the set,
210
- # unsorted and without deduplicating numbers or coalescing ranges.
211
216
# - #each_range:
212
217
# Yields each element in the set as a Range and returns +self+.
213
218
# - #ranges: Returns an Array of every element in the set, converting
@@ -217,6 +222,12 @@ class IMAP
217
222
# ranges into all of their contained numbers.
218
223
# - #to_set: Returns a Set containing all of the #numbers in the set.
219
224
#
225
+ # <i>Order preserving:</i>
226
+ # - #each_entry: Yields each number and range in the set, unsorted and
227
+ # without deduplicating numbers or coalescing ranges, and returns +self+.
228
+ # - #entries: Returns an Array of every number and range in the set,
229
+ # unsorted and without deduplicating numbers or coalescing ranges.
230
+ #
220
231
# === Methods for \Set Operations
221
232
# These methods do not modify +self+.
222
233
#
@@ -236,19 +247,29 @@ class IMAP
236
247
# === Methods for Assigning
237
248
# These methods add or replace elements in +self+.
238
249
#
250
+ # <i>Normalized (sorted and coalesced):</i>
251
+ #
252
+ # These methods always update #string to be fully sorted and coalesced.
253
+ #
239
254
# - #add (aliased as #<<): Adds a given object to the set; returns +self+.
240
255
# - #add?: If the given object is not an element in the set, adds it and
241
256
# returns +self+; otherwise, returns +nil+.
242
257
# - #merge: Merges multiple elements into the set; returns +self+.
258
+ # - #complement!: Replaces the contents of the set with its own #complement.
259
+ #
260
+ # <i>Order preserving:</i>
261
+ #
262
+ # These methods _may_ cause #string to not be sorted or coalesced.
263
+ #
243
264
# - #append: Adds a given object to the set, appending it to the existing
244
265
# string, and returns +self+.
245
266
# - #string=: Assigns a new #string value and replaces #elements to match.
246
267
# - #replace: Replaces the contents of the set with the contents
247
268
# of a given object.
248
- # - #complement!: Replaces the contents of the set with its own #complement.
249
269
#
250
270
# === Methods for Deleting
251
- # These methods remove elements from +self+.
271
+ # These methods remove elements from +self+, and update #string to be fully
272
+ # sorted and coalesced.
252
273
#
253
274
# - #clear: Removes all elements in the set; returns +self+.
254
275
# - #delete: Removes a given object from the set; returns +self+.
@@ -910,9 +931,7 @@ def numbers; each_number.to_a end
910
931
# Related: #entries, #each_element
911
932
def each_entry ( &block ) # :yields: integer or range or :*
912
933
return to_enum ( __method__ ) unless block_given?
913
- return each_element ( &block ) unless @string
914
- @string . split ( "," ) . each do yield tuple_to_entry str_to_tuple _1 end
915
- self
934
+ each_entry_tuple do yield tuple_to_entry _1 end
916
935
end
917
936
918
937
# Yields each number or range (or <tt>:*</tt>) in #elements to the block
@@ -930,6 +949,16 @@ def each_element # :yields: integer or range or :*
930
949
931
950
private
932
951
952
+ def each_entry_tuple ( &block )
953
+ return to_enum ( __method__ ) unless block_given?
954
+ if @string
955
+ @string . split ( "," ) do block . call str_to_tuple _1 end
956
+ else
957
+ @tuples . each ( &block )
958
+ end
959
+ self
960
+ end
961
+
933
962
def tuple_to_entry ( ( min , max ) )
934
963
if min == STAR_INT then :*
935
964
elsif max == STAR_INT then min ..
@@ -988,12 +1017,49 @@ def to_set; Set.new(numbers) end
988
1017
# If <tt>*</tt> and <tt>2**32 - 1</tt> (the maximum 32-bit unsigned
989
1018
# integer value) are both in the set, they will only be counted once.
990
1019
def count
991
- @tuples . sum ( @tuples . count ) { _2 - _1 } +
992
- ( include_star? && include? ( UINT32_MAX ) ? -1 : 0 )
1020
+ count_numbers_in_tuples ( @tuples )
993
1021
end
994
1022
995
1023
alias size count
996
1024
1025
+ # Returns the count of numbers in the ordered #entries, including any
1026
+ # repeated numbers.
1027
+ #
1028
+ # When #string is normalized, this behaves the same as #count.
1029
+ #
1030
+ # Related: #entries, #count_duplicates, #has_duplicates?
1031
+ def count_with_duplicates
1032
+ return count unless @string
1033
+ count_numbers_in_tuples ( each_entry_tuple )
1034
+ end
1035
+
1036
+ # Returns the count of repeated numbers in the ordered #entries.
1037
+ #
1038
+ # When #string is normalized, this is zero.
1039
+ #
1040
+ # Related: #entries, #count_with_duplicates, #has_duplicates?
1041
+ def count_duplicates
1042
+ return 0 unless @string
1043
+ count_with_duplicates - count
1044
+ end
1045
+
1046
+ # :call-seq: has_duplicates? -> true | false
1047
+ #
1048
+ # Returns whether or not the ordered #entries repeat any numbers.
1049
+ #
1050
+ # Always returns +false+ when #string is normalized.
1051
+ #
1052
+ # Related: #entries, #count_with_duplicates, #count_duplicates?
1053
+ def has_duplicates?
1054
+ return false unless @string
1055
+ count_with_duplicates != count
1056
+ end
1057
+
1058
+ private def count_numbers_in_tuples ( tuples )
1059
+ tuples . sum ( tuples . count ) { _2 - _1 } +
1060
+ ( include_star? && include? ( UINT32_MAX ) ? -1 : 0 )
1061
+ end
1062
+
997
1063
# Returns the index of +number+ in the set, or +nil+ if +number+ isn't in
998
1064
# the set.
999
1065
#
0 commit comments