ffi-radix_tree 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
+ SHA1:
3
+ metadata.gz: b552a559de9350d73c2c847b2aa4f0157fed12a8
4
+ data.tar.gz: f25f0dc4ad08766c3f805b8f75cba8c6fbda5a3d
5
+ SHA512:
6
+ metadata.gz: 63fc44026e11a67bdef49b7c7fd2c1fe3c5c1a34ef7ae3ae26823c52d77a0b278b43e506114dda67baf10f7cfb160e855c5bcef05005102e320ff3ae2395e9eb
7
+ data.tar.gz: 8facbab3ba214d8c382f2c176d6284c9743de7d34e1368e558ed550fa8e4d2b06c988bd29cef5cf01e3286287b9398628a913707284d8f6652960f647ebb8ebf
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.ruby-*
2
+ *.so
3
+ CMakeCache.txt
4
+ /vendor/radixtree/CMakeFiles
5
+ /vendor/radixtree/CMakeFiles/**/*
6
+ /vendor/radixtree/Makefile
7
+ cmake_install.cmake
8
+ /.bundle/
9
+ /.yardoc
10
+ /Gemfile.lock
11
+ /_yardoc/
12
+ /coverage/
13
+ /doc/
14
+ /pkg/
15
+ /spec/reports/
16
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in ffi-radix_tree.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Brandon Dewitt
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,39 @@
1
+ # Ffi::RadixTree
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ffi/radix_tree`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'ffi-radix_tree'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install ffi-radix_tree
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ 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.
30
+
31
+ 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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ffi-radix_tree.
36
+
37
+ ## License
38
+
39
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ import "ext/ffi/radixtree/Rakefile"
4
+
5
+ namespace :radixtree do
6
+ desc "build radixtree"
7
+ task :compile do
8
+ Rake::Task[:compile_radixtree].invoke
9
+ end
10
+ end
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << "test"
14
+ t.libs << "lib"
15
+ t.test_files = FileList["test/**/*_test.rb"]
16
+ end
17
+ Rake::Task[:test].prerequisites << "radixtree:compile"
18
+
19
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ffi/radix_tree"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,62 @@
1
+ require "rubygems"
2
+ require "fileutils"
3
+ require "ffi"
4
+
5
+ # Copied fom mkmf
6
+ def find_executable(bin, path = nil)
7
+ executable_file = proc do |name|
8
+ begin
9
+ stat = File.stat(name)
10
+ rescue SystemCallError
11
+ else
12
+ next name if stat.file? and stat.executable?
13
+ end
14
+ end
15
+
16
+ if File.expand_path(bin) == bin
17
+ return bin if executable_file.call(bin)
18
+ return nil
19
+ end
20
+ if path ||= ENV['PATH']
21
+ path = path.split(File::PATH_SEPARATOR)
22
+ else
23
+ path = %w[/usr/local/bin /usr/ucb /usr/bin /bin]
24
+ end
25
+ file = nil
26
+ path.each do |dir|
27
+ return file if executable_file.call(file = File.join(dir, bin))
28
+ end
29
+ nil
30
+ end
31
+
32
+ def sys(cmd)
33
+ puts " -- #{cmd}"
34
+ unless ret = system(cmd)
35
+ raise "ERROR: '#{cmd}' failed"
36
+ end
37
+ ret
38
+ end
39
+
40
+ desc "Build the radixtree shared lib"
41
+ task :compile_radixtree do
42
+ # Do not attempt to install if we want to use the system radixtree lib
43
+ next if ENV.key?("RADIX_TREE_USE_SYSTEM_LIB")
44
+
45
+ if !find_executable("cmake")
46
+ abort "ERROR: CMake is required to build ffi-radix_tree"
47
+ end
48
+
49
+ CWD = ::File.expand_path(::File.dirname(__FILE__))
50
+ RADIXTREE_DIR = ::File.join(CWD, "..", "..", "..", "vendor", "radixtree")
51
+
52
+ ::Dir.chdir(RADIXTREE_DIR) do
53
+ sys("cmake CMakeLists.txt")
54
+ sys("make")
55
+ end
56
+
57
+ unless ::File.exist?(::File.join(RADIXTREE_DIR, "libradixtree.#{::FFI::Platform::LIBSUFFIX}"))
58
+ abort "ERROR: Failed to build radixtree"
59
+ end
60
+ end
61
+
62
+ task :default => :compile_radixtree
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "ffi/radix_tree/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ffi-radix_tree"
8
+ spec.version = FFI::RadixTree::VERSION
9
+ spec.authors = ["Brandon Dewitt"]
10
+ spec.email = ["brandonsdewitt@gmail.com"]
11
+
12
+ spec.summary = %q{ radix tree implementation in c++ with FFI bindings }
13
+ spec.description = %q{ radix tree implementation in c++ with FFI bindings }
14
+ spec.homepage = "https://www.github.com/abrandoned/ffi-radix_tree"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.extensions = "ext/ffi/radixtree/Rakefile"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_dependency "msgpack"
35
+ spec.add_dependency "ffi"
36
+
37
+ spec.add_development_dependency "bundler", "~> 1.15"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "minitest", "~> 5.0"
40
+ end
@@ -0,0 +1,129 @@
1
+ require "ffi"
2
+ require "msgpack"
3
+ require "ffi/radix_tree/version"
4
+
5
+ module FFI
6
+ module RadixTree
7
+ extend FFI::Library
8
+ ffi_lib_flags :now, :global
9
+
10
+ ##
11
+ # ffi-rzmq-core for reference
12
+ #
13
+ # https://github.com/chuckremes/ffi-rzmq-core/blob/master/lib/ffi-rzmq-core/libzmq.rb
14
+ #
15
+ begin
16
+ # bias the library discovery to a path inside the gem first, then
17
+ # to the usual system paths
18
+ gem_base = ::File.join(::File.dirname(__FILE__), '..', '..', '..')
19
+ inside_gem = ::File.join(gem_base, 'ext')
20
+ local_path = ::FFI::Platform::IS_WINDOWS ? ENV['PATH'].split(';') : ENV['PATH'].split(':')
21
+ env_path = [ ENV['RADIX_TREE_LIB_PATH'] ].compact
22
+ rbconfig_path = ::RbConfig::CONFIG["libdir"]
23
+ homebrew_path = nil
24
+
25
+ # RUBYOPT set by RVM breaks 'brew' so we need to unset it.
26
+ rubyopt = ENV.delete('RUBYOPT')
27
+
28
+ begin
29
+ stdout, stderr, status = ::Open3.capture3("brew", "--prefix")
30
+ homebrew_path = if status.success?
31
+ "#{stdout.chomp}/lib"
32
+ else
33
+ '/usr/local/homebrew/lib'
34
+ end
35
+ rescue
36
+ # Homebrew doesn't exist
37
+ end
38
+
39
+ # Restore RUBYOPT after executing 'brew' above.
40
+ ENV['RUBYOPT'] = rubyopt
41
+
42
+ # Search for libradixtree in the following order...
43
+ radixtree_lib_paths =
44
+ if ENV.key?("RADIX_TREE_USE_SYSTEM_LIB")
45
+ [inside_gem] + env_path + local_path + [rbconfig_path] + [
46
+ '/usr/local/lib', '/opt/local/lib', homebrew_path, '/usr/lib64'
47
+ ]
48
+ else
49
+ [::File.join(gem_base, "vendor/radixtree/build/src")]
50
+ end
51
+
52
+ RADIX_TREE_LIB_PATHS = radixtree_lib_paths.
53
+ compact.map{|path| "#{path}/libradixtree.#{::FFI::Platform::LIBSUFFIX}"}
54
+
55
+ ffi_lib(RADIX_TREE_LIB_PATHS + %w{libradixtree})
56
+ rescue LoadError => error
57
+ if RADIX_TREE_LIB_PATHS.any? {|path| ::File.file?(::File.join(path)) }
58
+ warn "Unable to load this gem. The libradixtree library exists, but cannot be loaded."
59
+ warn "Set RADIX_TREE_LIB_PATH if custom load path is desired"
60
+ warn "If this is Windows:"
61
+ warn "- Check that you have MSVC runtime installed or statically linked"
62
+ warn "- Check that your DLL is compiled for #{FFI::Platform::ADDRESS_SIZE} bit"
63
+ else
64
+ warn "Unable to load this gem. The libradixtree library (or DLL) could not be found."
65
+ warn "Set RADIX_TREE_LIB_PATH if custom load path is desired"
66
+ warn "If this is a Windows platform, make sure libradixtree.dll is on the PATH."
67
+ warn "If the DLL was built with mingw, make sure the other two dependent DLLs,"
68
+ warn "libgcc_s_sjlj-1.dll and libstdc++6.dll, are also on the PATH."
69
+ warn "For non-Windows platforms, make sure libradixtree is located in this search path:"
70
+ warn RADIX_TREE_LIB_PATHS.inspect
71
+ end
72
+ raise error
73
+ end
74
+
75
+ attach_function :create, [], :pointer
76
+ attach_function :destroy, [:pointer], :void
77
+ attach_function :erase, [:string], :void
78
+ attach_function :fetch, [:pointer, :string, :pointer], :pointer
79
+ attach_function :insert, [:pointer, :string, :pointer, :size_t], :void
80
+ attach_function :longest_prefix, [:pointer, :string], :string
81
+ attach_function :longest_prefix_value, [:pointer, :string, :pointer], :pointer
82
+ attach_function :match_free, [:pointer], :void
83
+ attach_function :has_key, [:pointer, :string], :bool
84
+ end
85
+
86
+ class Tree
87
+ DESTROY_METHOD = ::RadixTree.method(:destroy)
88
+ FREE_METHOD = ::RadixTree.method(:match_free)
89
+
90
+ def initialize
91
+ @ptr = ::FFI::AutoPointer.new(::FFI::RadixTree.create, DESTROY_METHOD)
92
+ end
93
+
94
+ def has_key?(key)
95
+ ::FFI::RadixTree.has_key(@ptr, key)
96
+ end
97
+
98
+ def push(key, value)
99
+ storage_data = ::MessagePack.pack(value)
100
+ bytesize = storage_data.bytesize
101
+ memory_buffer = ::FFI::MemoryPointer.new(:char, bytesize, true)
102
+ memory_buffer.put_bytes(0, storage_data)
103
+ ::FFI::RadixTree.insert(@ptr, key, memory_buffer, bytesize)
104
+ end
105
+
106
+ def get(key)
107
+ byte_length = ::FFI::MemoryPointer.new(:int)
108
+ byte_pointer = ::FFI::AutoPointer.new(::FFI::RadixTree.fetch(@ptr, key, byte_length), FREE_METHOD)
109
+ bytesize = byte_length.read_int
110
+ return nil if bytesize <= 0
111
+ ::MessagePack.unpack(byte_pointer.get_bytes(0, bytesize))
112
+ end
113
+
114
+ def longest_prefix(string)
115
+ value, p_out = ::FFI::RadixTree.longest_prefix(@ptr, string)
116
+ p_out = ::FFI::AutoPointer.new(p_out, FREE_METHOD) unless p_out.nil?
117
+ value.force_encoding("UTF-8") unless value.nil?
118
+ value
119
+ end
120
+
121
+ def longest_prefix_value(string)
122
+ byte_length = ::FFI::MemoryPointer.new(:int)
123
+ byte_pointer = ::FFI::AutoPointer.new(::FFI::RadixTree.longest_prefix_value(@ptr, string, byte_length), FREE_METHOD)
124
+ bytesize = byte_length.read_int
125
+ return nil if bytesize <= 0
126
+ ::MessagePack.unpack(byte_pointer.get_bytes(0, bytesize))
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,5 @@
1
+ module FFI
2
+ module RadixTree
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ cmake_minimum_required(VERSION 2.8)
2
+
3
+ project (radixtree)
4
+ set(CMAKE_CXX_FLAGS "-Wall -Wextra")
5
+ set(CMAKE_CXX_FLAGS_DEBUG "-g")
6
+ set(CMAKE_CXX_FLAGS_RELEASE "-O3")
7
+ set(CMAKE_BUILD_TYPE Release)
8
+
9
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
10
+ add_library(radixtree SHARED ffi_radix_tree.cpp)
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2010, Yuuki Takano <ytakanoster@gmail.com>, All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification,
4
+ are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice,
7
+ this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright notice,
9
+ this list of conditions and the following disclaimer in the documentation
10
+ and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
16
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,101 @@
1
+ #include <algorithm>
2
+ #include <iostream>
3
+ #include <cstring>
4
+ #include <string>
5
+ #include <vector>
6
+
7
+ #include "radix_tree.hpp"
8
+
9
+ #ifdef __cplusplus
10
+ #define EXTERN_C extern "C"
11
+ #define EXTERN_C_BEGIN extern "C" {
12
+ #define EXTERN_C_END }
13
+ #else
14
+ #define EXTERN_C /* Nothing */
15
+ #define EXTERN_C_BEGIN /* Nothing */
16
+ #define EXTERN_C_END /* Nothing */
17
+ #endif
18
+
19
+ EXTERN_C_BEGIN
20
+ radix_tree<std::string, std::vector<char>>* create() {
21
+ radix_tree<std::string, std::vector<char>>* map_pointer = new radix_tree<std::string, std::vector<char>>();
22
+
23
+ return map_pointer;
24
+ }
25
+
26
+ void erase(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key) {
27
+ map_pointer->erase(std::string(key));
28
+ }
29
+
30
+ bool has_key(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key) {
31
+ return map_pointer->find(std::string(key)) != map_pointer->end();
32
+ }
33
+
34
+ void match_free(const char* match) {
35
+ if (match != NULL) {
36
+ delete[] match;
37
+ }
38
+ }
39
+
40
+ const char* longest_prefix(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key) {
41
+ std::string string_key(key);
42
+ auto iter = map_pointer->longest_match(string_key);
43
+
44
+ if (iter != map_pointer->end()) {
45
+ char *val = new char[iter->first.size() + 1]{0};
46
+ val[iter->first.size()] = '\0';
47
+ memcpy(val, iter->first.c_str(), iter->first.size());
48
+
49
+ return val;
50
+ }
51
+
52
+ return NULL;
53
+ }
54
+
55
+ const char* longest_prefix_value(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, int* read_size) {
56
+ std::string string_key(key);
57
+ auto iter = map_pointer->longest_match(string_key);
58
+ long counter = 0;
59
+
60
+ if (iter != map_pointer->end()) {
61
+ char *return_val = new char[iter->second.size()]{0};
62
+ for( auto& val : iter->second ) {
63
+ return_val[counter] = val;
64
+ counter++;
65
+ }
66
+
67
+ *read_size = iter->second.size();
68
+ return return_val;
69
+ }
70
+
71
+ *read_size = 0;
72
+ return NULL;
73
+ }
74
+
75
+ const char* fetch(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, int* read_size) {
76
+ auto iter = map_pointer->find(std::string(key));
77
+ long counter = 0;
78
+
79
+ if (iter != map_pointer->end()) {
80
+ char *return_val = new char[iter->second.size()]{0};
81
+ for( auto& val : iter->second ) {
82
+ return_val[counter] = val;
83
+ counter++;
84
+ }
85
+
86
+ *read_size = iter->second.size();
87
+ return return_val;
88
+ }
89
+
90
+ *read_size = 0;
91
+ return NULL;
92
+ }
93
+
94
+ void insert(radix_tree<std::string, std::vector<char>>* map_pointer, const char* key, char* value, size_t size) {
95
+ map_pointer->insert({std::string(key), std::vector<char>(value, value + size)});
96
+ }
97
+
98
+ void destroy(radix_tree<std::string, std::vector<char>>* map_pointer) {
99
+ delete map_pointer;
100
+ }
101
+ EXTERN_C_END