linked_lists 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 051b9202e1453821011079e89a87b543e43793e9a6444e4ec13d1b570ce9d091
4
+ data.tar.gz: 532365cb1268753b4b41eb5c081a0971771711f68ac1167f4996d56efd4ee3d8
5
+ SHA512:
6
+ metadata.gz: ac45c59a26b80eac9f3b57d721e6d9242a1e8d50df82781f54760baba3bcfb5494941a3a7ceb173489b185d8f07168265c5ffe31e35834ac59604beda43c5659
7
+ data.tar.gz: 5c98d590c4bd92b18add5298b08c7d12fe1a0e1bd05a5a9f9e492156b76623ce48286fc5ce022cc9d40b478d4316ab8dc1c445cd91f5465bc14f86f7a3b7c65a
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ inherit_gem:
2
+ rubocop-espago: rubocop.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.6
6
+
7
+ Style/MissingElse:
8
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-10-15
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in linked_lists.gemspec
6
+ gemspec
7
+
8
+ gem 'benchmark-ips' # benchmarks
9
+ gem 'debug'
10
+ gem 'minitest', '~> 5.0' # test framework
11
+ gem 'rake', '~> 13.0' # automation scripts
12
+ gem 'rake-compiler' # compiler for the native C extension
13
+ gem 'rubocop-espago' # linter config
14
+ gem 'solargraph' # Ruby language server
15
+ gem 'yard' # documentation tool
data/Gemfile.lock ADDED
@@ -0,0 +1,96 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ linked_lists (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ backport (1.2.0)
11
+ benchmark (0.2.0)
12
+ benchmark-ips (2.10.0)
13
+ debug (1.6.2)
14
+ irb (>= 1.3.6)
15
+ reline (>= 0.3.1)
16
+ diff-lcs (1.5.0)
17
+ e2mmap (0.1.0)
18
+ io-console (0.5.11)
19
+ irb (1.4.2)
20
+ reline (>= 0.3.0)
21
+ jaro_winkler (1.5.4)
22
+ json (2.6.2)
23
+ kramdown (2.4.0)
24
+ rexml
25
+ kramdown-parser-gfm (1.1.0)
26
+ kramdown (~> 2.0)
27
+ minitest (5.16.3)
28
+ nokogiri (1.13.8-arm64-darwin)
29
+ racc (~> 1.4)
30
+ parallel (1.22.1)
31
+ parser (3.1.2.1)
32
+ ast (~> 2.4.1)
33
+ racc (1.6.0)
34
+ rainbow (3.1.1)
35
+ rake (13.0.6)
36
+ rake-compiler (1.2.0)
37
+ rake
38
+ regexp_parser (2.6.0)
39
+ reline (0.3.1)
40
+ io-console (~> 0.5)
41
+ reverse_markdown (2.1.1)
42
+ nokogiri
43
+ rexml (3.2.5)
44
+ rubocop (1.36.0)
45
+ json (~> 2.3)
46
+ parallel (~> 1.10)
47
+ parser (>= 3.1.2.1)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ regexp_parser (>= 1.8, < 3.0)
50
+ rexml (>= 3.2.5, < 4.0)
51
+ rubocop-ast (>= 1.20.1, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 1.4.0, < 3.0)
54
+ rubocop-ast (1.21.0)
55
+ parser (>= 3.1.1.0)
56
+ rubocop-espago (1.0.0)
57
+ rubocop
58
+ ruby-progressbar (1.11.0)
59
+ solargraph (0.47.2)
60
+ backport (~> 1.2)
61
+ benchmark
62
+ bundler (>= 1.17.2)
63
+ diff-lcs (~> 1.4)
64
+ e2mmap
65
+ jaro_winkler (~> 1.5)
66
+ kramdown (~> 2.3)
67
+ kramdown-parser-gfm (~> 1.1)
68
+ parser (~> 3.0)
69
+ reverse_markdown (>= 1.0.5, < 3)
70
+ rubocop (>= 0.52)
71
+ thor (~> 1.0)
72
+ tilt (~> 2.0)
73
+ yard (~> 0.9, >= 0.9.24)
74
+ thor (1.2.1)
75
+ tilt (2.0.11)
76
+ unicode-display_width (2.3.0)
77
+ webrick (1.7.0)
78
+ yard (0.9.28)
79
+ webrick (~> 1.7.0)
80
+
81
+ PLATFORMS
82
+ arm64-darwin-20
83
+
84
+ DEPENDENCIES
85
+ benchmark-ips
86
+ debug
87
+ linked_lists!
88
+ minitest (~> 5.0)
89
+ rake (~> 13.0)
90
+ rake-compiler
91
+ rubocop-espago
92
+ solargraph
93
+ yard
94
+
95
+ BUNDLED WITH
96
+ 2.3.23
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Mateusz Drewniak
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # LinkedLists
2
+
3
+ Adds the linked list structure to Ruby as a proper `Enumerable` class,
4
+ like `Set` or `Array`.
5
+
6
+ Has a similar set of methods to `Array` and `Set`.
7
+
8
+ There are situations in which a linked list would be faster than an array.
9
+ Shifting and unshifting elements for example.
10
+
11
+ This library, for now, is implemented in Ruby which dwindles any performance
12
+ benefits from using this data structure when compared to the native Ruby `Array`.
13
+
14
+ I will reimplement it as a C extension, with the same API in the future.
15
+
16
+ ## Installation
17
+
18
+ Install the gem and add to the application's Gemfile by executing:
19
+
20
+ $ bundle add linked_lists
21
+
22
+ If bundler is not being used to manage dependencies, install the gem by executing:
23
+
24
+ $ gem install linked_lists
25
+
26
+ ## Usage
27
+
28
+ There is a new data structure called `LinkedList` which may be used
29
+ similarly to `Set` or `Array`.
30
+
31
+ It is a proper `Enumerable`.
32
+
33
+ ```ruby
34
+ list = LinkedList[1, 2, 3]
35
+ list #=> #<LinkedList: {1, 2, 3}>
36
+ list.shift #=> 1
37
+ list #=> #<LinkedList: {2, 3}>
38
+ list.unshift(:new) #=> #<LinkedList: {:new, 2, 3}>
39
+
40
+ list.each do |value|
41
+ p value
42
+ end
43
+ # :new
44
+ # 2
45
+ # 3
46
+
47
+ LinkedList[1, 2] + LinkedList[5, 'str'] #=> #<LinkedList: {1, 2, 5, 'str'}>
48
+
49
+ LinkedList[10, 20, 30].map { |a| a * 2 } #=> #<LinkedList: {20, 40, 60}>
50
+ list = LinkedList[10, 20, 30]
51
+ list.map!(&:to_s)
52
+ list #=> #<LinkedList: {"10", "20", "30"}>
53
+ list.to_a #=> ["10", "20", "30"]
54
+
55
+ LinkedList[:foo, nil, :bar, nil].compact #=> #<LinkedList: {:foo, :bar}>
56
+ ```
57
+
58
+ ## Development
59
+
60
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
61
+
62
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
63
+
64
+ ## Contributing
65
+
66
+ Bug reports and pull requests are welcome on GitHub at https://github.com/Verseth/linked_lists.
67
+
68
+ ## License
69
+
70
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ ::Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = ::FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ require 'rubocop/rake_task'
13
+
14
+ ::RuboCop::RakeTask.new
15
+
16
+ require 'rake/extensiontask'
17
+
18
+ task build: :compile
19
+
20
+ ::Rake::ExtensionTask.new('linked_lists') do |ext|
21
+ ext.lib_dir = 'lib/linked_lists'
22
+ end
23
+
24
+ task default: %i[clobber compile test rubocop]
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'benchmark_helper'
4
+
5
+ COUNT = 1000
6
+
7
+ def array_append
8
+ ary = []
9
+ COUNT.times { ary << _1 }
10
+ end
11
+
12
+ def list_append
13
+ linked_list = LinkedList.new
14
+ COUNT.times { linked_list << _1 }
15
+ end
16
+
17
+ Benchmark.ips do |x|
18
+ x.report('Array#append ') { array_append }
19
+ x.report('LinkedList#append') { list_append }
20
+ x.compare!
21
+ end
22
+
23
+ # Ruby 3.1.2
24
+ # Comparison:
25
+ # Array#append : 30031.2 i/s
26
+ # LinkedList#append: 30.3 i/s - 989.63x (± 0.00) slower
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+ require 'benchmark/ips'
5
+ require_relative '../lib/linked_lists'
data/benchmark/pop.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'benchmark_helper'
4
+
5
+ COUNT = 10_000
6
+ ARRAY = Array(0...COUNT)
7
+ LIST = LinkedList.new(0...COUNT)
8
+
9
+
10
+ def array_pop
11
+ while ARRAY.pop; end
12
+ end
13
+
14
+ def list_pop
15
+ while LIST.pop; end
16
+ end
17
+
18
+ Benchmark.bm do |x|
19
+ x.report('Array#pop ') { array_pop }
20
+ x.report('LinkedList#pop') { list_pop }
21
+ end
22
+
23
+ # Ruby 3.1.2
24
+ # user system total real
25
+ # Array#pop 0.000188 0.000022 0.000210 ( 0.000207)
26
+ # LinkedList#pop 2.771274 0.046929 2.818203 ( 2.818997)
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'benchmark_helper'
4
+
5
+ COUNT = 10_000
6
+ ARRAY = Array(0...COUNT)
7
+ LIST = LinkedList.new(0...COUNT)
8
+
9
+ def array_shift
10
+ while ARRAY.shift; end
11
+ end
12
+
13
+ def list_shift
14
+ while LIST.shift; end
15
+ end
16
+
17
+ Benchmark.bm do |x|
18
+ x.report('Array#shift ') { array_shift }
19
+ x.report('LinkedList#shift') { list_shift }
20
+ end
21
+
22
+ # Ruby 3.1.2
23
+ # user system total real
24
+ # Array#shift 0.000198 0.000002 0.000200 ( 0.000198)
25
+ # LinkedList#shift 0.000909 0.000005 0.000914 ( 0.000910)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'benchmark_helper'
4
+
5
+ COUNT = 1000
6
+
7
+ def array_unshift
8
+ ary = []
9
+ COUNT.times { ary.unshift _1 }
10
+ end
11
+
12
+ def list_unshift
13
+ linked_list = LinkedList.new
14
+ COUNT.times { linked_list.unshift _1 }
15
+ end
16
+
17
+ Benchmark.ips do |x|
18
+ x.report('Array#unshift ') { array_unshift }
19
+ x.report('LinkedList#unshift') { list_unshift }
20
+ x.compare!
21
+ end
22
+
23
+ # Ruby 3.1.2
24
+ # Comparison:
25
+ # Array#unshift : 23358.6 i/s
26
+ # LinkedList#unshift: 4713.2 i/s - 4.96x (± 0.00) slower
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+
5
+ create_makefile("linked_lists/linked_lists")
@@ -0,0 +1,9 @@
1
+ #include "linked_lists.h"
2
+
3
+ VALUE rb_mLinkedLists;
4
+
5
+ void
6
+ Init_linked_lists(void)
7
+ {
8
+ rb_mLinkedLists = rb_define_module("LinkedLists");
9
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef LINKED_LISTS_H
2
+ #define LINKED_LISTS_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #endif /* LINKED_LISTS_H */
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LinkedList
4
+ # Represents a node of a singly linked list.
5
+ class Node
6
+ class << self
7
+ # @param value [Object] Value to be wrapped in a node.
8
+ # @return [self]
9
+ def wrap(value)
10
+ return value if value.is_a?(self)
11
+
12
+ new(value)
13
+ end
14
+
15
+ alias [] wrap
16
+ end
17
+
18
+ # @return [self, nil] Next node of the linked list.
19
+ attr_accessor :next
20
+ # @return [Object] The value stored by this node.
21
+ attr_accessor :value
22
+
23
+ # @param value [Object]
24
+ # @param next_node [self, nil]
25
+ def initialize(value = nil, next_node = nil)
26
+ @value = value
27
+ @next = next_node
28
+ end
29
+
30
+ # @return [String]
31
+ def inspect
32
+ "#<#{self.class} #{value.inspect}>"
33
+ end
34
+
35
+ # Inserts the given `objects` after `self`.
36
+ #
37
+ # Time complexity is *O(m)* where *m* is the length of given `objects`.
38
+ #
39
+ # @param objects [Object]
40
+ # @return [self]
41
+ def insert_after(*objects)
42
+ prev_node = self
43
+ objects.each do |obj|
44
+ new_node = self.class.new obj
45
+ new_node.next = prev_node.next
46
+ prev_node.next = new_node
47
+ prev_node = new_node
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ # Set this node as the head of
54
+ # a new linked list.
55
+ #
56
+ # @return [LinkedList]
57
+ def to_list
58
+ list = LinkedList.new
59
+ list.head = self
60
+ list
61
+ end
62
+ end
63
+ end