subnets 1.0.0pre → 1.0.0pre1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ca7677ed446bf92038930c57e31d26878b05fe6dc7c6fa4cf5f731ec58a5340
4
- data.tar.gz: 3d82804a72f2181c5036d69aad617c927bac2eb64ee4fe496d822ca6a006a043
3
+ metadata.gz: 54f0c79b3c0859e0d9cd2758276652d48fd0ceeece739695691b76c5cb8d01a7
4
+ data.tar.gz: 69b64044d769ede44735081a0411b088cf3016bf6a4a732238c5996c105e5e19
5
5
  SHA512:
6
- metadata.gz: 1f152961d4118eac6bb2bfafb1f65bdc94ee971b6ff0215542790a446da7e3c3e09d35278dcbfbd8e918f5defad442dbf38d3cb067f39521a3e9fa67ae86d853
7
- data.tar.gz: 2655d78b2dbf09510a28cdabaea00c572c5038889b7724c34fa96e2f1bb72319831c468b57caf39055ddae8d106ff91a61e7695d9dd3762d6fbe92c7f7ac6f4b
6
+ metadata.gz: ceebcd95e1fb22ee86acf2c4eb606c3deda2a97c04a7f57d0e97f5493974441855f3e7a04e2525e6b4ff1a88f6508df29b548bebcfca36dceb0ee4384ab76f82
7
+ data.tar.gz: ac0e808b3e42227f53881eed50a807e136a0b2602f0402bda120a42f9cc78d16ce64029cd2d5aa2e6fd9456dfb797411fe5496c6fda5321528e4cd39a828e591
data/README.md CHANGED
@@ -27,11 +27,11 @@ better. Plotted on logscale. (Ruby 2.5.0p0, 2.5 GHz Intel Core i7).
27
27
  ```
28
28
  $ bundle exec rake benchmark TEST=test/private_networks_benchmark
29
29
 
30
- ipaddr : 46.25us/ip ██████████████████████████████████▋
31
- ipaddress : 63.88us/ip ██████████████████████████████████████▏
32
- netaddr : 31.03us/ip ██████████████████████████████▎
33
- *subnets : 4.19us/ip ████████▏
34
- rack (regexp) : 5.25us/ip ██████████▋
30
+ ipaddr : 46.25μs/ip ██████████████████████████████████▋
31
+ ipaddress : 63.88μs/ip ██████████████████████████████████████▏
32
+ netaddr : 31.03μs/ip ██████████████████████████████▎
33
+ *subnets : 4.19μs/ip ████████▏
34
+ rack (regexp) : 5.25μs/ip ██████████▋
35
35
  ' ' ' ' '
36
36
  2 5 10 20 50
37
37
  ```
data/ext/subnets/ext.c CHANGED
@@ -318,54 +318,45 @@ method_ip4_band(VALUE self, VALUE other) {
318
318
 
319
319
  VALUE
320
320
  method_ip6_not(VALUE self) {
321
- ip6_t *ip, not;
321
+ ip6_t *ip;
322
322
  Data_Get_Struct(self, ip6_t, ip);
323
- for (int i=0; i<8; i++) {
324
- not.x[i] = ~(ip->x[i]);
325
- }
326
- return ip6_new(IP6, not);
323
+ return ip6_new(IP6, ip6_not(*ip));
327
324
  }
328
325
 
329
326
  VALUE
330
327
  method_ip6_bor(VALUE self, VALUE other) {
331
- ip6_t *a, *b, bor;
328
+ ip6_t *a, *b;
332
329
 
333
330
  assert_kind_of(other, IP6);
334
331
 
335
332
  Data_Get_Struct(self, ip6_t, a);
336
333
  Data_Get_Struct(other, ip6_t, b);
337
- for (int i=0; i<8; i++) {
338
- bor.x[i] = a->x[i] | b->x[i];
339
- }
340
- return ip6_new(IP6, bor);
334
+
335
+ return ip6_new(IP6, ip6_bor(*a, *b));
341
336
  }
342
337
 
343
338
  VALUE
344
339
  method_ip6_xor(VALUE self, VALUE other) {
345
- ip6_t *a, *b, xor;
340
+ ip6_t *a, *b;
346
341
 
347
342
  assert_kind_of(other, IP6);
348
343
 
349
344
  Data_Get_Struct(self, ip6_t, a);
350
345
  Data_Get_Struct(other, ip6_t, b);
351
- for (int i=0; i<8; i++) {
352
- xor.x[i] = a->x[i] ^ b->x[i];
353
- }
354
- return ip6_new(IP6, xor);
346
+
347
+ return ip6_new(IP6, ip6_xor(*a, *b));
355
348
  }
356
349
 
357
350
  VALUE
358
351
  method_ip6_band(VALUE self, VALUE other) {
359
- ip6_t *a, *b, band;
352
+ ip6_t *a, *b;
360
353
 
361
354
  assert_kind_of(other, IP6);
362
355
 
363
356
  Data_Get_Struct(self, ip6_t, a);
364
357
  Data_Get_Struct(other, ip6_t, b);
365
- for (int i=0; i<8; i++) {
366
- band.x[i] = a->x[i] & b->x[i];
367
- }
368
- return ip6_new(IP6, band);
358
+
359
+ return ip6_new(IP6, ip6_band(*a, *b));
369
360
  }
370
361
 
371
362
  /**
@@ -546,6 +537,33 @@ method_net6_to_s(VALUE self) {
546
537
  return rb_str_new2(buf);
547
538
  }
548
539
 
540
+ VALUE
541
+ method_ip4_to_i(VALUE self) {
542
+ ip4_t *ip;
543
+ Data_Get_Struct(self, ip4_t, ip);
544
+ return RB_UINT2NUM(*ip);
545
+ }
546
+
547
+ VALUE
548
+ method_ip6_to_i(VALUE self) {
549
+ VALUE ret;
550
+ ip6_t *ip;
551
+ Data_Get_Struct(self, ip6_t, ip);
552
+
553
+ ID lshift = rb_intern("<<");
554
+ ID plus = rb_intern("+");
555
+
556
+ ret = RB_INT2NUM(0);
557
+
558
+ for (int i=0; i<8; i++) {
559
+ VALUE hextet = RB_UINT2NUM(ip->x[i]);
560
+ VALUE inc = rb_funcall(hextet, lshift, 1, RB_INT2NUM(16*(7-i)));
561
+ ret = rb_funcall(ret, plus, 1, inc);
562
+ }
563
+
564
+ return ret;
565
+ }
566
+
549
567
  /**
550
568
  * @return [Boolean]
551
569
  */
@@ -600,10 +618,7 @@ method_ip6_eql_p(VALUE self, VALUE other) {
600
618
  Data_Get_Struct(self, ip6_t, a);
601
619
  Data_Get_Struct(other, ip6_t, b);
602
620
 
603
- for (int i=0; i<8; i++) {
604
- if (a->x[i] != b->x[i]) return Qfalse;
605
- }
606
- return Qtrue;
621
+ return ip6_eql_p(*a, *b) ? Qtrue : Qfalse;
607
622
  }
608
623
 
609
624
  /**
@@ -745,34 +760,86 @@ method_net6_hextets(VALUE self) {
745
760
  return hextets;
746
761
  }
747
762
 
763
+ /**
764
+ * @return [Subnets::Net4] the smallest subnet that includes all of
765
+ * the subnets in +nets+
766
+ *
767
+ * @param nets [Array<Subnets::Net4>]
768
+ */
748
769
  VALUE
749
770
  method_net4_summarize(VALUE class, VALUE nets) {
750
771
  net4_t result;
751
772
 
752
- result.address = mk_mask4(32);
753
- result.prefixlen = 32;
754
- result.mask = mk_mask4(32);
755
-
756
773
  for (ssize_t i = 0; i < RARRAY_LEN(nets); i++) {
757
774
  VALUE rbnet = RARRAY_AREF(nets, i);
758
775
 
759
776
  assert_kind_of(rbnet, Net4);
760
777
 
761
- net4_t *net;
778
+ const net4_t *net;
762
779
  Data_Get_Struct(rbnet, net4_t, net);
763
780
 
764
- result.address &= (net->address & net->mask);
781
+ if (i == 0) {
782
+ result.address = (net->address & net->mask);
783
+ result.prefixlen = net->prefixlen;
784
+ result.mask = net->mask;
785
+ } else {
786
+ if (result.prefixlen > net->prefixlen) {
787
+ result.prefixlen = net->prefixlen;
788
+ result.mask = net->mask;
789
+ result.address &= result.mask;
790
+ }
765
791
 
766
- while (!net4_include_net4_p(result, *net)) {
767
- result.prefixlen -= 1;
768
- result.mask = mk_mask4(result.prefixlen);
769
- result.address &= result.mask;
792
+ while (result.address != (net->address & result.mask)) {
793
+ result.prefixlen -= 1;
794
+ result.mask = mk_mask4(result.prefixlen);
795
+ result.address &= result.mask;
796
+ }
770
797
  }
771
798
  }
772
799
 
773
800
  return net4_new(class, result);
774
801
  }
775
802
 
803
+ /**
804
+ * @return [Subnets::Net6] the smallest subnet that includes all of
805
+ * the subnets in +nets+
806
+ *
807
+ * @param nets [Array<Subnets::Net6>]
808
+ */
809
+ VALUE
810
+ method_net6_summarize(VALUE class, VALUE nets) {
811
+ net6_t result;
812
+
813
+ for (ssize_t i = 0; i < RARRAY_LEN(nets); i++) {
814
+ VALUE rbnet = RARRAY_AREF(nets, i);
815
+
816
+ assert_kind_of(rbnet, Net6);
817
+
818
+ net6_t *net;
819
+ Data_Get_Struct(rbnet, net6_t, net);
820
+
821
+ if (i == 0) {
822
+ result.address = ip6_band(net->address, net->mask);
823
+ result.prefixlen = net->prefixlen;
824
+ result.mask = net->mask;
825
+ } else {
826
+ if (result.prefixlen > net->prefixlen) {
827
+ result.prefixlen = net->prefixlen;
828
+ result.mask = net->mask;
829
+ result.address = ip6_band(result.address, result.mask);
830
+ }
831
+
832
+ while(!ip6_eql_p(result.address, ip6_band(net->address, result.mask))) {
833
+ result.prefixlen -= 1;
834
+ result.mask = mk_mask6(result.prefixlen);
835
+ result.address = ip6_band(result.address, result.mask);
836
+ }
837
+ }
838
+ }
839
+
840
+ return net6_new(class, result);
841
+ }
842
+
776
843
  /**
777
844
  * Try parsing +str+ as Net4, Net6, IP4, IP6.
778
845
  *
@@ -942,6 +1009,7 @@ void Init_Subnets() {
942
1009
  rb_define_alias(IP4, "eql?", "==");
943
1010
  rb_define_method(IP4, "hash", method_ip4_hash, 0);
944
1011
  rb_define_method(IP4, "to_s", method_ip4_to_s, 0);
1012
+ rb_define_method(IP4, "to_i", method_ip4_to_i, 0);
945
1013
 
946
1014
  rb_define_method(IP4, "~", method_ip4_not, 0);
947
1015
  rb_define_method(IP4, "|", method_ip4_bor, 1);
@@ -955,6 +1023,7 @@ void Init_Subnets() {
955
1023
  rb_define_alias(IP6, "eql?", "==");
956
1024
  rb_define_method(IP6, "hash", method_ip6_hash, 0);
957
1025
  rb_define_method(IP6, "to_s", method_ip6_to_s, 0);
1026
+ rb_define_method(IP6, "to_i", method_ip6_to_i, 0);
958
1027
  rb_define_method(IP6, "hextets", method_ip6_hextets, 0);
959
1028
 
960
1029
  rb_define_method(IP6, "~", method_ip6_not, 0);
@@ -988,6 +1057,7 @@ void Init_Subnets() {
988
1057
  rb_define_singleton_method(Net6, "parse", method_net6_parse, 1);
989
1058
  rb_define_singleton_method(Net6, "random", method_net6_random, -1);
990
1059
  rb_define_singleton_method(Net6, "new", method_net6_new, 2);
1060
+ rb_define_singleton_method(Net6, "summarize", method_net6_summarize, 1);
991
1061
  rb_define_method(Net6, "==", method_net6_eql_p, 1);
992
1062
  rb_define_alias(Net6, "eql?", "==");
993
1063
  rb_define_method(Net6, "hash", method_net6_hash, 0);
data/ext/subnets/ipaddr.c CHANGED
@@ -187,6 +187,50 @@ net6_snprint(net6_t net, char *str, size_t size) {
187
187
  return n0 + n1;
188
188
  }
189
189
 
190
+ int
191
+ ip6_eql_p(ip6_t a, ip6_t b) {
192
+ for (int i=0; i<8; i++) {
193
+ if (a.x[i] != b.x[i]) return 0;
194
+ }
195
+ return !0;
196
+ }
197
+
198
+ ip6_t
199
+ ip6_not(ip6_t ip) {
200
+ ip6_t not;
201
+ for (int i=0; i<8; i++) {
202
+ not.x[i] = ~(ip.x[i]);
203
+ }
204
+ return not;
205
+ }
206
+
207
+ ip6_t
208
+ ip6_band(ip6_t a, ip6_t b) {
209
+ ip6_t band;
210
+ for (int i=0; i<8; i++) {
211
+ band.x[i] = a.x[i] & b.x[i];
212
+ }
213
+ return band;
214
+ }
215
+
216
+ ip6_t
217
+ ip6_bor(ip6_t a, ip6_t b) {
218
+ ip6_t bor;
219
+ for (int i=0; i<8; i++) {
220
+ bor.x[i] = a.x[i] | b.x[i];
221
+ }
222
+ return bor;
223
+ }
224
+
225
+ ip6_t
226
+ ip6_xor(ip6_t a, ip6_t b) {
227
+ ip6_t xor;
228
+ for (int i=0; i<8; i++) {
229
+ xor.x[i] = a.x[i] ^ b.x[i];
230
+ }
231
+ return xor;
232
+ }
233
+
190
234
  int
191
235
  hexvalue(unsigned int c) {
192
236
  if (c-'0'<10) return c-'0';
data/ext/subnets/ipaddr.h CHANGED
@@ -102,4 +102,10 @@ size_t read_ip6_strict(const char *, ip6_t *);
102
102
  size_t read_net4_strict(const char *, net4_t *);
103
103
  size_t read_net6_strict(const char *, net6_t *);
104
104
 
105
+ int ip6_eql_p(ip6_t, ip6_t);
106
+ ip6_t ip6_not(ip6_t);
107
+ ip6_t ip6_band(ip6_t, ip6_t);
108
+ ip6_t ip6_bor(ip6_t, ip6_t);
109
+ ip6_t ip6_xor(ip6_t, ip6_t);
110
+
105
111
  #endif /* __IPADDR_H__ */
@@ -43,11 +43,11 @@ puts "# check if single IP is in the private IPv4 subnets"
43
43
  }.total
44
44
  count += 100
45
45
  end
46
- puts "%10.10s: checked %8d (%6d hits, %2d%%) in %2.2f for %7.2fus/ip" %
46
+ puts "%10.10s: checked %8d (%6d hits, %2d%%) in %2.2f for %7.2fμs/ip" %
47
47
  [check.name, count, hits, 100.0*hits/count, total, total/count*1e6]
48
48
 
49
49
  results[check.name] = total/count*1e6
50
50
  end
51
51
 
52
52
  puts
53
- plotbarslogscale(prefix: '%-15.15s: %5.2fus/ip ', width: 46, min: 2, max: 65, tics: [2,5,10,20,50], data: results)
53
+ plotbarslogscale(prefix: '%-15.15s: %5.2fμs/ip ', width: 46, min: 2, max: 65, tics: [2,5,10,20,50], data: results)
@@ -3,6 +3,7 @@ require 'test_helper'
3
3
  module Subnets
4
4
  class TestNet4 < Minitest::Test
5
5
  include EqlAndHash
6
+ include Summarize
6
7
 
7
8
  def klass
8
9
  Net4
@@ -70,5 +71,20 @@ module Subnets
70
71
  end
71
72
  end
72
73
  end
74
+
75
+ def test_summarize
76
+ data = {
77
+ '192.168.0.0/24' => ['192.168.0.0/25', '192.168.0.128/25'],
78
+ '10.0.0.0/8' => ['10.0.0.0/24', '10.250.2.3/19'],
79
+ }
80
+
81
+ data.each do |summ, nets|
82
+ summ = Subnets.parse(summ)
83
+ nets = nets.map(&Subnets.method(:parse))
84
+
85
+ assert_equal summ, Net4.summarize(nets)
86
+ assert_summarizes summ, nets
87
+ end
88
+ end
73
89
  end
74
90
  end
@@ -4,6 +4,7 @@ require 'ipaddr'
4
4
  module Subnets
5
5
  class TestNet6 < Minitest::Test
6
6
  include EqlAndHash
7
+ include Summarize
7
8
 
8
9
  # for EqlAndHash
9
10
  def klass
data/test/summarize.rb ADDED
@@ -0,0 +1,12 @@
1
+ module Summarize
2
+ def test_summarizing_net_includes_subnets
3
+ random = Random.new
4
+ start = Time.now
5
+ until Time.now - start > TIMED_TEST_DURATION
6
+ nets = (1..3).map{klass.random(random)}
7
+ summ = klass.summarize(nets)
8
+ assert_operator summ.prefixlen, :>=, 0, "summarized #{nets} to invalid #{summ}"
9
+ assert_summarizes klass.summarize(nets), nets
10
+ end
11
+ end
12
+ end
data/test/test_helper.rb CHANGED
@@ -18,6 +18,7 @@ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new,
18
18
  require 'subnets'
19
19
  require 'well_known_subnets'
20
20
  require 'eql_and_hash'
21
+ require 'summarize'
21
22
 
22
23
  TIMED_TEST_DURATION = (ENV['TIMED_TEST_DURATION'] || 1).to_i
23
24
 
@@ -28,3 +29,14 @@ end
28
29
  def refute_include(obj, val)
29
30
  refute obj.include?(val), "#{obj} should not include #{val}"
30
31
  end
32
+
33
+ def assert_summarizes(summ, nets)
34
+ bad = nil
35
+ nets.each do |net|
36
+ unless summ.include?(net)
37
+ bad = net
38
+ break
39
+ end
40
+ end
41
+ refute bad, "#{nets} not summarized by #{summ}: #{summ}.include?(#{bad}) was false"
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: subnets
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0pre
4
+ version: 1.0.0pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Mahoney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-12 00:00:00.000000000 Z
11
+ date: 2018-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -175,6 +175,7 @@ files:
175
175
  - test/subnets/net4_test.rb
176
176
  - test/subnets/net6_test.rb
177
177
  - test/subnets_test.rb
178
+ - test/summarize.rb
178
179
  - test/test_helper.rb
179
180
  - test/well_known_subnets.rb
180
181
  homepage: https://github.com/raisemarketplace/subnets