dskiplist 0.0.1

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
+ 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: []