Mercurial > pub > Impl
comparison lib/IMPL/Config/Bag.pm @ 415:3d24b10dd0d5 ref20150831
working on IMPL::Config::Container
author | cin |
---|---|
date | Tue, 20 Oct 2015 07:32:55 +0300 |
parents | ec6f2d389d1e |
children | 3ed0c58e9da3 |
comparison
equal
deleted
inserted
replaced
414:ec6f2d389d1e | 415:3d24b10dd0d5 |
---|---|
6 base => [ | 6 base => [ |
7 'IMPL::Object' => undef | 7 'IMPL::Object' => undef |
8 ], | 8 ], |
9 props => [ | 9 props => [ |
10 _parents => '*rw', # array of parent bags | 10 _parents => '*rw', # array of parent bags |
11 _state => '*rw', #array of previous timestamps | 11 _parentRev => '*rw', # the timestamp of the parent |
12 _sealed => '*rw', # the bag has descendants | |
12 _cache => '*rw', # own or cached entries | 13 _cache => '*rw', # own or cached entries |
13 _timestamp => '*rw', | 14 _timestamp => '*rw', |
14 _entries => '*rw', # each entry is represented by hash | 15 _entries => '*rw', # each entry is represented by hash |
15 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value } | 16 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value } |
16 ] | 17 ] |
18 | 19 |
19 sub CTOR { | 20 sub CTOR { |
20 my ( $this, $p ) = @_; | 21 my ( $this, $p ) = @_; |
21 | 22 |
22 if ($p) { | 23 if ($p) { |
24 $p->_Seal(); | |
23 my @parents; | 25 my @parents; |
24 push @parents, @{ $p->{$_parents} } if $p->{$_parents}; | 26 push @parents, @{ $p->{$_parents} } if $p->{$_parents}; |
25 push @parents, $p; | 27 push @parents, $p; |
26 $this->{$_parents} = \@parents; | 28 $this->{$_parents} = \@parents; |
27 $this->{$_state} = [ map $_->{$_timestamp}, @parents ]; | 29 $this->{$_parentRev} = $p->{$_timestamp}; |
28 } | 30 } |
29 | 31 |
30 $this->{$_timestamp} = 0; | 32 $this->{$_timestamp} = 0; |
31 $this->{$_cache} = {}; | 33 $this->{$_cache} = {}; |
32 $this->{$_entries} = []; | 34 $this->{$_entries} = []; |
33 } | 35 } |
34 | 36 |
35 sub GetParent { | 37 sub GetParent { |
36 $_[0]->{$_parents} && $_[0]->{$_parents}[0]; | 38 my ($this) = @_; |
39 | |
40 $this->{$_parents} && $this->{$_parents}[ @{ $this->{$_parents} } - 1 ]; | |
41 } | |
42 | |
43 sub _Seal { | |
44 unless ($_[0]->{$_sealed}) { | |
45 $_[0]->{$_sealed} = 1; | |
46 $_[0]->{$_timestamp} = 0; # from now the timestamp is important | |
47 } | |
37 } | 48 } |
38 | 49 |
39 sub _Validate { | 50 sub _Validate { |
40 my ($this) = @_; | 51 my ($this) = @_; |
41 | 52 |
42 my $parents = $this->{$_parents} | 53 my $chain = $this->{$_parents} |
43 or return; | 54 or return 1; |
44 my $state = $this->{$_state}; | 55 |
45 my $len = @$parents; | 56 my $rev = 0; # rev 0 means that parent was never modified |
57 # this allows to made more efficient checks | |
46 my $flush; | 58 my $flush; |
47 | 59 |
48 for ( my $i = 0 ; $i < $len ; $i++ ) { | 60 foreach my $bag (@$chain, $this) { |
49 if ($flush) { | 61 # we need to updated all bags after the first change was detected; |
50 $parents->[$i]{$_cache} = {}; | 62 if ($flush ||= $rev and $bag->{$_parentRev} != $rev) { |
51 $state->[$i] = $parents->[$i]{$_timestamp}; | 63 $bag->{$_cache} = {}; |
52 } | 64 $bag->{$_parentRev} = $rev; |
53 else { | 65 } |
54 $flush = ( $parents->[$i]{$_timestamp} != $state->[$i] ); | 66 $rev = $bag->{$_timestamp}; |
55 } | |
56 } | 67 } |
57 | 68 |
58 if ($flush) { | 69 return $flush ? 0 : 1; |
59 $this->{$_cache} = {}; | |
60 return 0; | |
61 } | |
62 | |
63 return 1; | |
64 } | 70 } |
65 | 71 |
66 sub Resolve { | 72 sub Resolve { |
67 my ( $this, $role ) = @_; | 73 my ( $this, $role ) = @_; |
68 | 74 |
69 if ( my $d = $this->GetDescriptor() ) { | 75 die IMPL::InvalidArgumentException->new('role') |
76 unless defined $role; | |
77 | |
78 if ( my $d = $this->_GetDescriptor($role) ) { | |
70 return $d->{value}; | 79 return $d->{value}; |
71 } | 80 } |
72 else { | 81 else { |
73 return; | 82 return; |
74 } | 83 } |
75 } | 84 } |
76 | 85 |
77 sub GetDescriptor { | 86 sub _GetDescriptor { |
78 my ( $this, $role ) = @_; | 87 my ( $this, $role ) = @_; |
79 | 88 |
80 my $d = $this->{$_cache}{$role}; | 89 my $d = $this->{$_cache}{$role}; |
81 | 90 |
82 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache) | 91 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache) |
83 # otherwise the cache must be validated | 92 # otherwise the cache must be validated |
84 return $d | 93 return $d |
85 if $d | 94 if $d |
86 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 ) | 95 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 ) |
87 or $this->_Validate() ); | 96 or $this->_Validate() ); |
97 | |
98 # if there were no descriptor in cache we need to ensure that the cache | |
99 # chain is valid before reolving starts | |
100 $this->_Validate() unless $d; | |
88 | 101 |
89 # the cache chain is valid | 102 # the cache chain is valid |
90 # $d is not a valid descriptor | 103 # $d is not a valid descriptor |
91 | 104 |
92 $d = undef; | 105 $d = undef; |
125 my ( $this, $role ) = @_; | 138 my ( $this, $role ) = @_; |
126 | 139 |
127 return [ | 140 return [ |
128 map $_->{value}, | 141 map $_->{value}, |
129 grep $_->{isa}{$role}, | 142 grep $_->{isa}{$role}, |
130 map $_->{$_entries}, | 143 map @{$_->{$_entries}}, |
131 @{ $this->{$_parents} || [] }, | 144 @{ $this->{$_parents} || [] }, |
132 $this | 145 $this |
133 ]; | 146 ]; |
134 | 147 |
135 } | 148 } |
136 | 149 |
137 sub Register { | 150 sub Register { |
138 my ( $this, $isa, $value ) = @_; | 151 my ( $this, $isa, $value ) = @_; |
139 | 152 |
140 $isa = { $isa, 1 } unless isHash($isa); | 153 $isa = { $isa, 1 } unless ishash($isa); |
141 | 154 |
142 push @{ $this->{$_entries} }, | 155 push @{ $this->{$_entries} }, |
143 { owner => $this, isa => $isa, value => $value }; | 156 { owner => $this, isa => $isa, value => $value }; |
144 $this->{$_timestamp}++; | 157 $this->{$_timestamp}++; |
145 | 158 |