File Coverage

blib/lib/Class/Accessor/PackedString/Set.pm
Criterion Covered Total %
statement 136 219 62.1
branch 47 114 41.2
condition 8 23 34.7
subroutine 3 3 100.0
pod n/a
total 194 359 54.0


line stmt bran cond sub pod time code
1             package Class::Accessor::PackedString::Set;
2              
3             our $DATE = '2017-10-15'; # DATE
4             our $VERSION = '0.001'; # VERSION
5              
6             #IFUNBUILT
7             # use strict 'subs', 'vars';
8             # use warnings;
9             #END IFUNBUILT
10              
11             sub import {
12 3     3   536 my ($class0, $spec) = @_;
13 3         7 my $caller = caller();
14              
15 3         42 my $class = $caller;
16              
17             #IFUNBUILT
18             # no warnings 'redefine';
19             #END IFUNBUILT
20              
21 3         6 my $attrs = $spec->{accessors};
22              
23             # store list of accessors in the package
24             {
25             #IFUNBUILT
26             # no warnings 'once';
27             #END IFUNBUILT
28 3         3 @{"$class\::HAS_PACKED"} = @$attrs;
  3         6  
  3         13  
29             }
30              
31             # generate accessors
32 3         7 my %idx ; # key = attribute name, value = index
33             my %tmpl ; # key = attribute name, value = pack() template
34 3         0 my %tmplsize; # key = attribute name, value = pack() data size
35 3         6 my @attrs = @$attrs;
36 3         10 while (my ($name, $template) = splice @attrs, 0, 2) {
37 7         14 $idx{$name} = keys %idx;
38 7         9 $tmpl{$name} = $template;
39 7         27 $tmplsize{$name} = length(pack $template);
40             }
41              
42 3         7 @attrs = @$attrs;
43 3         8 while (my ($name, $template) = splice @attrs, 0, 2) {
44 7         12 my $idx = $idx{$name};
45 7         11 my $code_str = 'sub (;$) {' . "\n";
46 7         10 $code_str .= qq( my \$self = shift;\n);
47              
48 7         9 $code_str .= qq( my \$val;\n my \$pos = 0;\n while (1) {\n last if \$pos >= length(\$\$self);\n my \$idx = ord(substr(\$\$self, \$pos++, 1));\n);
49 7         23 for my $attr (sort {$idx{$a} <=> $idx{$b}} keys %idx) {
  13         32  
50 17         21 my $idx = $idx{$attr};
51 17 100       48 $code_str .= qq| |.($idx == 0 ? "if " : "elsif").qq| (\$idx == $idx) { my \$v = unpack("| . $tmpl{$attr} . qq|", substr(\$\$self, \$pos, | . $tmplsize{$attr} . qq|));|;
52 17 100       28 if ($attr eq $name) {
53 7         14 $code_str .= qq| \$val = \$v; if (\@_ && defined \$_[0]) { substr(\$\$self, \$pos, | . $tmplsize{$attr} . qq|) = pack("| . $tmpl{$attr} . qq|", \$_[0]); return \$val } last|;
54             } else {
55 10         16 $code_str .= qq| \$pos += | . $tmplsize{$attr} . qq|; next|;
56             }
57 17         26 $code_str .= qq| }\n|;
58             }
59 7         12 $code_str .= qq( else { die "Invalid data in object \$self: invalid index \$idx" }\n);
60 7         8 $code_str .= qq( }\n);
61              
62 7         9 $code_str .= qq( return \$val unless \@_;\n);
63 7         11 $code_str .= qq( if (defined \$_[0]) {\n); # set a newly set attribute, append
64 7         11 $code_str .= qq| \$\$self .= chr($idx) . pack("|. $tmpl{$name} . qq|", \$_[0]);\n|;
65 7         11 $code_str .= qq( } elsif (defined \$val) {\n); # delete unset attribute
66 7         10 $code_str .= qq| substr(\$\$self, \$pos-1, | . $tmplsize{$name} . qq|+1) = "";\n|;
67 7         8 $code_str .= qq( }\n);
68 7         10 $code_str .= qq( return \$val;\n);
69 7         10 $code_str .= "}\n";
70             #print "D:accessor code for $name: ", $code_str, "\n";
71 7 50 0 1   1478 *{"$class\::$name"} = eval $code_str;
  7 0 0     34  
  1 0 100     23  
  1 0 0     2  
  1 0 0     2  
  1 50 0     2  
  1 50 100     8  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0 100       0  
  0 100       0  
  0 100       0  
  0 50       0  
  0 100       0  
  0 100       0  
  0 50       0  
  1 0       3  
  1 0       4  
  1 0       5  
  0 0       0  
  1 0       2  
  0 0       0  
  0 0       0  
  0 100       0  
  0 0       0  
  0 100       0  
  0 50       0  
  0 0       0  
  0 50       0  
  0 50       0  
  0 0       0  
  0 100       0  
  0 0       0  
  0 50       0  
  0 50       0  
  0 0       0  
  0 50       0  
  0 50       0  
  0 0       0  
  0 100       0  
  0 100       0  
  0 100       0  
  0 50       0  
  6 100       13  
  6 100       9  
  6 50       8  
  6         11  
  10         20  
  8         15  
  8         19  
  4         11  
  4         6  
  4         7  
  4         10  
  4         8  
  4         14  
  1         5  
  1         2  
  3         5  
  0         0  
  5         18  
  2         6  
  1         4  
  1         3  
  2         4  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         26  
  1         2  
  1         2  
  1         2  
  3         9  
  2         4  
  2         6  
  1         3  
  1         2  
  1         23  
  1         3  
  1         2  
  1         2  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         13  
  1         6  
  0         0  
  1         2  
  1         22  
  1         2  
  1         2  
  1         2  
  2         5  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         2  
  1         2  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         3  
  1         3  
  0         0  
  1         3  
  6         1294  
  6         10  
  6         8  
  6         11  
  7         20  
  5         12  
  5         17  
  4         12  
  4         7  
  4         16  
  1         4  
  1         3  
  3         5  
  1         5  
  1         5  
  1         3  
  0         0  
  5         23  
  2         7  
  1         6  
  1         3  
  2         5  
72 7 50       34 die if $@;
73             }
74              
75             # generate constructor
76             {
77 3         5 my $code_str;
  3         3  
78              
79 3         5 $code_str = 'sub { my $o = ""; bless \$o, shift }';
80              
81             # TODO
82              
83             #$code_str = 'sub { my ($class, %args) = @_;';
84             #$code_str .= qq( no warnings 'uninitialized';);
85             #$code_str .= qq( my \@attrs = map { undef } 1..$num_attrs;);
86             #for my $attr (sort keys %$attrs) {
87             # my $idx = $idx{$attr};
88             # $code_str .= qq( if (exists \$args{'$attr'}) { \$attrs[$idx] = delete \$args{'$attr'} });
89             #}
90             #$code_str .= ' die "Unknown $class attributes in constructor: ".join(", ", sort keys %args) if keys %args;';
91             #$code_str .= qq( my \$self = pack('$pack_template', \@attrs); bless \\\$self, '$class';);
92             #$code_str .= ' }';
93              
94             #print "D:constructor code for class $class: ", $code_str, "\n";
95 3   100     12 my $constructor = $spec->{constructor} || "new";
96 3 50       5 unless (*{"$class\::$constructor"}{CODE}) {
  3         13  
97 3     1   196 *{"$class\::$constructor"} = eval $code_str;
  3         10  
  1         974  
  1         4  
  0         0  
  0         0  
  1         2324  
  1         3  
98 3 50       72 die if $@;
99             };
100             }
101             }
102              
103             1;
104             # ABSTRACT: Like Class::Accessor::PackedString, but store attributes as they are set
105              
106             __END__