cidrmergerb 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 +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +23 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cidrmergerb.gemspec +26 -0
- data/ffi/Makefile +28 -0
- data/ffi/cidrmerge.h +153 -0
- data/ffi/libcidrmerge.c +529 -0
- data/ffi/optimized-sort.h +292 -0
- data/lib/cidrmergerb/ext.rb +29 -0
- data/lib/cidrmergerb/version.rb +3 -0
- data/lib/cidrmergerb.rb +61 -0
- metadata +120 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: fa2864f0fa01c1ad5efb023dd31341ae702e5bd0
|
|
4
|
+
data.tar.gz: 025f66ca2d5806b2b06897c6647781e81814d4cc
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 568ae27b383f662a0445f398a95b973fcf8a121896a0b0cdc1b42f60060c9879ddce7182eed7d34fd2c8708b29bd07207ced35d6dbd939156bcd13abbd0ea005
|
|
7
|
+
data.tar.gz: c5428103188e353dc4d164c89f25f2daa7ae45d6d5325f3b9de3f7d49464ace3ad9cad5571cfbd60bc445dd9d3167b1043026e3ff0c7a2d53e13c4c09d0bb9bd
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Cidrmergerb
|
|
2
|
+
|
|
3
|
+
CIDR Optimize toolkit -- wrapping for Daniele's cidr optimization awesome library
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem 'cidrmergerb'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
And then execute:
|
|
14
|
+
|
|
15
|
+
$ bundle
|
|
16
|
+
|
|
17
|
+
Or install it yourself as:
|
|
18
|
+
|
|
19
|
+
$ gem install cidrmergerb
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Cidrmergerb.optimize(cidrs) #=> optimized cidrs
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
2
|
+
require "rake/testtask"
|
|
3
|
+
|
|
4
|
+
Rake::TestTask.new(:test) do |t|
|
|
5
|
+
t.libs << "test"
|
|
6
|
+
t.libs << "lib"
|
|
7
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
desc "clean shared library"
|
|
11
|
+
task :clean_library do
|
|
12
|
+
FileUtils.cd(File.join(File.dirname(__FILE__), 'ext/cidrmergerb'))
|
|
13
|
+
%x{make clean}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
task :default => [:clean_library, :spec]
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "cidrmergerb"
|
|
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
|
data/bin/setup
ADDED
data/cidrmergerb.gemspec
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'cidrmergerb/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "cidrmergerb"
|
|
8
|
+
spec.version = Cidrmergerb::VERSION
|
|
9
|
+
spec.authors = ["Newell Zhu"]
|
|
10
|
+
spec.email = ["newell.zhu@kingaxis.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.}
|
|
13
|
+
spec.description = %q{CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.}
|
|
14
|
+
spec.homepage = "https://github.com/kingaxis/cidrmergerb"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
17
|
+
spec.bindir = "exe"
|
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_runtime_dependency "ffi", '~> 1.9', '>= 1.9.10'
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
26
|
+
end
|
data/ffi/Makefile
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#Compiler command
|
|
2
|
+
UNAME_S := $(shell uname -s)
|
|
3
|
+
ifeq ($(UNAME_S),Linux)
|
|
4
|
+
CC=gcc
|
|
5
|
+
LIBRARY_FLAGS=-shared -lc -ldl -Wl,-soname,liboptimize.so.1
|
|
6
|
+
endif
|
|
7
|
+
ifeq ($(UNAME_S),Darwin)
|
|
8
|
+
CC=g++
|
|
9
|
+
LIBRARY_FLAGS=-shared
|
|
10
|
+
endif
|
|
11
|
+
|
|
12
|
+
CC_FLAGS=-O3 -fPIC -g -c -Wall -W
|
|
13
|
+
CC_FLAGS+= -ansi -pedantic
|
|
14
|
+
STD_DEFINES=-D OPTIMIZED_SORT -D INLINE -D CHAR_PREFIX
|
|
15
|
+
|
|
16
|
+
all: libcidrmerge.so.1.5.3
|
|
17
|
+
|
|
18
|
+
libcidrmerge.o : libcidrmerge.c cidrmerge.h
|
|
19
|
+
gcc ${STD_DEFINES} ${DEBUG_DEFINES} ${CC_FLAGS} -c libcidrmerge.c
|
|
20
|
+
|
|
21
|
+
libcidrmerge.so.1.5.3 : libcidrmerge.o
|
|
22
|
+
${CC} ${LIBRARY_FLAGS} -o libcidrmerge.so libcidrmerge.o
|
|
23
|
+
|
|
24
|
+
clean :
|
|
25
|
+
rm -f *.o core
|
|
26
|
+
rm -f libcidrmerge.so
|
|
27
|
+
rm -f timestamp.out gmon.out
|
|
28
|
+
|
data/ffi/cidrmerge.h
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2004-2008 Daniele Depetrini
|
|
3
|
+
Author: Daniele Depetrini (depetrini@libero.it)
|
|
4
|
+
Version: 1.5.3
|
|
5
|
+
Date: 07/07/08
|
|
6
|
+
|
|
7
|
+
This file is part of cidrmerge.
|
|
8
|
+
|
|
9
|
+
CIDRMerge is free software; you can redistribute it and/or modify
|
|
10
|
+
it under the terms of the GNU General Public License as published by
|
|
11
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
12
|
+
(at your option) any later version.
|
|
13
|
+
|
|
14
|
+
CIDRMerge is distributed in the hope that it will be useful,
|
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
GNU General Public License for more details.
|
|
18
|
+
|
|
19
|
+
You should have received a copy of the GNU General Public License
|
|
20
|
+
along with cidrmerge; if not, write to the Free Software
|
|
21
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
22
|
+
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#ifndef CIDRMERGE
|
|
26
|
+
#define CIDRMERGE
|
|
27
|
+
|
|
28
|
+
#include <stdio.h>
|
|
29
|
+
|
|
30
|
+
#ifdef UNIX_IO
|
|
31
|
+
#include <unistd.h>
|
|
32
|
+
#include <sys/types.h>
|
|
33
|
+
#include <sys/stat.h>
|
|
34
|
+
#include <fcntl.h>
|
|
35
|
+
|
|
36
|
+
#define STREAM int
|
|
37
|
+
#define STDIN 0
|
|
38
|
+
#define STDOUT 1
|
|
39
|
+
#define STDERR 2
|
|
40
|
+
|
|
41
|
+
#define READ(f,b,n) read(f,b,n)
|
|
42
|
+
#define WRITE(f,b,n) write(f,b,n)
|
|
43
|
+
#define OPEN(name) open(name,O_RDONLY)
|
|
44
|
+
#define CLOSE(f) close(f)
|
|
45
|
+
#define N_EOF(f,ret) (ret==0)
|
|
46
|
+
|
|
47
|
+
#else
|
|
48
|
+
|
|
49
|
+
#define STREAM FILE *
|
|
50
|
+
#define STDIN (stdin)
|
|
51
|
+
#define STDOUT (stdout)
|
|
52
|
+
#define STDERR (stderr)
|
|
53
|
+
|
|
54
|
+
#define READ(f,b,n) fread(b,1,n,f)
|
|
55
|
+
#define WRITE(f,b,n) fwrite(b,1,n,f)
|
|
56
|
+
#define OPEN(name) fopen(name,"r")
|
|
57
|
+
#define CLOSE(f) fclose(f)
|
|
58
|
+
#define N_EOF(f,ret) feof(f)
|
|
59
|
+
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
#ifdef TIMESTAMP
|
|
63
|
+
#include <sys/time.h>
|
|
64
|
+
#include <time.h>
|
|
65
|
+
#endif
|
|
66
|
+
|
|
67
|
+
#include <stdlib.h>
|
|
68
|
+
#include <string.h>
|
|
69
|
+
#include <stdint.h>
|
|
70
|
+
|
|
71
|
+
#define MAXLINE 1023
|
|
72
|
+
#define BUFFER 8192*8
|
|
73
|
+
|
|
74
|
+
/* Allocate BUCKET array entries per time */
|
|
75
|
+
#define BUCKET 100000
|
|
76
|
+
#define MAXCIDR 23
|
|
77
|
+
|
|
78
|
+
/*Special prefix values.
|
|
79
|
+
Important: INVALID_PREFIX must be < EXPANDED_PREFIX.
|
|
80
|
+
EXPANDED_PREFIX + 32 must be < 255
|
|
81
|
+
*/
|
|
82
|
+
#define INVALID_PREFIX 200
|
|
83
|
+
#define EXPANDED_PREFIX 220
|
|
84
|
+
|
|
85
|
+
#define MASK1 0xff000000
|
|
86
|
+
#define MASK2 0xff0000
|
|
87
|
+
#define MASK3 0xff00
|
|
88
|
+
#define MASK4 0xff
|
|
89
|
+
|
|
90
|
+
#ifndef MAXINT
|
|
91
|
+
#define MAXINT 0xffffffff
|
|
92
|
+
#endif
|
|
93
|
+
|
|
94
|
+
/* timestamping precision definitions */
|
|
95
|
+
#define PRECISION (1000)
|
|
96
|
+
#define PRECISION_INV (1000000/PRECISION)
|
|
97
|
+
#define PRECISION_STRING "milliseconds"
|
|
98
|
+
|
|
99
|
+
struct entry
|
|
100
|
+
{
|
|
101
|
+
uint32_t network;
|
|
102
|
+
#ifdef CHAR_PREFIX
|
|
103
|
+
unsigned char prefix;
|
|
104
|
+
#else
|
|
105
|
+
uint32_t prefix;
|
|
106
|
+
#endif
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
static uint32_t prefix_table[]= {
|
|
110
|
+
0x0,0x80000000,0xc0000000,0xe0000000,0xf0000000,0xf8000000,0xfc000000,0xfe000000,0xff000000,0xff800000,
|
|
111
|
+
0xffc00000,0xffe00000,0xfff00000,0xfff80000,0xfffc0000,0xfffe0000,0xffff0000,0xffff8000,0xffffc000,
|
|
112
|
+
0xffffe000,0xfffff000,0xfffff800,0xfffffc00,0xfffffe00,0xffffff00,0xffffff80,0xffffffc0,0xffffffe0,
|
|
113
|
+
0xfffffff0,0xfffffff8,0xfffffffc,0xfffffffe,0xffffffff
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/*#define TONETMASK(PREFIX) (((PREFIX)==0)?(0):(MAXINT<<(32-(PREFIX))))*/
|
|
117
|
+
#define TONETMASK(PREFIX) prefix_table[PREFIX]
|
|
118
|
+
|
|
119
|
+
/*
|
|
120
|
+
Function execute the reduction of entry array addr.It returns the number of entries in the final array.
|
|
121
|
+
PARAM: addr array: contains entries to be optimized
|
|
122
|
+
PARAM: len: number of entries into addr array.
|
|
123
|
+
PARAM: do_sort: if 0, sort will NOT be perfomed. Be carefull: optimizing a non-sorted input will produce unpredictable results
|
|
124
|
+
NOTE3: resulting array may contains entries with prefix bigger than EXPANDED_PREFIX. Those are logical pointers: expanded_list[entry.network] (array returned by apply_whitelist function) is the starting position and the leght is entry.prefix- EXPANDED_PREFIX
|
|
125
|
+
*/
|
|
126
|
+
unsigned int optimize(struct entry *addr,unsigned int len,int do_sort);
|
|
127
|
+
|
|
128
|
+
/*
|
|
129
|
+
Remove from array *entry_list occurence of array white.
|
|
130
|
+
Returns number of element into output array expanded_list (that can be reassigned to allow array extension).
|
|
131
|
+
Function allocate more memory if needed. It does NOT deallocate any if the result is smaller.
|
|
132
|
+
PARAM: *entry_list: pointer to input/output param entry list.
|
|
133
|
+
PARAM: **expanded_list: pointer to output param entry list, used to store expanded networks.
|
|
134
|
+
PARAM: *white: white list entry array
|
|
135
|
+
PARAM: len1: number of entry into entry_list in input
|
|
136
|
+
PARAM: len2: number of entry into white_list in input
|
|
137
|
+
PARAM: size_expanded: return paramether that contains memory size of the output expanded_list array
|
|
138
|
+
PARAM: do_sort: if 0, sort will NOT be perfomed on both entry_list and white. Be carefull: optimizing a non-sorted input will produce unpredictable results
|
|
139
|
+
NOTE1: both arrays entry_list and white have to be sorted with sort_entries() function BEFORE calling this.function OR paramether do_sort needs to be set to non zero. Unpredictable results if not
|
|
140
|
+
NOTE2: resulting array may contains entries with INVALID_PREFIX value prefix. This means entry is invalid and it doesn't have to be taken into account.
|
|
141
|
+
NOTE3: resulting array may contains entries with prefix bigger than EXPANDED_PREFIX. Those are logical pointers: expanded_list[entry.network] is the starting position and the leght is entry.prefix- EXPANDED_PREFIX
|
|
142
|
+
NOTE4: resulning array is ordered apart from invalid entries (the ones with INVALID_PREFIX value in prefix)
|
|
143
|
+
*/
|
|
144
|
+
unsigned int apply_whitelist(struct entry *addr,struct entry **expanded_list,struct entry *white,unsigned int len1,unsigned int len2,unsigned int *size_expanded,int do_sort);
|
|
145
|
+
|
|
146
|
+
/*
|
|
147
|
+
Execute entries sorting using quicksort.
|
|
148
|
+
PARAM: addr array: contains entries to be sorted
|
|
149
|
+
PARAM: len: number of entries into addr array.
|
|
150
|
+
*/
|
|
151
|
+
void sort_entries(struct entry *addr,unsigned int len);
|
|
152
|
+
|
|
153
|
+
#endif
|
data/ffi/libcidrmerge.c
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2004-2008 Daniele Depetrini
|
|
3
|
+
Author: Daniele Depetrini (depetrini@libero.it)
|
|
4
|
+
Version: 1.5.3
|
|
5
|
+
Date: 06/07/08
|
|
6
|
+
|
|
7
|
+
This file is part of CIDRMerge.
|
|
8
|
+
|
|
9
|
+
CIDRMerge is free software; you can redistribute it and/or modify
|
|
10
|
+
it under the terms of the GNU General Public License as published by
|
|
11
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
12
|
+
(at your option) any later version.
|
|
13
|
+
|
|
14
|
+
CIDRMerge is distributed in the hope that it will be useful,
|
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
GNU General Public License for more details.
|
|
18
|
+
|
|
19
|
+
You should have received a copy of the GNU General Public License
|
|
20
|
+
along with CIDRMerge; if not, write to the Free Software
|
|
21
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
22
|
+
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
#include "cidrmerge.h"
|
|
26
|
+
|
|
27
|
+
#ifdef LIBRARY_DEBUG
|
|
28
|
+
#include <stdarg.h>
|
|
29
|
+
|
|
30
|
+
/* Using those functions from cidrmerge.c for debugging purposes only */
|
|
31
|
+
void print_address(STREAM file,uint32_t net, unsigned char pref);
|
|
32
|
+
void print_addresses(STREAM f,struct entry *addr,int size,struct entry *expanded,int level);
|
|
33
|
+
|
|
34
|
+
void print_debug(STREAM f,char *buf,char *fmt,...)
|
|
35
|
+
{
|
|
36
|
+
va_list ap;
|
|
37
|
+
va_start(ap, fmt);
|
|
38
|
+
sprintf(buf,fmt,ap);
|
|
39
|
+
WRITE(f,buf,strlen(buf));
|
|
40
|
+
va_end(ap);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#endif
|
|
44
|
+
/*
|
|
45
|
+
Exectute one entry comparation. a1 is bigger than a2 if:
|
|
46
|
+
- a1.network is bigger than a2.network
|
|
47
|
+
- a1.network is equal to a2.network but a1.prefix is bigger than a2.prefix
|
|
48
|
+
PARAM: a1 first entry
|
|
49
|
+
PARAM: a2 second entry
|
|
50
|
+
RETURN VALUE: it returns -1 if a1<a2, 0 if a1=a2 and 1 if a1>a2
|
|
51
|
+
*/
|
|
52
|
+
#ifndef OPTIMIZED_SORT
|
|
53
|
+
typedef int(*cmp_type)(const void *,const void*);
|
|
54
|
+
|
|
55
|
+
static int cmp_entry(struct entry *a1, struct entry *a2)
|
|
56
|
+
{
|
|
57
|
+
if ((*a1).network<(*a2).network)
|
|
58
|
+
{
|
|
59
|
+
return -1;
|
|
60
|
+
}
|
|
61
|
+
if ((*a1).network>(*a2).network)
|
|
62
|
+
{
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
/* Network are ==, so we compare netmasks*/
|
|
66
|
+
if ((*a1).prefix<(*a2).prefix)
|
|
67
|
+
{
|
|
68
|
+
return -1;
|
|
69
|
+
}
|
|
70
|
+
if ((*a1).prefix>(*a2).prefix)
|
|
71
|
+
{
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
#endif
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
Please see cidrmerge.h
|
|
81
|
+
*/
|
|
82
|
+
void sort_entries(struct entry *addr,unsigned int len)
|
|
83
|
+
{
|
|
84
|
+
#ifndef OPTIMIZED_SORT
|
|
85
|
+
/*standard C quicksort*/
|
|
86
|
+
qsort(addr,len,sizeof(struct entry),(cmp_type)cmp_entry);
|
|
87
|
+
#else
|
|
88
|
+
/*Optimized quicksort. Thanks to Michael Tokarev*/
|
|
89
|
+
#include "optimized-sort.h"
|
|
90
|
+
#define cmp_entry(a1,a2) (((a1)->network<(a2)->network) || (((a1)->network==(a2)->network) && ((a1)->prefix<(a2)->prefix)))
|
|
91
|
+
|
|
92
|
+
if (len>1)
|
|
93
|
+
{
|
|
94
|
+
/*sprintf(debug_buf,"SORT: addr[0] %d len %d\n",addr[0].network,len);*/
|
|
95
|
+
QSORT(struct entry,addr,len,cmp_entry);
|
|
96
|
+
}
|
|
97
|
+
#endif
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
#ifdef INLINE
|
|
101
|
+
__inline
|
|
102
|
+
#endif
|
|
103
|
+
static void expand(struct entry **expanded_list,struct entry to_expand,struct entry *white,unsigned int len_white,unsigned int n,unsigned int *current_position,unsigned int *size_expanded)
|
|
104
|
+
{
|
|
105
|
+
int first=*current_position,last=*current_position+n-1;
|
|
106
|
+
unsigned int first_conflict,last_conflict,i;
|
|
107
|
+
struct entry tmp_small,tmp_big;
|
|
108
|
+
struct entry *result=*expanded_list;
|
|
109
|
+
#ifdef LIBRARY_DEBUG
|
|
110
|
+
char debug_buf[MAXLINE];
|
|
111
|
+
#endif
|
|
112
|
+
|
|
113
|
+
*current_position+=n;
|
|
114
|
+
|
|
115
|
+
if (*current_position>*size_expanded)
|
|
116
|
+
{
|
|
117
|
+
/* we need to increase expanded_list array size */
|
|
118
|
+
#ifdef LIBRARY_DEBUG
|
|
119
|
+
print_debug(STDOUT,debug_buf,"BEFORE realloc: size_expanded: %u, MEM: %u\n", *size_expanded,(*size_expanded)*sizeof(struct entry));
|
|
120
|
+
#endif
|
|
121
|
+
|
|
122
|
+
*size_expanded+=BUCKET;
|
|
123
|
+
#ifdef LIBRARY_DEBUG
|
|
124
|
+
print_debug(STDOUT,debug_buf,"AFTER realloc size_expanded: %u,MEM: %u\n", *size_expanded,(*size_expanded)*sizeof(struct entry));
|
|
125
|
+
#endif
|
|
126
|
+
|
|
127
|
+
result=*expanded_list=realloc(*expanded_list,(*size_expanded)*sizeof(struct entry));
|
|
128
|
+
if (result==NULL)
|
|
129
|
+
{
|
|
130
|
+
fprintf(stderr,"Error reallocating %lu bytes\n",(unsigned long)(*size_expanded)*sizeof(struct entry));
|
|
131
|
+
exit(1);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#ifdef LIBRARY_DEBUG
|
|
136
|
+
print_debug(STDOUT,debug_buf,"\nTO EXPAND n %u:\n",n);
|
|
137
|
+
print_address(STDOUT,to_expand.network,to_expand.prefix);
|
|
138
|
+
|
|
139
|
+
print_debug(STDOUT,debug_buf,"START WHITE len_white %u:\n",len_white);
|
|
140
|
+
print_addresses(STDOUT,white,len_white,NULL,0);
|
|
141
|
+
print_debug(STDOUT,debug_buf,"END WHITE\n");
|
|
142
|
+
#endif
|
|
143
|
+
|
|
144
|
+
while (first<=last)
|
|
145
|
+
{
|
|
146
|
+
tmp_small.prefix=tmp_big.prefix=to_expand.prefix+1;
|
|
147
|
+
tmp_small.network=to_expand.network; /*last network bit set to 0 */
|
|
148
|
+
tmp_big.network=to_expand.network+(0x1<<(32-tmp_small.prefix)); /*last network bit set to 1 */
|
|
149
|
+
|
|
150
|
+
if ( (white[0].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network )
|
|
151
|
+
{
|
|
152
|
+
/* conflicting whith tmp_small. */
|
|
153
|
+
i=1;
|
|
154
|
+
/* search for first conflicting position with tmp_big (it cant be the first) */
|
|
155
|
+
while((i<len_white) && !( (white[i].network & TONETMASK(tmp_big.prefix) ) == tmp_big.network ))
|
|
156
|
+
{
|
|
157
|
+
i++;
|
|
158
|
+
}
|
|
159
|
+
first_conflict=i;
|
|
160
|
+
/* search for last conflicting position with tmp_big*/
|
|
161
|
+
while((i<len_white) && ( (white[i].network & TONETMASK(tmp_big.prefix) ) == tmp_big.network ))
|
|
162
|
+
{
|
|
163
|
+
i++;
|
|
164
|
+
}
|
|
165
|
+
last_conflict=i;
|
|
166
|
+
/* check if there is at least one conflicting with tmp_big network into whitelist */
|
|
167
|
+
if (first_conflict!=len_white)
|
|
168
|
+
{
|
|
169
|
+
if (white[first_conflict].prefix!=tmp_big.prefix)
|
|
170
|
+
{
|
|
171
|
+
|
|
172
|
+
#ifdef LIBRARY_DEBUG
|
|
173
|
+
print_debug(STDOUT,debug_buf,"RE-CONFLICT BIG first %u last %u\n",first_conflict,last_conflict);
|
|
174
|
+
print_address(STDOUT,tmp_big.network,tmp_big.prefix);
|
|
175
|
+
#endif
|
|
176
|
+
|
|
177
|
+
result[last].network=*current_position;
|
|
178
|
+
result[last].prefix=EXPANDED_PREFIX+white[first_conflict].prefix-tmp_big.prefix;
|
|
179
|
+
|
|
180
|
+
expand(expanded_list,tmp_big,&white[first_conflict],last_conflict-first_conflict,white[first_conflict].prefix-tmp_big.prefix,current_position,size_expanded);
|
|
181
|
+
}
|
|
182
|
+
else
|
|
183
|
+
{
|
|
184
|
+
#ifdef LIBRARY_DEBUG
|
|
185
|
+
print_debug(STDOUT,debug_buf,"INVALIDATING BIG POSITION %u\n",last);
|
|
186
|
+
#endif
|
|
187
|
+
result[last].prefix=INVALID_PREFIX;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else
|
|
191
|
+
{
|
|
192
|
+
#ifdef LIBRARY_DEBUG
|
|
193
|
+
print_debug(STDOUT,debug_buf,"VALID BIG position %u:\n",last);
|
|
194
|
+
print_address(STDOUT,tmp_big.network,tmp_big.prefix);
|
|
195
|
+
#endif
|
|
196
|
+
result[last].network=tmp_big.network;
|
|
197
|
+
result[last].prefix=tmp_big.prefix;
|
|
198
|
+
}
|
|
199
|
+
to_expand.network=tmp_small.network;
|
|
200
|
+
to_expand.prefix=tmp_small.prefix;
|
|
201
|
+
last--;
|
|
202
|
+
}
|
|
203
|
+
else
|
|
204
|
+
{
|
|
205
|
+
/* conflicting with tmp_big */
|
|
206
|
+
i=1;
|
|
207
|
+
/* search for first conflicting position with tmp_small (it cant be the first)*/
|
|
208
|
+
while((i<len_white) && !( (white[i].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network ))
|
|
209
|
+
{
|
|
210
|
+
i++;
|
|
211
|
+
}
|
|
212
|
+
first_conflict=i;
|
|
213
|
+
/* search for last conflicting position with tmp_small*/
|
|
214
|
+
while((i<len_white) && ( (white[i].network & TONETMASK(tmp_small.prefix) ) == tmp_small.network ))
|
|
215
|
+
{
|
|
216
|
+
i++;
|
|
217
|
+
}
|
|
218
|
+
last_conflict=i;
|
|
219
|
+
|
|
220
|
+
/* check if there is at least one conflicting with tmp_small network into whitelist */
|
|
221
|
+
if (first_conflict!=len_white)
|
|
222
|
+
{
|
|
223
|
+
if (white[first_conflict].prefix!=tmp_small.prefix)
|
|
224
|
+
{
|
|
225
|
+
#ifdef LIBRARY_DEBUG
|
|
226
|
+
print_debug(STDOUT,debug_buf,"RE-CONFLICT LOW first %u last %u\n",first_conflict,last_conflict);
|
|
227
|
+
print_address(STDOUT,tmp_small.network,tmp_small.prefix);
|
|
228
|
+
#endif
|
|
229
|
+
|
|
230
|
+
result[first].network=*current_position;
|
|
231
|
+
result[first].prefix=EXPANDED_PREFIX+white[first_conflict].prefix-tmp_small.prefix;
|
|
232
|
+
|
|
233
|
+
expand(expanded_list,tmp_small,&white[first_conflict],last_conflict-first_conflict,white[first_conflict].prefix-tmp_small.prefix,current_position,size_expanded);
|
|
234
|
+
}
|
|
235
|
+
else
|
|
236
|
+
{
|
|
237
|
+
#ifdef LIBRARY_DEBUG
|
|
238
|
+
print_debug(STDOUT,debug_buf,"INVALIDATING LOW POSITION %u\n",first);
|
|
239
|
+
#endif
|
|
240
|
+
result[first].prefix=INVALID_PREFIX;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else
|
|
244
|
+
{
|
|
245
|
+
#ifdef LIBRARY_DEBUG
|
|
246
|
+
print_debug(STDOUT,debug_buf,"VALID LOW position %u:\n",first);
|
|
247
|
+
print_address(STDOUT,tmp_small.network,tmp_small.prefix);
|
|
248
|
+
#endif
|
|
249
|
+
|
|
250
|
+
result[first].network=tmp_small.network;
|
|
251
|
+
result[first].prefix=tmp_small.prefix;
|
|
252
|
+
}
|
|
253
|
+
to_expand.network=tmp_big.network;
|
|
254
|
+
to_expand.prefix=tmp_big.prefix;
|
|
255
|
+
first++;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#ifdef LIBRARY_DEBUG
|
|
259
|
+
print_debug(STDOUT,debug_buf,"first %d last %d\n",first,last);
|
|
260
|
+
#endif
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
#ifdef LIBRARY_DEBUG
|
|
264
|
+
print_debug(STDOUT,debug_buf,"EXPAND END. Local position %d, current position %u:\n",n,*current_position);
|
|
265
|
+
print_debug(STDOUT,debug_buf,"\n");
|
|
266
|
+
#endif
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/*
|
|
270
|
+
Please see cidrmerge.h
|
|
271
|
+
*/
|
|
272
|
+
unsigned int apply_whitelist(struct entry *addr,struct entry **expanded_list,struct entry *white,unsigned int len1,unsigned int len2,unsigned int *size_expanded,int do_sort)
|
|
273
|
+
{
|
|
274
|
+
unsigned int i1,i2,invalid,tmp,expanded_index=0;
|
|
275
|
+
uint32_t supermask;
|
|
276
|
+
struct entry tmp_entry;
|
|
277
|
+
#ifdef LIBRARY_DEBUG
|
|
278
|
+
char debug_buf[MAXLINE];
|
|
279
|
+
unsigned int step=0;
|
|
280
|
+
print_debug(STDOUT,debug_buf,"START apply_whitelist\n");
|
|
281
|
+
#endif
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
if (do_sort)
|
|
285
|
+
{
|
|
286
|
+
#ifdef LIBRARY_DEBUG
|
|
287
|
+
print_debug(STDOUT,debug_buf,"Sorting entries\n");
|
|
288
|
+
#endif
|
|
289
|
+
sort_entries(addr,len1);
|
|
290
|
+
sort_entries(white,len2);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
i1=i2=0;
|
|
294
|
+
while ((i1<len1)&&(i2<len2))
|
|
295
|
+
{
|
|
296
|
+
#ifdef LIBRARY_DEBUG
|
|
297
|
+
print_debug(STDOUT,debug_buf,"STEP=%u I1=%d I2=%d\n",step++,i1,i2);
|
|
298
|
+
#endif
|
|
299
|
+
#ifdef LIBRARY_DEBUG_FULL
|
|
300
|
+
print_addresses(STDOUT,addr,len1,NULL,0);
|
|
301
|
+
#endif
|
|
302
|
+
|
|
303
|
+
supermask=TONETMASK(addr[i1].prefix)&TONETMASK(white[i2].prefix);
|
|
304
|
+
|
|
305
|
+
if ((addr[i1].prefix<=32)&&(addr[i1].network&supermask)==(white[i2].network&supermask))
|
|
306
|
+
{
|
|
307
|
+
#ifdef LIBRARY_DEBUG
|
|
308
|
+
print_debug(STDOUT,debug_buf,"CONFLICT\n");
|
|
309
|
+
print_address(STDOUT,addr[i1].network,addr[i1].prefix);
|
|
310
|
+
print_address(STDOUT,white[i2].network,white[i2].prefix);
|
|
311
|
+
#endif
|
|
312
|
+
if (addr[i1].prefix<white[i2].prefix)
|
|
313
|
+
{
|
|
314
|
+
/*we have to expand the network*/
|
|
315
|
+
|
|
316
|
+
/*invalidate all addr[i1] subnetworks */
|
|
317
|
+
invalid=i1+1;
|
|
318
|
+
while ((invalid<len1)&&(addr[invalid].network&supermask)==(white[i2].network&supermask))
|
|
319
|
+
{
|
|
320
|
+
/*address is already present in the expanded network, just drop it*/
|
|
321
|
+
#ifdef LIBRARY_DEBUG
|
|
322
|
+
print_debug(STDOUT,debug_buf,"INVALIDATING ");
|
|
323
|
+
print_address(STDOUT,addr[invalid].network,addr[invalid].prefix);
|
|
324
|
+
#endif
|
|
325
|
+
addr[invalid].prefix=INVALID_PREFIX;
|
|
326
|
+
|
|
327
|
+
invalid++;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
invalid-=i1+1; /*invalid represents the number of invalidated positions*/
|
|
331
|
+
|
|
332
|
+
#ifdef LIBRARY_DEBUG
|
|
333
|
+
print_debug(STDOUT,debug_buf,"INVALID %u LEN1 %u\n",invalid,len1);
|
|
334
|
+
#endif
|
|
335
|
+
|
|
336
|
+
tmp=i2;
|
|
337
|
+
i2+=1;
|
|
338
|
+
while ( (i2<len2) && ((addr[i1].network&supermask)==(white[i2].network&supermask)) )
|
|
339
|
+
{
|
|
340
|
+
i2++;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
#ifdef LIBRARY_DEBUG
|
|
344
|
+
print_debug(STDOUT,debug_buf,"EXPAND expanded_index %u whitelist elements: %u num expand %d\n",expanded_index,i2-tmp,white[tmp].prefix-addr[i1].prefix);
|
|
345
|
+
#endif
|
|
346
|
+
|
|
347
|
+
tmp_entry.network=addr[i1].network;
|
|
348
|
+
tmp_entry.prefix=addr[i1].prefix;
|
|
349
|
+
|
|
350
|
+
addr[i1].prefix=EXPANDED_PREFIX+white[tmp].prefix-addr[i1].prefix;
|
|
351
|
+
addr[i1].network=expanded_index;
|
|
352
|
+
/* expanded positions are clean and optimized */
|
|
353
|
+
expand(expanded_list,tmp_entry,&(white[tmp]),i2-tmp,white[tmp].prefix-tmp_entry.prefix,&expanded_index,size_expanded);
|
|
354
|
+
|
|
355
|
+
i1+=invalid+1;
|
|
356
|
+
|
|
357
|
+
#ifdef LIBRARY_DEBUG
|
|
358
|
+
print_debug(STDOUT,debug_buf,"END MAIN EXPAND expanded_index %u i1: %u i2: %u\n",expanded_index,i1,i2);
|
|
359
|
+
#endif
|
|
360
|
+
|
|
361
|
+
}
|
|
362
|
+
else
|
|
363
|
+
{
|
|
364
|
+
/*just invalidating entry i1*/
|
|
365
|
+
#ifdef LIBRARY_DEBUG
|
|
366
|
+
printf ("INVALIDATING ");
|
|
367
|
+
print_address(STDOUT,addr[i1].network,addr[i1].prefix);
|
|
368
|
+
#endif
|
|
369
|
+
addr[i1].prefix=INVALID_PREFIX;
|
|
370
|
+
i1++;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
}
|
|
374
|
+
else if ((addr[i1].prefix==INVALID_PREFIX)||(addr[i1].network&supermask)<=(white[i2].network&supermask))
|
|
375
|
+
{
|
|
376
|
+
i1++;
|
|
377
|
+
}
|
|
378
|
+
else
|
|
379
|
+
{
|
|
380
|
+
i2++;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
#ifdef LIBRARY_DEBUG
|
|
384
|
+
print_debug(STDOUT,debug_buf,"END apply_whitelist\n");
|
|
385
|
+
#endif
|
|
386
|
+
return expanded_index;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/*
|
|
390
|
+
Please see cidrmerge.h
|
|
391
|
+
*/
|
|
392
|
+
unsigned int optimize(struct entry *addr,unsigned int len,int do_sort)
|
|
393
|
+
{
|
|
394
|
+
unsigned int i,cur;
|
|
395
|
+
unsigned int tmp_net;
|
|
396
|
+
#ifdef LIBRARY_DEBUG
|
|
397
|
+
char debug_buf[MAXLINE];
|
|
398
|
+
unsigned int step=0;
|
|
399
|
+
|
|
400
|
+
print_debug(STDOUT,debug_buf,"START optimize\n");
|
|
401
|
+
#endif
|
|
402
|
+
|
|
403
|
+
i=0; /*pointer to last valid position*/
|
|
404
|
+
cur=1; /*pointer to next addr to analize*/
|
|
405
|
+
|
|
406
|
+
if (len <= 1)
|
|
407
|
+
{
|
|
408
|
+
/* empty or sigle element array is optimized by definition.*/
|
|
409
|
+
return len;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (do_sort)
|
|
413
|
+
{
|
|
414
|
+
sort_entries(addr,len);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/*Find first valid address and move it to first position*/
|
|
418
|
+
while ((addr[0].prefix==INVALID_PREFIX) && (cur<len))
|
|
419
|
+
{
|
|
420
|
+
#ifdef LIBRARY_DEBUG
|
|
421
|
+
printf ("SEARCH FIRST I: %d CUR: %d\n",i,cur);
|
|
422
|
+
#endif
|
|
423
|
+
if (addr[cur].prefix!=INVALID_PREFIX)
|
|
424
|
+
{
|
|
425
|
+
addr[0].network=addr[cur].network;
|
|
426
|
+
addr[0].prefix=addr[cur].prefix;
|
|
427
|
+
addr[cur].prefix=INVALID_PREFIX;
|
|
428
|
+
}
|
|
429
|
+
cur++;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
while (cur<len)
|
|
433
|
+
{
|
|
434
|
+
#ifdef LIBRARY_DEBUG
|
|
435
|
+
printf ("STEP: %u I: %d CUR: %d\n",step++,i,cur);
|
|
436
|
+
#endif
|
|
437
|
+
#ifdef LIBRARY_DEBUG_FULL
|
|
438
|
+
print_addresses(STDOUT,addr,len,NULL,0);
|
|
439
|
+
#endif
|
|
440
|
+
|
|
441
|
+
/*check for expanded networks, they can never conflicts*/
|
|
442
|
+
if (addr[cur].prefix>=EXPANDED_PREFIX)
|
|
443
|
+
{
|
|
444
|
+
#ifdef LIBRARY_DEBUG
|
|
445
|
+
printf ("COPY EXPANDED I: %d CUR: %d\n",i,cur);
|
|
446
|
+
#endif
|
|
447
|
+
i++;
|
|
448
|
+
addr[i].network=addr[cur].network;
|
|
449
|
+
addr[i].prefix=addr[cur].prefix;
|
|
450
|
+
cur++;
|
|
451
|
+
while ((addr[i].prefix>=EXPANDED_PREFIX) && (cur<len))
|
|
452
|
+
{
|
|
453
|
+
#ifdef LIBRARY_DEBUG
|
|
454
|
+
printf ("COPY ADDR[CUR] FOR EXPANDED I: %d CUR: %d\n",i,cur);
|
|
455
|
+
#endif
|
|
456
|
+
if (addr[cur].prefix!=INVALID_PREFIX)
|
|
457
|
+
{
|
|
458
|
+
i++;
|
|
459
|
+
if (cur != i)
|
|
460
|
+
{
|
|
461
|
+
addr[i].network=addr[cur].network;
|
|
462
|
+
addr[i].prefix=addr[cur].prefix;
|
|
463
|
+
addr[cur].prefix=INVALID_PREFIX;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
cur++;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
else
|
|
470
|
+
{
|
|
471
|
+
/*If this test will fail we just skip addr[cur]*/
|
|
472
|
+
if ((addr[cur].prefix<=32)&&((addr[cur].network&TONETMASK(addr[i].prefix))!=addr[i].network))
|
|
473
|
+
{
|
|
474
|
+
tmp_net=TONETMASK(addr[i].prefix-1);
|
|
475
|
+
|
|
476
|
+
if ( (addr[i].prefix==addr[cur].prefix) && ( (addr[i].network&tmp_net) == (addr[cur].network&tmp_net) ) )
|
|
477
|
+
{
|
|
478
|
+
#ifdef LIBRARY_DEBUG
|
|
479
|
+
printf ("COLLAPSE I: %d CUR: %d\n",i,cur);
|
|
480
|
+
#endif
|
|
481
|
+
|
|
482
|
+
if (i>0)
|
|
483
|
+
{
|
|
484
|
+
addr[cur].prefix=addr[i].prefix-1;
|
|
485
|
+
addr[cur].network&=tmp_net;
|
|
486
|
+
i--;
|
|
487
|
+
}
|
|
488
|
+
else
|
|
489
|
+
{
|
|
490
|
+
addr[i].prefix=addr[i].prefix-1;
|
|
491
|
+
addr[i].network&=tmp_net;
|
|
492
|
+
cur++;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
else
|
|
496
|
+
{
|
|
497
|
+
i++;
|
|
498
|
+
|
|
499
|
+
addr[i].network=addr[cur].network;
|
|
500
|
+
addr[i].prefix=addr[cur].prefix;
|
|
501
|
+
|
|
502
|
+
cur++;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
else
|
|
506
|
+
{
|
|
507
|
+
#ifdef LIBRARY_DEBUG
|
|
508
|
+
printf ("SKIP CUR: %d\n",cur);
|
|
509
|
+
#endif
|
|
510
|
+
|
|
511
|
+
cur++;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
#ifdef LIBRARY_DEBUG
|
|
517
|
+
print_debug(STDOUT,debug_buf,"END optimize\n");
|
|
518
|
+
#endif
|
|
519
|
+
|
|
520
|
+
if (addr[i].prefix!=INVALID_PREFIX)
|
|
521
|
+
{
|
|
522
|
+
return i+1;
|
|
523
|
+
}
|
|
524
|
+
else
|
|
525
|
+
{
|
|
526
|
+
return i;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/* $Id: optimized-sort.h,v 1.1 2008/06/07 22:30:24 depetrini Exp $
|
|
2
|
+
* Adopted from GNU glibc by Mjt.
|
|
3
|
+
* See stdlib/qsort.c in glibc */
|
|
4
|
+
|
|
5
|
+
/* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
|
|
6
|
+
This file is part of the GNU C Library.
|
|
7
|
+
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
|
|
8
|
+
|
|
9
|
+
The GNU C Library is free software; you can redistribute it and/or
|
|
10
|
+
modify it under the terms of the GNU Lesser General Public
|
|
11
|
+
License as published by the Free Software Foundation; either
|
|
12
|
+
version 2.1 of the License, or (at your option) any later version.
|
|
13
|
+
|
|
14
|
+
The GNU C Library is distributed in the hope that it will be useful,
|
|
15
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
17
|
+
Lesser General Public License for more details.
|
|
18
|
+
|
|
19
|
+
You should have received a copy of the GNU Lesser General Public
|
|
20
|
+
License along with the GNU C Library; if not, write to the Free
|
|
21
|
+
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
22
|
+
02111-1307 USA. */
|
|
23
|
+
|
|
24
|
+
/* in-line qsort implementation. Differs from traditional qsort() routine
|
|
25
|
+
* in that it is a macro, not a function, and instead of passing an address
|
|
26
|
+
* of a comparision routine to the function, it is possible to inline
|
|
27
|
+
* comparision routine, thus speed up sorting alot.
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* #include "iqsort.h"
|
|
31
|
+
* #define islt(a,b) (strcmp((*a),(*b))<0)
|
|
32
|
+
* char *arr[];
|
|
33
|
+
* int n;
|
|
34
|
+
* QSORT(char*, arr, n, islt);
|
|
35
|
+
*
|
|
36
|
+
* The "prototype" and 4 arguments are:
|
|
37
|
+
* QSORT(TYPE,BASE,NELT,ISLT)
|
|
38
|
+
* 1) type of each element, TYPE,
|
|
39
|
+
* 2) address of the beginning of the array, of type TYPE*,
|
|
40
|
+
* 3) number of elements in the array, and
|
|
41
|
+
* 4) comparision routine.
|
|
42
|
+
* Array pointer and number of elements are referenced only once.
|
|
43
|
+
* This is similar to a call
|
|
44
|
+
* qsort(BASE,NELT,sizeof(TYPE),ISLT)
|
|
45
|
+
* with the difference in last parameter.
|
|
46
|
+
* Note the islt macro/routine (it receives pointers to two elements):
|
|
47
|
+
* the only condition of interest is whenever one element is less than
|
|
48
|
+
* another, no other conditions (greather than, equal to etc) are tested.
|
|
49
|
+
* So, for example, to define integer sort, use:
|
|
50
|
+
* #define islt(a,b) ((*a)<(*b))
|
|
51
|
+
* QSORT(int, arr, n, islt)
|
|
52
|
+
*
|
|
53
|
+
* The macro could be used to implement a sorting function (see examples
|
|
54
|
+
* below), or to implement the sorting algorithm inline. That is, either
|
|
55
|
+
* create a sorting function and use it whenever you want to sort something,
|
|
56
|
+
* or use QSORT() macro directly instead a call to such routine. Note that
|
|
57
|
+
* the macro expands to quite some code (compiled size of int qsort on x86
|
|
58
|
+
* is about 700..800 bytes).
|
|
59
|
+
*
|
|
60
|
+
* Using this macro directly it isn't possible to implement traditional
|
|
61
|
+
* qsort() routine, because the macro assumes sizeof(element) == sizeof(TYPE),
|
|
62
|
+
* while qsort() allows element size to be different.
|
|
63
|
+
*
|
|
64
|
+
* Several ready-to-use examples:
|
|
65
|
+
*
|
|
66
|
+
* Sorting array of integers:
|
|
67
|
+
* void int_qsort(int *arr, unsigned n) {
|
|
68
|
+
* #define int_lt(a,b) ((*a)<(*b))
|
|
69
|
+
* QSORT(int, arr, n, int_lt);
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* Sorting array of string pointers:
|
|
73
|
+
* void str_qsort(char *arr[], unsigned n) {
|
|
74
|
+
* #define str_lt(a,b) (strcmp((*a),(*b)) < 0)
|
|
75
|
+
* QSORT(char*, arr, n, str_lt);
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* Sorting array of structures:
|
|
79
|
+
*
|
|
80
|
+
* struct elt {
|
|
81
|
+
* int key;
|
|
82
|
+
* ...
|
|
83
|
+
* };
|
|
84
|
+
* void elt_qsort(struct elt *arr, unsigned n) {
|
|
85
|
+
* #define elt_lt(a,b) ((a)->key < (b)->key)
|
|
86
|
+
* QSORT(struct elt, arr, n, elt_lt);
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* And so on.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/* Swap two items pointed to by A and B using temporary buffer t. */
|
|
93
|
+
#define _QSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t)))
|
|
94
|
+
|
|
95
|
+
/* Discontinue quicksort algorithm when partition gets below this size.
|
|
96
|
+
This particular magic number was chosen to work best on a Sun 4/260. */
|
|
97
|
+
#define _QSORT_MAX_THRESH 4
|
|
98
|
+
|
|
99
|
+
/* Stack node declarations used to store unfulfilled partition obligations
|
|
100
|
+
* (inlined in QSORT).
|
|
101
|
+
typedef struct {
|
|
102
|
+
QSORT_TYPE *_lo, *_hi;
|
|
103
|
+
} qsort_stack_node;
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
|
107
|
+
/* The stack needs log (total_elements) entries (we could even subtract
|
|
108
|
+
log(MAX_THRESH)). Since total_elements has type unsigned, we get as
|
|
109
|
+
upper bound for log (total_elements):
|
|
110
|
+
bits per byte (CHAR_BIT) * sizeof(unsigned). */
|
|
111
|
+
#define _QSORT_STACK_SIZE (8 * sizeof(unsigned))
|
|
112
|
+
#define _QSORT_PUSH(top, low, high) \
|
|
113
|
+
(((top->_lo = (low)), (top->_hi = (high)), ++top))
|
|
114
|
+
#define _QSORT_POP(low, high, top) \
|
|
115
|
+
((--top, (low = top->_lo), (high = top->_hi)))
|
|
116
|
+
#define _QSORT_STACK_NOT_EMPTY (_stack < _top)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/* Order size using quicksort. This implementation incorporates
|
|
120
|
+
four optimizations discussed in Sedgewick:
|
|
121
|
+
|
|
122
|
+
1. Non-recursive, using an explicit stack of pointer that store the
|
|
123
|
+
next array partition to sort. To save time, this maximum amount
|
|
124
|
+
of space required to store an array of SIZE_MAX is allocated on the
|
|
125
|
+
stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
|
|
126
|
+
only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
|
|
127
|
+
Pretty cheap, actually.
|
|
128
|
+
|
|
129
|
+
2. Chose the pivot element using a median-of-three decision tree.
|
|
130
|
+
This reduces the probability of selecting a bad pivot value and
|
|
131
|
+
eliminates certain extraneous comparisons.
|
|
132
|
+
|
|
133
|
+
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
|
134
|
+
insertion sort to order the MAX_THRESH items within each partition.
|
|
135
|
+
This is a big win, since insertion sort is faster for small, mostly
|
|
136
|
+
sorted array segments.
|
|
137
|
+
|
|
138
|
+
4. The larger of the two sub-partitions is always pushed onto the
|
|
139
|
+
stack first, with the algorithm then concentrating on the
|
|
140
|
+
smaller partition. This *guarantees* no more than log (total_elems)
|
|
141
|
+
stack size is needed (actually O(1) in this case)! */
|
|
142
|
+
|
|
143
|
+
/* The main code starts here... */
|
|
144
|
+
#define QSORT(QSORT_TYPE,QSORT_BASE,QSORT_NELT,QSORT_LT) \
|
|
145
|
+
{ \
|
|
146
|
+
QSORT_TYPE *const _base = (QSORT_BASE); \
|
|
147
|
+
const unsigned _elems = (QSORT_NELT); \
|
|
148
|
+
QSORT_TYPE _hold; \
|
|
149
|
+
\
|
|
150
|
+
/* Don't declare two variables of type QSORT_TYPE in a single \
|
|
151
|
+
* statement: eg `TYPE a, b;', in case if TYPE is a pointer, \
|
|
152
|
+
* expands to `type* a, b;' wich isn't what we want. \
|
|
153
|
+
*/ \
|
|
154
|
+
\
|
|
155
|
+
if (_elems > _QSORT_MAX_THRESH) { \
|
|
156
|
+
QSORT_TYPE *_lo = _base; \
|
|
157
|
+
QSORT_TYPE *_hi = _lo + _elems - 1; \
|
|
158
|
+
struct { \
|
|
159
|
+
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
|
160
|
+
} _stack[_QSORT_STACK_SIZE], *_top = _stack + 1; \
|
|
161
|
+
\
|
|
162
|
+
while (_QSORT_STACK_NOT_EMPTY) { \
|
|
163
|
+
QSORT_TYPE *_left_ptr; QSORT_TYPE *_right_ptr; \
|
|
164
|
+
\
|
|
165
|
+
/* Select median value from among LO, MID, and HI. Rearrange \
|
|
166
|
+
LO and HI so the three values are sorted. This lowers the \
|
|
167
|
+
probability of picking a pathological pivot value and \
|
|
168
|
+
skips a comparison for both the LEFT_PTR and RIGHT_PTR in \
|
|
169
|
+
the while loops. */ \
|
|
170
|
+
\
|
|
171
|
+
QSORT_TYPE *_mid = _lo + ((_hi - _lo) >> 1); \
|
|
172
|
+
\
|
|
173
|
+
if (QSORT_LT (_mid, _lo)) \
|
|
174
|
+
_QSORT_SWAP (_mid, _lo, _hold); \
|
|
175
|
+
if (QSORT_LT (_hi, _mid)) \
|
|
176
|
+
_QSORT_SWAP (_mid, _hi, _hold); \
|
|
177
|
+
else \
|
|
178
|
+
goto _jump_over; \
|
|
179
|
+
if (QSORT_LT (_mid, _lo)) \
|
|
180
|
+
_QSORT_SWAP (_mid, _lo, _hold); \
|
|
181
|
+
_jump_over:; \
|
|
182
|
+
\
|
|
183
|
+
_left_ptr = _lo + 1; \
|
|
184
|
+
_right_ptr = _hi - 1; \
|
|
185
|
+
\
|
|
186
|
+
/* Here's the famous ``collapse the walls'' section of quicksort. \
|
|
187
|
+
Gotta like those tight inner loops! They are the main reason \
|
|
188
|
+
that this algorithm runs much faster than others. */ \
|
|
189
|
+
do { \
|
|
190
|
+
while (QSORT_LT (_left_ptr, _mid)) \
|
|
191
|
+
++_left_ptr; \
|
|
192
|
+
\
|
|
193
|
+
while (QSORT_LT (_mid, _right_ptr)) \
|
|
194
|
+
--_right_ptr; \
|
|
195
|
+
\
|
|
196
|
+
if (_left_ptr < _right_ptr) { \
|
|
197
|
+
_QSORT_SWAP (_left_ptr, _right_ptr, _hold); \
|
|
198
|
+
if (_mid == _left_ptr) \
|
|
199
|
+
_mid = _right_ptr; \
|
|
200
|
+
else if (_mid == _right_ptr) \
|
|
201
|
+
_mid = _left_ptr; \
|
|
202
|
+
++_left_ptr; \
|
|
203
|
+
--_right_ptr; \
|
|
204
|
+
} \
|
|
205
|
+
else if (_left_ptr == _right_ptr) { \
|
|
206
|
+
++_left_ptr; \
|
|
207
|
+
--_right_ptr; \
|
|
208
|
+
break; \
|
|
209
|
+
} \
|
|
210
|
+
} while (_left_ptr <= _right_ptr); \
|
|
211
|
+
\
|
|
212
|
+
/* Set up pointers for next iteration. First determine whether \
|
|
213
|
+
left and right partitions are below the threshold size. If so, \
|
|
214
|
+
ignore one or both. Otherwise, push the larger partition's \
|
|
215
|
+
bounds on the stack and continue sorting the smaller one. */ \
|
|
216
|
+
\
|
|
217
|
+
if (_right_ptr - _lo <= _QSORT_MAX_THRESH) { \
|
|
218
|
+
if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
|
219
|
+
/* Ignore both small partitions. */ \
|
|
220
|
+
_QSORT_POP (_lo, _hi, _top); \
|
|
221
|
+
else \
|
|
222
|
+
/* Ignore small left partition. */ \
|
|
223
|
+
_lo = _left_ptr; \
|
|
224
|
+
} \
|
|
225
|
+
else if (_hi - _left_ptr <= _QSORT_MAX_THRESH) \
|
|
226
|
+
/* Ignore small right partition. */ \
|
|
227
|
+
_hi = _right_ptr; \
|
|
228
|
+
else if (_right_ptr - _lo > _hi - _left_ptr) { \
|
|
229
|
+
/* Push larger left partition indices. */ \
|
|
230
|
+
_QSORT_PUSH (_top, _lo, _right_ptr); \
|
|
231
|
+
_lo = _left_ptr; \
|
|
232
|
+
} \
|
|
233
|
+
else { \
|
|
234
|
+
/* Push larger right partition indices. */ \
|
|
235
|
+
_QSORT_PUSH (_top, _left_ptr, _hi); \
|
|
236
|
+
_hi = _right_ptr; \
|
|
237
|
+
} \
|
|
238
|
+
} \
|
|
239
|
+
} \
|
|
240
|
+
\
|
|
241
|
+
/* Once the BASE array is partially sorted by quicksort the rest \
|
|
242
|
+
is completely sorted using insertion sort, since this is efficient \
|
|
243
|
+
for partitions below MAX_THRESH size. BASE points to the \
|
|
244
|
+
beginning of the array to sort, and END_PTR points at the very \
|
|
245
|
+
last element in the array (*not* one beyond it!). */ \
|
|
246
|
+
\
|
|
247
|
+
{ \
|
|
248
|
+
QSORT_TYPE *const _end_ptr = _base + _elems - 1; \
|
|
249
|
+
QSORT_TYPE *_tmp_ptr = _base; \
|
|
250
|
+
register QSORT_TYPE *_run_ptr; \
|
|
251
|
+
QSORT_TYPE *_thresh; \
|
|
252
|
+
\
|
|
253
|
+
_thresh = _base + _QSORT_MAX_THRESH; \
|
|
254
|
+
if (_thresh > _end_ptr) \
|
|
255
|
+
_thresh = _end_ptr; \
|
|
256
|
+
\
|
|
257
|
+
/* Find smallest element in first threshold and place it at the \
|
|
258
|
+
array's beginning. This is the smallest array element, \
|
|
259
|
+
and the operation speeds up insertion sort's inner loop. */ \
|
|
260
|
+
\
|
|
261
|
+
for (_run_ptr = _tmp_ptr + 1; _run_ptr <= _thresh; ++_run_ptr) \
|
|
262
|
+
if (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
|
263
|
+
_tmp_ptr = _run_ptr; \
|
|
264
|
+
\
|
|
265
|
+
if (_tmp_ptr != _base) \
|
|
266
|
+
_QSORT_SWAP (_tmp_ptr, _base, _hold); \
|
|
267
|
+
\
|
|
268
|
+
/* Insertion sort, running from left-hand-side \
|
|
269
|
+
* up to right-hand-side. */ \
|
|
270
|
+
\
|
|
271
|
+
_run_ptr = _base + 1; \
|
|
272
|
+
while (++_run_ptr <= _end_ptr) { \
|
|
273
|
+
_tmp_ptr = _run_ptr - 1; \
|
|
274
|
+
while (QSORT_LT (_run_ptr, _tmp_ptr)) \
|
|
275
|
+
--_tmp_ptr; \
|
|
276
|
+
\
|
|
277
|
+
++_tmp_ptr; \
|
|
278
|
+
if (_tmp_ptr != _run_ptr) { \
|
|
279
|
+
QSORT_TYPE *_trav = _run_ptr + 1; \
|
|
280
|
+
while (--_trav >= _run_ptr) { \
|
|
281
|
+
QSORT_TYPE *_hi; QSORT_TYPE *_lo; \
|
|
282
|
+
_hold = *_trav; \
|
|
283
|
+
\
|
|
284
|
+
for (_hi = _lo = _trav; --_lo >= _tmp_ptr; _hi = _lo) \
|
|
285
|
+
*_hi = *_lo; \
|
|
286
|
+
*_hi = _hold; \
|
|
287
|
+
} \
|
|
288
|
+
} \
|
|
289
|
+
} \
|
|
290
|
+
} \
|
|
291
|
+
\
|
|
292
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'ffi'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
SHARED_LIBRARY_FOLDER = File.join(File.dirname(__FILE__), '../../ffi')
|
|
5
|
+
SHARED_LIBRARY_NAME = File.join(SHARED_LIBRARY_FOLDER, 'libcidrmerge.so')
|
|
6
|
+
|
|
7
|
+
unless File.exist?(SHARED_LIBRARY_NAME)
|
|
8
|
+
FileUtils.cd(SHARED_LIBRARY_FOLDER)
|
|
9
|
+
%x{make}
|
|
10
|
+
fail "compile shared library fail, try to compile it by manual" if $?.exitstatus < 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module Cidrmergerb
|
|
14
|
+
class Ext
|
|
15
|
+
extend FFI::Library
|
|
16
|
+
ffi_lib SHARED_LIBRARY_NAME
|
|
17
|
+
|
|
18
|
+
class Entry < FFI::ManagedStruct
|
|
19
|
+
layout :network => :uint,
|
|
20
|
+
:prefix => :uchar
|
|
21
|
+
|
|
22
|
+
def self.release(ptr)
|
|
23
|
+
Cidrmergerb::Ext.free_object(ptr)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attach_function :optimize, [ :pointer, :uint, :int ], :uint
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/cidrmergerb.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require "cidrmergerb/version"
|
|
2
|
+
require 'cidrmergerb/ext'
|
|
3
|
+
require 'ipaddr'
|
|
4
|
+
require 'ffi'
|
|
5
|
+
|
|
6
|
+
module Cidrmergerb
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def optimize(cidrs)
|
|
10
|
+
pointer = build_pointer_to_cidrs(cidrs)
|
|
11
|
+
optimize_length = Cidrmergerb::Ext.optimize(pointer, cidrs.length, 1)
|
|
12
|
+
|
|
13
|
+
structs = wrap_with_struct(pointer, Cidrmergerb::Ext::Entry, optimize_length)
|
|
14
|
+
structs.map { |struct| strcut_to_cidr(struct) }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
def build_pointer_to_cidrs(cidrs)
|
|
19
|
+
cidrs.select! {|cidr| cidr_valid?(cidr) }
|
|
20
|
+
|
|
21
|
+
pointer = alloc_memory(Cidrmergerb::Ext::Entry, cidrs.length)
|
|
22
|
+
entries = wrap_with_struct(pointer, Cidrmergerb::Ext::Entry, cidrs.length)
|
|
23
|
+
|
|
24
|
+
cidrs.each_with_index do |cidr, index|
|
|
25
|
+
ip, netmask = cidr.split('/')
|
|
26
|
+
entries[index][:network] = IPAddr.new(ip).to_i
|
|
27
|
+
entries[index][:prefix] = netmask.to_i
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
pointer
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def cidr_valid?(cidr)
|
|
34
|
+
ip, netmask = cidr.split('/')
|
|
35
|
+
ipaddr = IPAddr.new(ip)
|
|
36
|
+
ipaddr && netmask.to_i.between?(1, 32)
|
|
37
|
+
rescue IPAddr::InvalidAddressError => e
|
|
38
|
+
false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def remove_invalid(cidrs)
|
|
42
|
+
cidrs.map do |cidr|
|
|
43
|
+
ip, netmask = cidr.split('/')
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def alloc_memory(type, size)
|
|
48
|
+
FFI::MemoryPointer.new type, size, false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def wrap_with_struct(pointer, struct_type, length)
|
|
52
|
+
length.times.collect do |i|
|
|
53
|
+
struct_type.new(pointer + i * struct_type.size)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def strcut_to_cidr(struct)
|
|
58
|
+
"#{IPAddr.new(struct[:network], Socket::AF_INET).to_s}/#{struct[:prefix]}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cidrmergerb
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Newell Zhu
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-06-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: ffi
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.9'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 1.9.10
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.9'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 1.9.10
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: bundler
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.11'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.11'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rake
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '10.0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '10.0'
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: minitest
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '5.0'
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '5.0'
|
|
75
|
+
description: CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.
|
|
76
|
+
email:
|
|
77
|
+
- newell.zhu@kingaxis.com
|
|
78
|
+
executables: []
|
|
79
|
+
extensions: []
|
|
80
|
+
extra_rdoc_files: []
|
|
81
|
+
files:
|
|
82
|
+
- ".gitignore"
|
|
83
|
+
- ".travis.yml"
|
|
84
|
+
- Gemfile
|
|
85
|
+
- README.md
|
|
86
|
+
- Rakefile
|
|
87
|
+
- bin/console
|
|
88
|
+
- bin/setup
|
|
89
|
+
- cidrmergerb.gemspec
|
|
90
|
+
- ffi/Makefile
|
|
91
|
+
- ffi/cidrmerge.h
|
|
92
|
+
- ffi/libcidrmerge.c
|
|
93
|
+
- ffi/optimized-sort.h
|
|
94
|
+
- lib/cidrmergerb.rb
|
|
95
|
+
- lib/cidrmergerb/ext.rb
|
|
96
|
+
- lib/cidrmergerb/version.rb
|
|
97
|
+
homepage: https://github.com/kingaxis/cidrmergerb
|
|
98
|
+
licenses: []
|
|
99
|
+
metadata: {}
|
|
100
|
+
post_install_message:
|
|
101
|
+
rdoc_options: []
|
|
102
|
+
require_paths:
|
|
103
|
+
- lib
|
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - ">="
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '0'
|
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '0'
|
|
114
|
+
requirements: []
|
|
115
|
+
rubyforge_project:
|
|
116
|
+
rubygems_version: 2.5.1
|
|
117
|
+
signing_key:
|
|
118
|
+
specification_version: 4
|
|
119
|
+
summary: CIDR Merge toolkit -- Wrapping for Daniele's CIDR Optimization library.
|
|
120
|
+
test_files: []
|