dskiplist 0.0.1

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
+ SHA1:
3
+ metadata.gz: f56c0d3deac75e8d56c87df301557365e8bdfae6
4
+ data.tar.gz: 9e991f79a2505c20db7b17e17d64b680d60bc75b
5
+ SHA512:
6
+ metadata.gz: 976a3493109c67757abc19b3bec4f195217d7ab440839644598a042cf6e25dedde0ad0f98191cea5fbf25cd4e9825ec781c4a0bc77e1a793469ec3958c37c62f
7
+ data.tar.gz: d47ebb750ffdbd1dd32f0bec2f9cca91db7862fc0b9fd40b60004a492437f5f49a279f69b40da57f7af043c5b081ec88c9f04c542e7a55bb6f00d14038e8cf90
data/.git-new/HEAD ADDED
@@ -0,0 +1 @@
1
+ ref: refs/heads/master
data/.git-new/config ADDED
@@ -0,0 +1,5 @@
1
+ [core]
2
+ repositoryformatversion = 0
3
+ filemode = true
4
+ bare = false
5
+ logallrefupdates = true
@@ -0,0 +1 @@
1
+ Unnamed repository; edit this file 'description' to name the repository.
@@ -0,0 +1,15 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to check the commit log message taken by
4
+ # applypatch from an e-mail message.
5
+ #
6
+ # The hook should exit with non-zero status after issuing an
7
+ # appropriate message if it wants to stop the commit. The hook is
8
+ # allowed to edit the commit message file.
9
+ #
10
+ # To enable this hook, rename this file to "applypatch-msg".
11
+
12
+ . git-sh-setup
13
+ test -x "$GIT_DIR/hooks/commit-msg" &&
14
+ exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
15
+ :
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to check the commit log message.
4
+ # Called by "git commit" with one argument, the name of the file
5
+ # that has the commit message. The hook should exit with non-zero
6
+ # status after issuing an appropriate message if it wants to stop the
7
+ # commit. The hook is allowed to edit the commit message file.
8
+ #
9
+ # To enable this hook, rename this file to "commit-msg".
10
+
11
+ # Uncomment the below to add a Signed-off-by line to the message.
12
+ # Doing this in a hook is a bad idea in general, but the prepare-commit-msg
13
+ # hook is more suited to it.
14
+ #
15
+ # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
16
+ # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
17
+
18
+ # This example catches duplicate Signed-off-by lines.
19
+
20
+ test "" = "$(grep '^Signed-off-by: ' "$1" |
21
+ sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
22
+ echo >&2 Duplicate Signed-off-by lines.
23
+ exit 1
24
+ }
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to prepare a packed repository for use over
4
+ # dumb transports.
5
+ #
6
+ # To enable this hook, rename this file to "post-update".
7
+
8
+ exec git update-server-info
@@ -0,0 +1,14 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to verify what is about to be committed
4
+ # by applypatch from an e-mail message.
5
+ #
6
+ # The hook should exit with non-zero status after issuing an
7
+ # appropriate message if it wants to stop the commit.
8
+ #
9
+ # To enable this hook, rename this file to "pre-applypatch".
10
+
11
+ . git-sh-setup
12
+ test -x "$GIT_DIR/hooks/pre-commit" &&
13
+ exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
14
+ :
@@ -0,0 +1,50 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to verify what is about to be committed.
4
+ # Called by "git commit" with no arguments. The hook should
5
+ # exit with non-zero status after issuing an appropriate message if
6
+ # it wants to stop the commit.
7
+ #
8
+ # To enable this hook, rename this file to "pre-commit".
9
+
10
+ if git rev-parse --verify HEAD >/dev/null 2>&1
11
+ then
12
+ against=HEAD
13
+ else
14
+ # Initial commit: diff against an empty tree object
15
+ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
16
+ fi
17
+
18
+ # If you want to allow non-ascii filenames set this variable to true.
19
+ allownonascii=$(git config hooks.allownonascii)
20
+
21
+ # Redirect output to stderr.
22
+ exec 1>&2
23
+
24
+ # Cross platform projects tend to avoid non-ascii filenames; prevent
25
+ # them from being added to the repository. We exploit the fact that the
26
+ # printable range starts at the space character and ends with tilde.
27
+ if [ "$allownonascii" != "true" ] &&
28
+ # Note that the use of brackets around a tr range is ok here, (it's
29
+ # even required, for portability to Solaris 10's /usr/bin/tr), since
30
+ # the square bracket bytes happen to fall in the designated range.
31
+ test $(git diff --cached --name-only --diff-filter=A -z $against |
32
+ LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
33
+ then
34
+ echo "Error: Attempt to add a non-ascii file name."
35
+ echo
36
+ echo "This can cause problems if you want to work"
37
+ echo "with people on other platforms."
38
+ echo
39
+ echo "To be portable it is advisable to rename the file ..."
40
+ echo
41
+ echo "If you know what you are doing you can disable this"
42
+ echo "check using:"
43
+ echo
44
+ echo " git config hooks.allownonascii true"
45
+ echo
46
+ exit 1
47
+ fi
48
+
49
+ # If there are whitespace errors, print the offending file names and fail.
50
+ exec git diff-index --check --cached $against --
@@ -0,0 +1,169 @@
1
+ #!/bin/sh
2
+ #
3
+ # Copyright (c) 2006, 2008 Junio C Hamano
4
+ #
5
+ # The "pre-rebase" hook is run just before "git rebase" starts doing
6
+ # its job, and can prevent the command from running by exiting with
7
+ # non-zero status.
8
+ #
9
+ # The hook is called with the following parameters:
10
+ #
11
+ # $1 -- the upstream the series was forked from.
12
+ # $2 -- the branch being rebased (or empty when rebasing the current branch).
13
+ #
14
+ # This sample shows how to prevent topic branches that are already
15
+ # merged to 'next' branch from getting rebased, because allowing it
16
+ # would result in rebasing already published history.
17
+
18
+ publish=next
19
+ basebranch="$1"
20
+ if test "$#" = 2
21
+ then
22
+ topic="refs/heads/$2"
23
+ else
24
+ topic=`git symbolic-ref HEAD` ||
25
+ exit 0 ;# we do not interrupt rebasing detached HEAD
26
+ fi
27
+
28
+ case "$topic" in
29
+ refs/heads/??/*)
30
+ ;;
31
+ *)
32
+ exit 0 ;# we do not interrupt others.
33
+ ;;
34
+ esac
35
+
36
+ # Now we are dealing with a topic branch being rebased
37
+ # on top of master. Is it OK to rebase it?
38
+
39
+ # Does the topic really exist?
40
+ git show-ref -q "$topic" || {
41
+ echo >&2 "No such branch $topic"
42
+ exit 1
43
+ }
44
+
45
+ # Is topic fully merged to master?
46
+ not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
47
+ if test -z "$not_in_master"
48
+ then
49
+ echo >&2 "$topic is fully merged to master; better remove it."
50
+ exit 1 ;# we could allow it, but there is no point.
51
+ fi
52
+
53
+ # Is topic ever merged to next? If so you should not be rebasing it.
54
+ only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
55
+ only_next_2=`git rev-list ^master ${publish} | sort`
56
+ if test "$only_next_1" = "$only_next_2"
57
+ then
58
+ not_in_topic=`git rev-list "^$topic" master`
59
+ if test -z "$not_in_topic"
60
+ then
61
+ echo >&2 "$topic is already up-to-date with master"
62
+ exit 1 ;# we could allow it, but there is no point.
63
+ else
64
+ exit 0
65
+ fi
66
+ else
67
+ not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
68
+ /usr/bin/perl -e '
69
+ my $topic = $ARGV[0];
70
+ my $msg = "* $topic has commits already merged to public branch:\n";
71
+ my (%not_in_next) = map {
72
+ /^([0-9a-f]+) /;
73
+ ($1 => 1);
74
+ } split(/\n/, $ARGV[1]);
75
+ for my $elem (map {
76
+ /^([0-9a-f]+) (.*)$/;
77
+ [$1 => $2];
78
+ } split(/\n/, $ARGV[2])) {
79
+ if (!exists $not_in_next{$elem->[0]}) {
80
+ if ($msg) {
81
+ print STDERR $msg;
82
+ undef $msg;
83
+ }
84
+ print STDERR " $elem->[1]\n";
85
+ }
86
+ }
87
+ ' "$topic" "$not_in_next" "$not_in_master"
88
+ exit 1
89
+ fi
90
+
91
+ <<\DOC_END
92
+
93
+ This sample hook safeguards topic branches that have been
94
+ published from being rewound.
95
+
96
+ The workflow assumed here is:
97
+
98
+ * Once a topic branch forks from "master", "master" is never
99
+ merged into it again (either directly or indirectly).
100
+
101
+ * Once a topic branch is fully cooked and merged into "master",
102
+ it is deleted. If you need to build on top of it to correct
103
+ earlier mistakes, a new topic branch is created by forking at
104
+ the tip of the "master". This is not strictly necessary, but
105
+ it makes it easier to keep your history simple.
106
+
107
+ * Whenever you need to test or publish your changes to topic
108
+ branches, merge them into "next" branch.
109
+
110
+ The script, being an example, hardcodes the publish branch name
111
+ to be "next", but it is trivial to make it configurable via
112
+ $GIT_DIR/config mechanism.
113
+
114
+ With this workflow, you would want to know:
115
+
116
+ (1) ... if a topic branch has ever been merged to "next". Young
117
+ topic branches can have stupid mistakes you would rather
118
+ clean up before publishing, and things that have not been
119
+ merged into other branches can be easily rebased without
120
+ affecting other people. But once it is published, you would
121
+ not want to rewind it.
122
+
123
+ (2) ... if a topic branch has been fully merged to "master".
124
+ Then you can delete it. More importantly, you should not
125
+ build on top of it -- other people may already want to
126
+ change things related to the topic as patches against your
127
+ "master", so if you need further changes, it is better to
128
+ fork the topic (perhaps with the same name) afresh from the
129
+ tip of "master".
130
+
131
+ Let's look at this example:
132
+
133
+ o---o---o---o---o---o---o---o---o---o "next"
134
+ / / / /
135
+ / a---a---b A / /
136
+ / / / /
137
+ / / c---c---c---c B /
138
+ / / / \ /
139
+ / / / b---b C \ /
140
+ / / / / \ /
141
+ ---o---o---o---o---o---o---o---o---o---o---o "master"
142
+
143
+
144
+ A, B and C are topic branches.
145
+
146
+ * A has one fix since it was merged up to "next".
147
+
148
+ * B has finished. It has been fully merged up to "master" and "next",
149
+ and is ready to be deleted.
150
+
151
+ * C has not merged to "next" at all.
152
+
153
+ We would want to allow C to be rebased, refuse A, and encourage
154
+ B to be deleted.
155
+
156
+ To compute (1):
157
+
158
+ git rev-list ^master ^topic next
159
+ git rev-list ^master next
160
+
161
+ if these match, topic has not merged in next at all.
162
+
163
+ To compute (2):
164
+
165
+ git rev-list master..topic
166
+
167
+ if this is empty, it is fully merged to "master".
168
+
169
+ DOC_END
@@ -0,0 +1,36 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to prepare the commit log message.
4
+ # Called by "git commit" with the name of the file that has the
5
+ # commit message, followed by the description of the commit
6
+ # message's source. The hook's purpose is to edit the commit
7
+ # message file. If the hook fails with a non-zero status,
8
+ # the commit is aborted.
9
+ #
10
+ # To enable this hook, rename this file to "prepare-commit-msg".
11
+
12
+ # This hook includes three examples. The first comments out the
13
+ # "Conflicts:" part of a merge commit.
14
+ #
15
+ # The second includes the output of "git diff --name-status -r"
16
+ # into the message, just before the "git status" output. It is
17
+ # commented because it doesn't cope with --amend or with squashed
18
+ # commits.
19
+ #
20
+ # The third example adds a Signed-off-by line to the message, that can
21
+ # still be edited. This is rarely a good idea.
22
+
23
+ case "$2,$3" in
24
+ merge,)
25
+ /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
26
+
27
+ # ,|template,)
28
+ # /usr/bin/perl -i.bak -pe '
29
+ # print "\n" . `git diff --cached --name-status -r`
30
+ # if /^#/ && $first++ == 0' "$1" ;;
31
+
32
+ *) ;;
33
+ esac
34
+
35
+ # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
36
+ # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
@@ -0,0 +1,128 @@
1
+ #!/bin/sh
2
+ #
3
+ # An example hook script to blocks unannotated tags from entering.
4
+ # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
5
+ #
6
+ # To enable this hook, rename this file to "update".
7
+ #
8
+ # Config
9
+ # ------
10
+ # hooks.allowunannotated
11
+ # This boolean sets whether unannotated tags will be allowed into the
12
+ # repository. By default they won't be.
13
+ # hooks.allowdeletetag
14
+ # This boolean sets whether deleting tags will be allowed in the
15
+ # repository. By default they won't be.
16
+ # hooks.allowmodifytag
17
+ # This boolean sets whether a tag may be modified after creation. By default
18
+ # it won't be.
19
+ # hooks.allowdeletebranch
20
+ # This boolean sets whether deleting branches will be allowed in the
21
+ # repository. By default they won't be.
22
+ # hooks.denycreatebranch
23
+ # This boolean sets whether remotely creating branches will be denied
24
+ # in the repository. By default this is allowed.
25
+ #
26
+
27
+ # --- Command line
28
+ refname="$1"
29
+ oldrev="$2"
30
+ newrev="$3"
31
+
32
+ # --- Safety check
33
+ if [ -z "$GIT_DIR" ]; then
34
+ echo "Don't run this script from the command line." >&2
35
+ echo " (if you want, you could supply GIT_DIR then run" >&2
36
+ echo " $0 <ref> <oldrev> <newrev>)" >&2
37
+ exit 1
38
+ fi
39
+
40
+ if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
41
+ echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
42
+ exit 1
43
+ fi
44
+
45
+ # --- Config
46
+ allowunannotated=$(git config --bool hooks.allowunannotated)
47
+ allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
48
+ denycreatebranch=$(git config --bool hooks.denycreatebranch)
49
+ allowdeletetag=$(git config --bool hooks.allowdeletetag)
50
+ allowmodifytag=$(git config --bool hooks.allowmodifytag)
51
+
52
+ # check for no description
53
+ projectdesc=$(sed -e '1q' "$GIT_DIR/description")
54
+ case "$projectdesc" in
55
+ "Unnamed repository"* | "")
56
+ echo "*** Project description file hasn't been set" >&2
57
+ exit 1
58
+ ;;
59
+ esac
60
+
61
+ # --- Check types
62
+ # if $newrev is 0000...0000, it's a commit to delete a ref.
63
+ zero="0000000000000000000000000000000000000000"
64
+ if [ "$newrev" = "$zero" ]; then
65
+ newrev_type=delete
66
+ else
67
+ newrev_type=$(git cat-file -t $newrev)
68
+ fi
69
+
70
+ case "$refname","$newrev_type" in
71
+ refs/tags/*,commit)
72
+ # un-annotated tag
73
+ short_refname=${refname##refs/tags/}
74
+ if [ "$allowunannotated" != "true" ]; then
75
+ echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
76
+ echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
77
+ exit 1
78
+ fi
79
+ ;;
80
+ refs/tags/*,delete)
81
+ # delete tag
82
+ if [ "$allowdeletetag" != "true" ]; then
83
+ echo "*** Deleting a tag is not allowed in this repository" >&2
84
+ exit 1
85
+ fi
86
+ ;;
87
+ refs/tags/*,tag)
88
+ # annotated tag
89
+ if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
90
+ then
91
+ echo "*** Tag '$refname' already exists." >&2
92
+ echo "*** Modifying a tag is not allowed in this repository." >&2
93
+ exit 1
94
+ fi
95
+ ;;
96
+ refs/heads/*,commit)
97
+ # branch
98
+ if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
99
+ echo "*** Creating a branch is not allowed in this repository" >&2
100
+ exit 1
101
+ fi
102
+ ;;
103
+ refs/heads/*,delete)
104
+ # delete branch
105
+ if [ "$allowdeletebranch" != "true" ]; then
106
+ echo "*** Deleting a branch is not allowed in this repository" >&2
107
+ exit 1
108
+ fi
109
+ ;;
110
+ refs/remotes/*,commit)
111
+ # tracking branch
112
+ ;;
113
+ refs/remotes/*,delete)
114
+ # delete tracking branch
115
+ if [ "$allowdeletebranch" != "true" ]; then
116
+ echo "*** Deleting a tracking branch is not allowed in this repository" >&2
117
+ exit 1
118
+ fi
119
+ ;;
120
+ *)
121
+ # Anything else (is there anything else?)
122
+ echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
123
+ exit 1
124
+ ;;
125
+ esac
126
+
127
+ # --- Finished
128
+ exit 0
data/.git-new/index ADDED
Binary file
@@ -0,0 +1,6 @@
1
+ # git ls-files --others --exclude-from=.git/info/exclude
2
+ # Lines that start with '#' are comments.
3
+ # For a project mostly in C, the following would be a good set of
4
+ # exclude patterns (uncomment them if you want to use them):
5
+ # *.[oa]
6
+ # *~
@@ -0,0 +1 @@
1
+ x5ɱ� @��s i�&L�eD^�~#7�X4"��x�l�K��W��^Z�Z�ȩ�b�K��vê�ؔ
@@ -0,0 +1,5 @@
1
+ x]RK��0�Y�b�i�v�,=����Fԑ��l��J��X����w�<� F���5j������/�9}L��;xh����+�f��u��y�n�h!����ZmF�z5��S=:�E�������������8���i\�G=H
- �N�#�5{w'���֚V׈�i�]�<�^�ƒ�Y�׉�c �T=�M��
2
+ ���fv�]L��6���y
3
+ �Ns3h�G����vZ_ )E��W3�U��4�^�� =�B0�FxϽ9~v���iDJ �u# ��U�<�W�7�`�h
4
+ ��r |]d�%pg���7X���r|�Z�� �P��\J�L�+D�K��jA�+�1S�PPY�x�Q �Fyɐ>!"\�Yؚ�� Y�
5
+ �;�\�, Tt��e���N�U�<K��d�.3v�BSqF�:����W'!G�
@@ -0,0 +1 @@
1
+ x5�1� ��yE��`q�o��jO���ߋ�S�$.f�2In�#�V����\?��˩��ag�tt�#�a�@@�0yBJ�&�$�|���� �#�
@@ -0,0 +1,2 @@
1
+ xe�MO�0 �9�WXڤn��0B�6�8
2
+ ˵h`q$���i�����������:i���M��M�i��-�i�܄�o3x ��/C3���� ce-����l��J�+~�O�r��
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dskiplist.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Forrest
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # DSkipList
2
+
3
+ Warning: This software is alpha.
4
+
5
+ This is a ruby skiplist much faster than the ruby skiplist gem here https://github.com/metanest/ruby-skiplist
6
+ Benchmarks below
7
+
8
+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'dskiplist'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install dskiplist
23
+
24
+ ## Usage
25
+ ``` ruby
26
+ require 'dskiplist'
27
+
28
+ list = DSkipList.new
29
+
30
+ list[1] = 'dog'
31
+ list[2] = 'cat'
32
+
33
+ #or
34
+
35
+ list.insert_hash Hash[3 => 'fish']
36
+
37
+ list[1]
38
+ => 'dog'
39
+
40
+ list.to_a
41
+ => ['dog', 'cat', 'fish']
42
+
43
+ list.to_h
44
+ => {1=>"dog", 2=>"cat", 3=>"fish"}
45
+
46
+ list.each {|e| puts e.reverse}
47
+ => god
48
+ => tac
49
+ => shif
50
+
51
+
52
+ list.count
53
+ => 3
54
+
55
+ list.clear
56
+ => empty list
57
+
58
+
59
+
60
+ ```
61
+ ## Benchmarks
62
+ Other list: https://github.com/metanest/ruby-skiplist
63
+
64
+ ```ruby
65
+ this list insert 10000 elements time:
66
+ 0.150000
67
+ other skip list insert 10000 elements time:
68
+ 3.540000
69
+ this list search 10000 elements time
70
+ 0.080000
71
+ other list search 10000 elements time
72
+ 2.480000
73
+ ```
74
+ But slower than Ruby's hash
75
+ ```ruby
76
+ user system total real
77
+ List insert million elements: 23.680000 0.150000 23.830000 ( 25.223663)
78
+ Hash insert million elements: 2.740000 0.060000 2.800000 ( 2.949170)
79
+ List search 10000 elements 0.140000 0.000000 0.140000 ( 0.169945)
80
+ Hash search 10000 elements 0.050000 0.000000 0.050000 ( 0.104777)
81
+
82
+ ```
83
+ Ok, so why use this instead of hash? Order
84
+ ```ruby
85
+ >> list[1] = "duck"
86
+ >> list [2] = "goose"
87
+ >> list[3] = "quail"
88
+ >> list[4] = "pidgin"
89
+
90
+ >> list.smallest
91
+ => "duck"
92
+ >> list.largest
93
+ => "pidgin"
94
+
95
+ #get your elements in order
96
+ >> list.to_a
97
+ => ["duck", "goose", "quail", "pidgin"]
98
+
99
+ #or in an inclusive range
100
+ >> from = 1
101
+ >> to = 3
102
+ #0 is the base layer of the list. It contains all elements. default 0
103
+ >> layer = 0
104
+ #limit return size if desired
105
+ >> limit = nil
106
+
107
+ >> list.to_a(from, to, limit, layer)
108
+ => ["duck", "goose", "quail"]
109
+ >> list.to_a(2, nil, 2)
110
+ => ["goose", "quail"]
111
+ >> list.to_a(nil, 3, nil)
112
+ => ["duck", "goose", "quail"]
113
+
114
+ #or count the elements between two elements(plus two to include the endpoints)
115
+ >> list.count(from, to)
116
+ => 3
117
+
118
+ ```
119
+
120
+ ## Contributing
121
+
122
+ 1. Fork it ( http://github.com/<my-github-username>/dskiplist/fork )
123
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
124
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
125
+ 4. Push to the branch (`git push origin my-new-feature`)
126
+ 5. Create new Pull Request
127
+
128
+
129
+
130
+
131
+ ToDo:
132
+ - Jruby multithreading and locking with mutexes for multi-core support.
133
+ - Lazy operations
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/dskiplist.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dskiplist/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dskiplist"
8
+ spec.version = Dskiplist::VERSION
9
+ spec.authors = ["Forrest Allison"]
10
+ spec.email = ["light24bulbs@gmail.com"]
11
+ spec.summary = %q{High speed skiplist gem}
12
+ spec.homepage = "https://github.com/light24bulbs/dynamic-skiplist/"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = '>= 1.9.3'
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.5"
21
+ spec.add_development_dependency "rake"
22
+ end
@@ -0,0 +1,3 @@
1
+ module Dskiplist
2
+ VERSION = "0.0.1"
3
+ end
data/lib/dskiplist.rb ADDED
@@ -0,0 +1,225 @@
1
+ =begin
2
+ The MIT License (MIT)
3
+
4
+ Copyright (c) 2014 Forrest Allison
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+ =end
24
+
25
+ class DSkipList
26
+ attr_accessor :level
27
+ attr_accessor :header
28
+ include Enumerable
29
+
30
+ class Node
31
+ attr_accessor :key
32
+ attr_accessor :value
33
+ attr_accessor :forward
34
+
35
+ def initialize(k, v = nil)
36
+ @key = k
37
+ @value = v.nil? ? k : v
38
+ @forward = []
39
+ end
40
+ end
41
+
42
+ def initialize(top_level = Float::INFINITY)
43
+ @header = Node.new(1)
44
+ @level = 0
45
+ @max_level = top_level
46
+ @p = 0.5
47
+ @node_nil = Node.new(1000000)
48
+ end
49
+
50
+ def clear
51
+ initialize(@max_level)
52
+ return self
53
+ end
54
+
55
+ def find_node(search_key)
56
+ x = @header
57
+ @level.downto(0) do |i|
58
+ while x.forward[i] and x.forward[i].key < search_key
59
+ x = x.forward[i]
60
+ end
61
+ end
62
+ x = x.forward[0]
63
+ if x and x.key == search_key
64
+ return x
65
+ else
66
+ return nil
67
+ end
68
+ end
69
+
70
+ def [] key
71
+ node = self.find_node(key)
72
+ return node.value if node
73
+ end
74
+
75
+ def random_level
76
+ v = 0
77
+ while rand < @p && v < @max_level
78
+ v += 1
79
+ end
80
+ v
81
+ end
82
+
83
+ def delete(search_key)
84
+ update = []
85
+ x = @header
86
+ @level.downto(0) do |i|
87
+ while x.forward[i] and x.forward[i].key < search_key
88
+ x = x.forward[i]
89
+ end
90
+ update[i] = x
91
+ end
92
+ x = x.forward[0]
93
+ if x and x.key == search_key
94
+ 0.upto(x.forward.length - 1) do |i|
95
+ update[i].forward[i] = x.forward[i] if x.forward[i]
96
+ end
97
+ return true
98
+ else
99
+ return false
100
+ end
101
+ end
102
+
103
+
104
+ def insert(search_key, new_value = nil)
105
+ new_value = search_key if new_value.nil?
106
+ update = []
107
+ x = @header
108
+ @level.downto(0) do |i|
109
+ while x.forward[i] and x.forward[i].key < search_key
110
+ x = x.forward[i]
111
+ end
112
+ update[i] = x
113
+ end
114
+ x = x.forward[0]
115
+ if x and x.key == search_key
116
+ x.value = new_value
117
+ else
118
+ v = random_level
119
+ if v > @level
120
+ (@level + 1).upto(v) do |i|
121
+ update[i] = @header
122
+ end
123
+ @level = v
124
+ end
125
+ x = Node.new(search_key, new_value)
126
+ 0.upto(v) do |i|
127
+ x.forward[i] = update[i].forward[i]
128
+ update[i].forward[i] = x
129
+ end
130
+ end
131
+ return self
132
+ end
133
+
134
+ def []= key, value
135
+ self.insert(key, value)
136
+ end
137
+
138
+ def insert_hash(hash)
139
+ hash.each {|key, value| self[key] = value}
140
+ return self
141
+ end
142
+
143
+ def count(from = nil, to = nil, level = 0)
144
+ walk(from, to, nil, level, nil)
145
+ end
146
+
147
+ def walk(from, to, limit, level, output)
148
+ if from
149
+ x = find_node(from)
150
+ raise 'start node not found' if !x
151
+ else
152
+ x = @header.forward[level]
153
+ end
154
+ if to
155
+ to_node = find_node(to)
156
+ raise 'stop node not found' if !to_node
157
+ end
158
+ #if no block is given, assume we are trying to count
159
+ if !block_given?
160
+ count = 0
161
+ while x
162
+ count += 1
163
+ break if to_node == x
164
+ x = x.forward[level]
165
+ end
166
+ return count
167
+ elsif to_node or limit
168
+ count = 0
169
+ while x
170
+ yield(x, output)
171
+ count += 1
172
+ break if to_node and x == to_node
173
+ break if limit and count == limit
174
+ x = x.forward[level]
175
+ end
176
+ else
177
+ while x
178
+ yield(x, output)
179
+ x = x.forward[level]
180
+ end
181
+ end
182
+ return output
183
+ end
184
+
185
+ def to_h(from = nil, to = nil, limit = nil, level = 0)
186
+ walk(from, to, limit, level, {}) {|n, hash| hash[n.key] = n.value}
187
+ end
188
+
189
+ def to_a(from = nil, to = nil, limit = nil, level = 0)
190
+ walk(from, to, limit, level, []) {|n, arr| arr.push(n.value)}
191
+ end
192
+ alias_method :to_ary, :to_a
193
+
194
+ def largest
195
+ x = @header
196
+ @level.downto(0) do |i|
197
+ while x.forward[i]
198
+ x = x.forward[i]
199
+ end
200
+ end
201
+ return x.value
202
+ end
203
+
204
+ def smallest
205
+ return @header.forward[0].value
206
+ end
207
+
208
+ def to_s
209
+ str = ""
210
+ @level.downto(0) do |l|
211
+ str << "Level #{l}: " + to_a(nil, nil, nil, l).join('-') + "\n"
212
+ end
213
+ return str
214
+ end
215
+
216
+ def to_str
217
+ return "SkipList level #{@max_level}"
218
+ end
219
+
220
+ def each(&block)
221
+ self.to_a.each(&block)
222
+ end
223
+
224
+ end
225
+
data/skiplist-test.rb ADDED
@@ -0,0 +1,50 @@
1
+ require './lib/dskiplist.rb'
2
+ require 'benchmark'
3
+ require 'skiplist'
4
+ list = DSkipList.new
5
+ otherList = SkipList.new 100
6
+ hash = {}
7
+ Benchmark.bm(30) do |b|
8
+ #b.report('Insert time: ') {1.upto(100000) {|i| list[i] = i}}
9
+ #b.report('Other list insert: ') {1.upto(10000) {|i| otherList[i] = i}}
10
+ #b.report('Search time: ') {1.upto(10000) {|i| list[i]}}
11
+ #b.report('Other list search: ') {1.upto(10000) {|i| otherList[i]}}
12
+ #b.report('List insert million elements: ') {10000.upto(1010000) {|i| list[i] = i}}
13
+ #b.report('Hash insert million elements: ') {1.upto(1000000) {|i| hash[i] = i}}
14
+ #b.report('List search 10000') {1000000.upto(1010000) {|i| list[i]}}
15
+ #b.report('Hash search 10000') {900000.upto(1000000) {|i| hash[i]}}
16
+ #b.report('List +10000: ') {1040000.upto(1050000) {|i| list[i] = i}}
17
+ #b.report('Search time: ') {1000000.upto(1010000) {|i| list[i]}}
18
+ b.report('to_a: ') {list.to_a}
19
+ b.report('to_h: ') {list.to_h}
20
+ end
21
+ hash = Hash['a'=> 1, 'b'=>2, 'c'=>3]
22
+ puts "the hash size is " + hash.count.to_s
23
+ puts list.insert_hash hash
24
+ puts list.to_s
25
+ puts list
26
+ puts "list size: " + list.count.to_s
27
+ puts list.to_a.to_s
28
+ #puts "deleting 150"
29
+ #list.delete(150)
30
+ puts "list level " + list.level.to_s
31
+ #list[100000000] = "the highest element"
32
+ puts "smallest is: " + list.smallest.to_s
33
+ puts "largest is: " + list.largest.to_s
34
+ #puts "range from 100 to 110: " + list.to_a(100,110).join(',')
35
+ def test(list)
36
+ complete = list.to_a
37
+ 1.upto(list.level) do |l|
38
+ #if anything in the higher layer wasn't in layer 0
39
+ difference = list.to_a(nil,nil,nil,l) - complete
40
+ puts "test failed level #{l} ,inconsistent node(s) #{difference}" if (difference.count != 0)
41
+ end
42
+ puts "test complete"
43
+ end
44
+ #puts list.to_s
45
+ #test(list)
46
+ #list.clear
47
+
48
+ #puts "attempting to use string as key"
49
+ #list["hello"] = "world"
50
+ #puts "the output of key hello is: " + list["hello"]
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dskiplist
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Forrest Allison
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description:
42
+ email:
43
+ - light24bulbs@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".git-new/HEAD"
49
+ - ".git-new/config"
50
+ - ".git-new/description"
51
+ - ".git-new/hooks/applypatch-msg.sample"
52
+ - ".git-new/hooks/commit-msg.sample"
53
+ - ".git-new/hooks/post-update.sample"
54
+ - ".git-new/hooks/pre-applypatch.sample"
55
+ - ".git-new/hooks/pre-commit.sample"
56
+ - ".git-new/hooks/pre-rebase.sample"
57
+ - ".git-new/hooks/prepare-commit-msg.sample"
58
+ - ".git-new/hooks/update.sample"
59
+ - ".git-new/index"
60
+ - ".git-new/info/exclude"
61
+ - ".git-new/objects/0e/edc5f174ed9e76e83ef27b2a54c604632bf443"
62
+ - ".git-new/objects/29/955274e0d42e164337c411ad9144e8ffd7e46e"
63
+ - ".git-new/objects/36/8486cc0ca607437a86b263d962a1a99e53871e"
64
+ - ".git-new/objects/76/f3e51982d7f828f33bfdf9d1bb1e4828681e8c"
65
+ - ".git-new/objects/80/68966517dd445a29902032053bb0345af12dee"
66
+ - ".git-new/objects/8d/5bb04a9ca61fea0629b41a31da796169e05f14"
67
+ - ".git-new/objects/ae/ee3428c017916e5cc0e57d387224f33ed0b990"
68
+ - ".git-new/objects/d8/7d4be66f458acd52878902bbf1391732ad21e1"
69
+ - ".gitignore"
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - dskiplist.gemspec
75
+ - lib/dskiplist.rb
76
+ - lib/dskiplist/version.rb
77
+ - skiplist-test.rb
78
+ homepage: https://github.com/light24bulbs/dynamic-skiplist/
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 1.9.3
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.2.2
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: High speed skiplist gem
102
+ test_files: []