File Coverage

blib/lib/Tree/RB/XS.pm
Criterion Covered Total %
statement 52 54 96.3
branch 21 24 87.5
condition 19 34 55.8
subroutine 18 19 94.7
pod 5 5 100.0
total 115 136 84.5


line stmt bran cond sub pod time code
1             package Tree::RB::XS;
2             $Tree::RB::XS::VERSION = '0.20';
3             # VERSION
4             # ABSTRACT: Red/Black Tree and LRU Cache implemented in C
5              
6 13     13   3081438 use strict;
  13         49  
  13         558  
7 13     13   78 use warnings;
  13         33  
  13         762  
8 13     13   76 use Carp;
  13         24  
  13         937  
9 13     13   76 use Scalar::Util ();
  13         25  
  13         2225  
10             require XSLoader;
11             XSLoader::load('Tree::RB::XS', $Tree::RB::XS::VERSION);
12 13     13   70 use Exporter 'import';
  13         25  
  13         17036  
13             our @_key_types= qw( KEY_TYPE_ANY KEY_TYPE_INT KEY_TYPE_FLOAT KEY_TYPE_BSTR KEY_TYPE_USTR );
14             our @_cmp_enum= qw( CMP_PERL CMP_INT CMP_FLOAT CMP_MEMCMP CMP_STR CMP_UTF8 CMP_FOLDCASE CMP_NUMSPLIT CMP_NUMSPLIT_FOLDCASE );
15             *CMP_UTF8= *CMP_STR; # back-compat
16             our @_lookup_modes= qw( GET_EQ GET_EQ_LAST GET_GT GET_LT GET_GE GET_LE GET_LE_LAST GET_NEXT GET_PREV
17             GET_OR_ADD LUEQUAL LUGTEQ LULTEQ LUGREAT LULESS LUNEXT LUPREV );
18             our @EXPORT_OK= (@_key_types, @_cmp_enum, @_lookup_modes, 'cmp_numsplit');
19             our %EXPORT_TAGS= (
20             key_type => \@_key_types,
21             cmp => \@_cmp_enum,
22             lookup => \@_lookup_modes,
23             get => \@_lookup_modes,
24             all => \@EXPORT_OK,
25             );
26              
27             if ($] < 5.016) {
28             # Before 5.16, perl didn't have 'fc' and CORE::lc wasn't a real sub, so need to wrap the op in our own sub.
29             # If anyone cares about the difference between 'fc' and 'lc' they can monkey-patch this.
30             eval('sub _fc_impl { lc shift } 1')
31             or die $@;
32             }
33              
34              
35              
36             *root= *root_node;
37             *min= *min_node;
38             *max= *max_node;
39             *nth= *nth_node;
40             *oldest= *oldest_node;
41             *newest= *newest_node;
42              
43              
44             sub iter {
45 129     129 1 3581278 my ($self, $key_or_node, $mode)= @_;
46 129 50 66     347 $key_or_node= $self->get_node($key_or_node, @_ > 2? $mode : GET_GE())
    100          
47             if @_ > 1 && ref $key_or_node ne 'Tree::RB::XS::Node';
48 129   66     448 Tree::RB::XS::Iter->_new($key_or_node || $self, 1);
49             }
50              
51             sub rev_iter {
52 109     109 1 245694 my ($self, $key_or_node, $mode)= @_;
53 109 50 66     258 $key_or_node= $self->get_node($key_or_node, @_ > 2? $mode : GET_LE_LAST())
    100          
54             if @_ > 1 && ref $key_or_node ne 'Tree::RB::XS::Node';
55 109   66     268 Tree::RB::XS::Iter->_new($key_or_node || $self, -1);
56             }
57              
58             sub iter_newer {
59 9     9 1 300165 my ($self, $node)= @_;
60 9   33     110 Tree::RB::XS::Iter->_new($node || $self, 2);
61             }
62              
63             sub iter_older {
64 4     4 1 614 my ($self, $node)= @_;
65 4   33     29 Tree::RB::XS::Iter->_new($node || $self, -2);
66             }
67              
68             *Tree::RB::XS::Node::min= *Tree::RB::XS::Node::left_leaf;
69             *Tree::RB::XS::Node::max= *Tree::RB::XS::Node::right_leaf;
70             *Tree::RB::XS::Node::successor= *Tree::RB::XS::Node::next;
71             *Tree::RB::XS::Node::predecessor= *Tree::RB::XS::Node::prev;
72              
73             sub Tree::RB::XS::Node::strip {
74 1     1   4561 my ($self, $cb)= @_;
75 1   33     25 my ($at, $next, $last)= (undef, $self->left_leaf || $self, $self->right_leaf || $self);
      33        
76 1         3 do {
77 3         9 $at= $next;
78 3         8 $next= $next->next;
79 3 100       11 if ($at != $self) {
80 2         8 $at->prune;
81 2 50       7 $cb->($at) if $cb;
82             }
83             } while ($at != $last);
84             }
85              
86             sub Tree::RB::XS::Node::as_lol {
87 3   33 3   329054 my $self= $_[1] || $_[0];
88             [
89 3 100 50     48 $self->left? $self->left->as_lol : '*',
    100          
    100          
90             $self->right? $self->right->as_lol : '*',
91             ($self->color? 'R':'B').':'.($self->key||'')
92             ]
93             }
94              
95             sub Tree::RB::XS::Node::iter {
96 3     3   30120 Tree::RB::XS::Iter->_new($_[0], 1);
97             }
98              
99             sub Tree::RB::XS::Node::rev_iter {
100 1     1   924 Tree::RB::XS::Iter->_new($_[0], -1);
101             }
102              
103             sub Tree::RB::XS::Node::iter_newer {
104 1     1   6 Tree::RB::XS::Iter->_new($_[0], 2);
105             }
106              
107             sub Tree::RB::XS::Node::iter_older {
108 1     1   5 Tree::RB::XS::Iter->_new($_[0], -2);
109             }
110              
111              
112             # I can't figure out how to do the closure in XS yet
113             sub Tree::RB::XS::Iter::_new {
114 257     257   376 my $class= shift;
115 257         333 my ($self,$y);
116 257     1   733 $self= bless sub { Tree::RB::XS::Iter::next($y) }, $class;
  1         7616  
117 257         376 Scalar::Util::weaken($y= $self);
118 257         1424 $self->_init(@_);
119             }
120             sub Tree::RB::XS::Iter::clone {
121 0     0   0 my $self= shift;
122 0         0 ref($self)->_new($self);
123             }
124              
125              
126             sub hseek {
127 3     3 1 301671 my ($self, $key, $opts)= @_;
128 3 100 100     38 if (@_ == 2 && ref $key eq 'HASH') {
129 1         4 $opts= $key;
130 1         5 $key= $opts->{'-key'};
131             }
132 3   100     25 my $reverse= $opts && $opts->{'-reverse'} || 0;
133 3 100       38 my $node= defined $key? $self->get_node($key, $reverse? GET_LE_LAST() : GET_GE()) : undef;
    100          
134 3         66 $self->_set_hashiter($node, $reverse);
135             }
136              
137              
138             *LUEQUAL= *GET_EQ;
139             *LUGTEQ= *GET_GE;
140             *LUGTLT= *GET_LE;
141             *LUGREAT= *GET_GT;
142             *LULESS= *GET_LT;
143             *LUPREV= *GET_PREV;
144             *LUNEXT= *GET_NEXT;
145              
146              
147             1;
148              
149             __END__