skn_utils 3.3.4 → 3.3.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fc867ac95eebf226b53be3336ddf721265150d4
4
- data.tar.gz: a70380b703cd8f20d25b314f7710720788953669
3
+ metadata.gz: 84cb7bcd483e3369c94109704c491658263a497d
4
+ data.tar.gz: 0fefb9e19e864638acfeaa605dd315e12db33a0c
5
5
  SHA512:
6
- metadata.gz: 5a72919f92f6e597edec5bedb80beece8a45b68741471e3c9e422ca6a572b6029e023b226ecd26966f27706653426d772737bdca241c0072f525802145588b07
7
- data.tar.gz: b7f22a691d0c272dc4d48ae92713bbf73ededd4666994d04ec3ee1d6e463cbf86598f0833e619007eed81251624baea8c3fe87342987a67ca0a0703b17d1a087
6
+ metadata.gz: 66f1414ed28fae1ab9e2701c6d21590e9ea463303964c23de9ffd0f3eabe5df701bc18bb6cceb9c98752d353038d79bbffb97909d1dd447c683eeafc88c9cb12
7
+ data.tar.gz: 3552bd034096bc4c60f339082af9a22f09bfe57e4c53b589507306e3e190e7598a5b765da62f7ad561fa5270df14652f6272d9d939359c32901cc10802c54abe
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # Ref: https://github.com/evanphx/benchmark-ips
5
+ #
6
+
7
+ require 'bundler/setup'
8
+ require 'skn_utils'
9
+ require 'ostruct'
10
+ require 'benchmark/ips'
11
+
12
+ class GCSuite
13
+ def warming(*)
14
+ run_gc
15
+ end
16
+
17
+ def running(*)
18
+ run_gc
19
+ end
20
+
21
+ def warmup_stats(*)
22
+ end
23
+
24
+ def add_report(*)
25
+ end
26
+
27
+ private
28
+
29
+ def run_gc
30
+ GC.enable
31
+ GC.start
32
+ GC.disable
33
+ end
34
+ end
35
+
36
+ suite = GCSuite.new
37
+
38
+ # Warming up --------------------------------------
39
+ # LinkedList Ops 2.297k i/100ms
40
+ # Array Ops 34.468k i/100ms
41
+ # Calculating -------------------------------------
42
+ # LinkedList Ops 17.015k (±35.2%) i/s - 71.207k in 5.100193s
43
+ # Array Ops 377.943k (± 7.3%) i/s - 1.896M in 5.048217s
44
+ #
45
+ # Comparison:
46
+ # Array Ops: 377942.7 i/s
47
+ # LinkedList Ops: 17015.4 i/s - 22.21x slower
48
+
49
+
50
+ Benchmark.ips do |x|
51
+ x.config(:suite => suite)
52
+
53
+ adders = [50, 10, 110, 6, 30, 101, 12, 33, 4]
54
+ vargs = [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
55
+ cproc = lambda {|a| a}
56
+
57
+ x.report('LinkedList Ops') do
58
+ ll = SknUtils::Lists::LinkedList.new(*vargs, &cproc)
59
+ adders.each {|x| ll.insert_after(74, x)}
60
+ value = ll.sort!
61
+ ll.first
62
+ ll.clear
63
+ end
64
+
65
+ x.report('Array Ops') do
66
+ ary = Array.new(vargs)
67
+ adders.each {|x| ary.insert(5, x)}
68
+ value = ary.sort!
69
+ ary.first
70
+ ary.clear
71
+ end
72
+
73
+ x.compare!
74
+ end
@@ -35,6 +35,21 @@ end
35
35
 
36
36
  suite = GCSuite.new
37
37
 
38
+ # Warming up --------------------------------------
39
+ # regular class 179.755k i/100ms
40
+ # OpenStruct class 11.367k i/100ms
41
+ # NestedResult class 9.674k i/100ms
42
+ # Calculating -------------------------------------
43
+ # regular class 3.674M (±17.4%) i/s - 17.256M in 5.001576s
44
+ # OpenStruct class 155.394k (±31.2%) i/s - 670.653k in 5.095404s
45
+ # NestedResult class 119.896k (±39.0%) i/s - 493.374k in 5.212147s
46
+ #
47
+ # Comparison:
48
+ # regular class: 3673640.5 i/s
49
+ # OpenStruct class: 155394.0 i/s - 23.64x slower
50
+ # NestedResult class: 119896.1 i/s - 30.64x slower
51
+ #
52
+
38
53
  Benchmark.ips do |x|
39
54
  x.config(:suite => suite)
40
55
 
@@ -65,54 +80,3 @@ Benchmark.ips do |x|
65
80
 
66
81
  x.compare!
67
82
  end
68
-
69
- # Warming up --------------------------------------
70
- # regular class 179.755k i/100ms
71
- # OpenStruct class 11.367k i/100ms
72
- # NestedResult class 9.674k i/100ms
73
- # Calculating -------------------------------------
74
- # regular class 3.674M (±17.4%) i/s - 17.256M in 5.001576s
75
- # OpenStruct class 155.394k (±31.2%) i/s - 670.653k in 5.095404s
76
- # NestedResult class 119.896k (±39.0%) i/s - 493.374k in 5.212147s
77
- #
78
- # Comparison:
79
- # regular class: 3673640.5 i/s
80
- # OpenStruct class: 155394.0 i/s - 23.64x slower
81
- # NestedResult class: 119896.1 i/s - 30.64x slower
82
- #
83
- # Warming up --------------------------------------
84
- # LinkedList Ops 2.297k i/100ms
85
- # Array Ops 34.468k i/100ms
86
- # Calculating -------------------------------------
87
- # LinkedList Ops 17.015k (±35.2%) i/s - 71.207k in 5.100193s
88
- # Array Ops 377.943k (± 7.3%) i/s - 1.896M in 5.048217s
89
- #
90
- # Comparison:
91
- # Array Ops: 377942.7 i/s
92
- # LinkedList Ops: 17015.4 i/s - 22.21x slower
93
-
94
-
95
- Benchmark.ips do |x|
96
- x.config(:suite => suite)
97
-
98
- adders = [50, 10, 110, 6, 30, 101, 12, 33, 4]
99
- vargs = [70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
100
-
101
- x.report('LinkedList Ops') do
102
- ll = SknUtils::Lists::LinkedList.new(*vargs)
103
- adders.each {|x| ll.insert_after(74, x)}
104
- value = ll.sort!
105
- ll.first
106
- ll.clear
107
- end
108
-
109
- x.report('Array Ops') do
110
- ary = Array.new(vargs)
111
- adders.each {|x| ary.insert(5, x)}
112
- value = ary.sort!
113
- ary.first
114
- ary.clear
115
- end
116
-
117
- x.compare!
118
- end
@@ -1,3 +1,26 @@
1
+ ##
2
+ # File <SknUtils>/lib/skn_utils/lists/circular_linked_list.rb
3
+ #
4
+ # ll = SknUtils::Lists::CircularLinkedList.new(*vargs, &compare_key_proc)
5
+ # - or -
6
+ # ll = SknUtils::Lists::CircularLinkedList.new(1,2,3,4,5) {|element| element[:key] }
7
+ # - or -
8
+ # ll = SknUtils::Lists::CircularLinkedList.new(
9
+ # {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
10
+ # ) {|el| el[:key] }
11
+ # - or -
12
+ # cmp_proc = lambda { |el| el[:key] }
13
+ # vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
14
+ # ll = SknUtils::Lists::CircularLinkedList.new(*vargs, &cmp_proc)
15
+ ###
16
+ # value = ll.first
17
+ # value = ll.at_index(4)
18
+ # count = ll.insert({key: 'anyValue'})
19
+ # ...
20
+ # count = ll.sort! -- defaults to :asc
21
+ # count = ll.sort!(:desc)
22
+ # count = ll.sort!() {|a,b| a[:key] <= b[:key] }
23
+ ##
1
24
 
2
25
  module SknUtils
3
26
  module Lists
@@ -29,7 +52,7 @@ module SknUtils
29
52
  # return values and position current to last node accessed
30
53
  # prevent @current from nil assignment
31
54
  def first
32
- @current = head if head
55
+ @current = self.head if self.head
33
56
  @current.value rescue nil
34
57
  end
35
58
 
@@ -48,7 +71,7 @@ module SknUtils
48
71
  end
49
72
 
50
73
  def last
51
- @current = tail if tail
74
+ @current = self.tail if self.tail
52
75
  @current.value rescue nil
53
76
  end
54
77
 
@@ -81,7 +104,7 @@ module SknUtils
81
104
  end
82
105
 
83
106
  def empty?
84
- size == 0
107
+ self.size == 0
85
108
  end
86
109
 
87
110
  #
@@ -96,12 +119,12 @@ module SknUtils
96
119
 
97
120
  # return new size
98
121
  def prepend(value)
99
- temp = head.value rescue nil
122
+ temp = self.head.value rescue nil
100
123
  insert_before(temp, value)
101
124
  end
102
125
  # return new size
103
126
  def append(value)
104
- temp = tail.value rescue nil
127
+ temp = self.tail.value rescue nil
105
128
  insert_after(temp, value)
106
129
  end
107
130
 
@@ -109,9 +132,19 @@ module SknUtils
109
132
  def insert_before(position_value, value)
110
133
  target = find_by_value(position_value)
111
134
  node = LinkNode.new(value, target, :circle_before, &@match_value)
112
- @current = node if target
113
- self.head = node if head === target
114
- self.tail = node if tail.nil?
135
+ @current = node
136
+ if self.size == 0 # only
137
+ self.head = node
138
+ self.tail = node
139
+ elsif self.head == target # new head
140
+ self.head = node
141
+ node.prev = self.tail
142
+ self.tail.next = node
143
+ elsif self.tail == target
144
+ self.tail = node
145
+ node.next = self.head
146
+ self.head.prev = node
147
+ end
115
148
  self.size += 1
116
149
  end
117
150
 
@@ -120,8 +153,18 @@ module SknUtils
120
153
  target = find_by_value(position_value)
121
154
  node = LinkNode.new(value, target, :circle_after, &@match_value)
122
155
  @current = node
123
- self.head = node if head.nil?
124
- self.tail = node if tail === target
156
+ if self.size == 0 # only
157
+ self.head = node
158
+ self.tail = node
159
+ elsif self.tail == target
160
+ self.tail = node
161
+ node.next = self.head
162
+ self.head.prev = node
163
+ elsif self.head == target # new head
164
+ self.head = node
165
+ node.prev = self.tail
166
+ self.tail.next = node
167
+ end
125
168
  self.size += 1
126
169
  end
127
170
 
@@ -129,25 +172,40 @@ module SknUtils
129
172
  def remove(value)
130
173
  target_node = find_by_value(value)
131
174
  if target_node
132
- @current = target_node.prev
133
- @current.next = target_node.next
134
- @current.next.prev = @current if @current and @current.next and @current.next.prev
175
+ if self.size == 1 # will become zero
176
+ @current = nil
177
+ self.head = nil
178
+ self.tail = nil
179
+ elsif target_node === self.head # top
180
+ @current = target_node.next
181
+ @current.prev = target_node.prev
182
+ self.tail.next = @current
183
+ self.head = @current
184
+ elsif target_node === self.tail # bottom
185
+ @current = target_node.prev
186
+ @current.next = target_node.next
187
+ self.head.prev = @current
188
+ self.tail = @current
189
+ else # middle
190
+ @current = target_node.prev
191
+ @current.next = target_node.next
192
+ @current.next.prev = @current
193
+ end
135
194
  target_node.remove!
195
+ self.size -= 1
136
196
  end
137
- self.tail = @current if tail === target_node
138
- self.head = @current if head === target_node
139
- self.size -= 1
140
197
  end
141
198
 
199
+
142
200
  # return number cleared
143
201
  def clear
144
202
  rc = 0
145
- node = head
146
- position = head
203
+ node = self.head
204
+ position = node
147
205
  while node do
148
206
  node = node.remove!
149
207
  rc += 1
150
- break if position === node
208
+ break if position.equal?(node)
151
209
  end
152
210
 
153
211
  @current = nil
@@ -163,8 +221,8 @@ module SknUtils
163
221
 
164
222
  # perform each() or return enumerator
165
223
  def each(&block)
166
- @current = head
167
- position = head
224
+ @current = self.head
225
+ position = self.head
168
226
  if block_given?
169
227
  while position do
170
228
  block.call( position.value.dup )
@@ -184,13 +242,13 @@ module SknUtils
184
242
 
185
243
  # convert self to a value array
186
244
  def to_a
187
- @current = head
188
- position = head
245
+ @current = self.head
246
+ position = self.head
189
247
  result = []
190
248
  while position do
191
249
  result << position.value.dup
192
250
  position = position.next
193
- break if position === @current
251
+ break if position.equal?(@current)
194
252
  end
195
253
  result
196
254
  end
@@ -206,33 +264,34 @@ module SknUtils
206
264
  else
207
265
  @sort_condition
208
266
  end
209
- sorted = merge_sort(to_a)
267
+ sorted = merge_sort(self.to_a)
210
268
  clear
211
269
  sorted.each {|item| insert(item) }
212
- size
270
+ self.size
213
271
  end
214
272
 
215
- private
273
+ protected
216
274
 
217
275
  attr_accessor :head, :tail
218
276
 
219
277
  def find_by_value(value)
220
- return nil if head.nil? or value.nil? or size == 0
221
- prior = head
222
- target = prior
223
- while target and not target.match_by_value(value)
224
- prior = target
225
- target = prior.next
226
- @current = target if target
278
+ return nil if value.nil? || self.size == 0
279
+ stop_node = self.head
280
+ target = stop_node
281
+ rtn_node = nil
282
+ while !target.match_by_value(value)
283
+ target = target.next
284
+ break if stop_node.equal?(target)
227
285
  end
286
+ target = nil unless target.match_by_value(value)
228
287
  target
229
288
  end
230
289
 
231
290
  def find_by_index(index)
232
- return nil if head.nil? or index < 1 or index > size
233
- node = head
234
- node = node.next while ((index -= 1) > 0 and node.next)
235
- @current = node if node
291
+ return nil if ( index > self.size || index < 1 )
292
+ node = self.head
293
+ node = node.next while ( (index -= 1) > 0 )
294
+ @current = node
236
295
  node
237
296
  end
238
297
 
@@ -240,26 +299,20 @@ module SknUtils
240
299
  # arr is Array to be sorted, sort_cond is Proc expecting a/b params returning true/false
241
300
  def merge_sort(arr)
242
301
  return arr if arr.size < 2
243
-
244
302
  middle = arr.size / 2
245
-
246
- left = merge_sort(arr[0...middle])
247
- right = merge_sort(arr[middle..arr.size])
248
-
303
+ left = merge_sort(arr[0...middle])
304
+ right = merge_sort(arr[middle..arr.size])
249
305
  merge(left, right)
250
306
  end
251
307
 
252
308
  def merge(left, right)
253
309
  sorted = []
254
-
255
310
  while left.any? && right.any?
256
-
257
311
  if @active_sort_condition.call(left.first, right.first)
258
312
  sorted.push right.shift
259
313
  else
260
314
  sorted.push left.shift
261
315
  end
262
-
263
316
  end
264
317
 
265
318
  sorted + left + right
@@ -1,3 +1,26 @@
1
+ ##
2
+ # File <SknUtils>/lib/skn_utils/lists/doubly_linked_list.rb
3
+ #
4
+ # ll = SknUtils::Lists::DoublyLinkedList.new(*vargs, &compare_key_proc)
5
+ # - or -
6
+ # ll = SknUtils::Lists::DoublyLinkedList.new(1,2,3,4,5) {|element| element[:key] }
7
+ # - or -
8
+ # ll = SknUtils::Lists::DoublyLinkedList.new(
9
+ # {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
10
+ # ) {|el| el[:key] }
11
+ # - or -
12
+ # cmp_proc = lambda { |el| el[:key] }
13
+ # vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
14
+ # ll = SknUtils::Lists::DoublyLinkedList.new(*vargs, &cmp_proc)
15
+ ###
16
+ # value = ll.first
17
+ # value = ll.at_index(4)
18
+ # count = ll.insert({key: 'anyValue'})
19
+ # ...
20
+ # count = ll.sort! -- defaults to :asc
21
+ # count = ll.sort!(:desc)
22
+ # count = ll.sort!() {|a,b| a[:key] <= b[:key] }
23
+ ##
1
24
 
2
25
  module SknUtils
3
26
  module Lists
@@ -127,14 +150,26 @@ module SknUtils
127
150
  def remove(value)
128
151
  target_node = find_by_value(value)
129
152
  if target_node
130
- @current = target_node.prev if target_node.prev
131
- @current.next = target_node.next if target_node.next
132
- @current.next.prev = @current if @current and @current.next and @current.next.prev
153
+ if size == 1 # will become zero
154
+ @current = nil
155
+ self.head = nil
156
+ self.tail = nil
157
+ elsif target_node.prev.nil? # top
158
+ @current = target_node.next
159
+ @current.prev = nil
160
+ self.head = @current
161
+ elsif target_node.next.nil? # bottom
162
+ @current = target_node.prev
163
+ @current.next = nil
164
+ self.tail = @current
165
+ else # middle
166
+ @current = target_node.prev
167
+ @current.next = target_node.next
168
+ target_node.next.prev = @current
169
+ end
133
170
  target_node.remove!
171
+ self.size -= 1
134
172
  end
135
- self.tail = @current if tail === target_node
136
- self.head = @current if head === target_node
137
- self.size -= 1
138
173
  end
139
174
 
140
175
  # return number cleared
@@ -215,13 +250,12 @@ module SknUtils
215
250
  attr_accessor :head, :tail
216
251
 
217
252
  def find_by_value(value)
218
- return nil if head.nil? or value.nil?
253
+ return nil if head.nil? || value.nil? || size == 0
219
254
  prior = head
220
255
  target = prior
221
256
  while target and not target.match_by_value(value)
222
257
  prior = target
223
258
  target = prior.next
224
- @current = target if target
225
259
  end
226
260
  target
227
261
  end
@@ -16,26 +16,26 @@ module SknUtils
16
16
 
17
17
  case strategy
18
18
  when :single # after logic
19
- anchor_node.next = self if anchor_node
19
+ if anchor_node
20
+ @next = anchor_node.next
21
+ anchor_node.next = self
22
+ end
20
23
  when :before
21
24
  @prev = anchor_node.prev if anchor_node
22
- @next = anchor_node
23
25
  anchor_node.prev = self if anchor_node
26
+ @next = anchor_node
24
27
  when :after
25
- @prev = anchor_node
26
28
  @next = anchor_node.next if anchor_node
27
29
  anchor_node.next = self if anchor_node
28
- @next.prev = self if @next
30
+ @prev = anchor_node
29
31
  when :circle_before
30
32
  @prev = anchor_node ? anchor_node.prev : self
31
- @next = anchor_node ? anchor_node : self
32
33
  anchor_node.prev = self if anchor_node
33
- @prev.next = self if anchor_node
34
+ @next = anchor_node ? anchor_node : self
34
35
  when :circle_after
35
- @prev = anchor_node ? anchor_node : self
36
36
  @next = anchor_node ? anchor_node.next : self
37
37
  anchor_node.next = self if anchor_node
38
- @next.prev = self if anchor_node
38
+ @prev = anchor_node ? anchor_node : self
39
39
  end
40
40
  end
41
41
 
@@ -1,3 +1,26 @@
1
+ ##
2
+ # File <SknUtils>/lib/skn_utils/lists/linked_list.rb
3
+ #
4
+ # ll = SknUtils::Lists::LinkedList.new(*vargs, &compare_key_proc)
5
+ # - or -
6
+ # ll = SknUtils::Lists::LinkedList.new(1,2,3,4,5) {|element| element[:key] }
7
+ # - or -
8
+ # ll = SknUtils::Lists::LinkedList.new(
9
+ # {key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}
10
+ # ) {|el| el[:key] }
11
+ # - or -
12
+ # cmp_proc = lambda { |el| el[:key] }
13
+ # vargs = [{key: 'Z'}, {key: 'K'}, {key: 'S'}, {key: 'n'}, {key: 's'}]
14
+ # ll = SknUtils::Lists::LinkedList.new(*vargs, &cmp_proc)
15
+ ###
16
+ # value = ll.first
17
+ # value = ll.at_index(4)
18
+ # count = ll.insert({key: 'anyValue'})
19
+ # ...
20
+ # count = ll.sort! -- defaults to :asc
21
+ # count = ll.sort!(:desc)
22
+ # count = ll.sort!() {|a,b| a[:key] <= b[:key] }
23
+ ##
1
24
 
2
25
  module SknUtils
3
26
  module Lists
@@ -50,7 +73,7 @@ module SknUtils
50
73
  @current.value rescue nil
51
74
  end
52
75
 
53
- # -+ int position from current node
76
+ # +int position from current node
54
77
  def nth(index)
55
78
  node = @current
56
79
  while index > 1 and node and node.next
@@ -60,8 +83,6 @@ module SknUtils
60
83
  end
61
84
  # no reverse or prev for Single List
62
85
  current
63
- rescue NoMethodError
64
- nil
65
86
  end
66
87
 
67
88
  # return node at positive index from head
@@ -119,10 +140,11 @@ module SknUtils
119
140
 
120
141
  # return remaining size
121
142
  def remove(value)
122
- @current, target_node = find_by_value(value)
123
- @current.next = target_node.remove!
124
- self.tail = @current.next if tail === target_node
125
- self.head = @current if head === target_node
143
+ prior, target_node = find_by_value(value)
144
+ @current = prior.nil? ? target_node.next : prior
145
+ @current.next = target_node.remove! if @current && target_node
146
+ self.tail = @current.next if @current && tail === target_node
147
+ self.head = @current.next if @current && head === target_node
126
148
  self.size -= 1
127
149
  end
128
150
 
@@ -203,19 +225,19 @@ module SknUtils
203
225
  attr_accessor :head, :tail
204
226
 
205
227
  def find_by_value(value)
206
- return [nil,nil] if head.nil? or value.nil?
207
- prior = head
228
+ return [@current, nil] if head.nil? || value.nil?
229
+ prior = head
208
230
  target = prior
209
231
  while target and not target.match_by_value(value)
210
232
  prior = target
211
- target = prior.next
212
- @current = target if target
233
+ target = target.next
234
+ @current = prior if target
213
235
  end
214
236
  [prior, target]
215
237
  end
216
238
 
217
239
  def find_by_index(index)
218
- return nil if head.nil? or index < 1 or index > size
240
+ return nil if head.nil? || index < 1 || index > size
219
241
  node = head
220
242
  node = node.next while ((index -= 1) > 0 and node.next)
221
243
  @current = node if node
@@ -3,7 +3,7 @@ module SknUtils
3
3
  class Version
4
4
  MAJOR = 3
5
5
  MINOR = 3
6
- PATCH = 4
6
+ PATCH = 5
7
7
 
8
8
  def self.to_s
9
9
  [MAJOR, MINOR, PATCH].join('.')