linked_lists 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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