Mercurial > pub > Impl
comparison lib/IMPL/Config/Bag.pm @ 414:ec6f2d389d1e ref20150831
working on IMPL::Config::Bag
author | cin |
---|---|
date | Fri, 02 Oct 2015 06:56:24 +0300 |
parents | af8d359ee4cc |
children | 3d24b10dd0d5 |
comparison
equal
deleted
inserted
replaced
413:af8d359ee4cc | 414:ec6f2d389d1e |
---|---|
1 package IMPL::Config::Bag; | 1 package IMPL::Config::Bag; |
2 use strict; | 2 use strict; |
3 | 3 |
4 use IMPL::lang qw(:base); | |
4 use IMPL::declare { | 5 use IMPL::declare { |
5 base => [ | 6 base => [ |
6 'IMPL::Object' => undef | 7 'IMPL::Object' => undef |
7 ], | 8 ], |
8 props => [ | 9 props => [ |
9 parent => '*r', | 10 _parents => '*rw', # array of parent bags |
10 _cache => '*rw', | 11 _state => '*rw', #array of previous timestamps |
11 _entries => '*rw' | 12 _cache => '*rw', # own or cached entries |
13 _timestamp => '*rw', | |
14 _entries => '*rw', # each entry is represented by hash | |
15 # { isa => linear_isa_hash, owner => owner_of_the_entry, value => value } | |
12 ] | 16 ] |
13 }; | 17 }; |
14 | 18 |
15 sub CTOR { | 19 sub CTOR { |
16 my ($this, $p) = @_; | 20 my ( $this, $p ) = @_; |
17 | 21 |
18 $this->{$parent} = $p; | 22 if ($p) { |
19 $this->{$_cache} = {}; | 23 my @parents; |
20 $this->{$_entries} = []; | 24 push @parents, @{ $p->{$_parents} } if $p->{$_parents}; |
25 push @parents, $p; | |
26 $this->{$_parents} = \@parents; | |
27 $this->{$_state} = [ map $_->{$_timestamp}, @parents ]; | |
28 } | |
29 | |
30 $this->{$_timestamp} = 0; | |
31 $this->{$_cache} = {}; | |
32 $this->{$_entries} = []; | |
33 } | |
34 | |
35 sub GetParent { | |
36 $_[0]->{$_parents} && $_[0]->{$_parents}[0]; | |
37 } | |
38 | |
39 sub _Validate { | |
40 my ($this) = @_; | |
41 | |
42 my $parents = $this->{$_parents} | |
43 or return; | |
44 my $state = $this->{$_state}; | |
45 my $len = @$parents; | |
46 my $flush; | |
47 | |
48 for ( my $i = 0 ; $i < $len ; $i++ ) { | |
49 if ($flush) { | |
50 $parents->[$i]{$_cache} = {}; | |
51 $state->[$i] = $parents->[$i]{$_timestamp}; | |
52 } | |
53 else { | |
54 $flush = ( $parents->[$i]{$_timestamp} != $state->[$i] ); | |
55 } | |
56 } | |
57 | |
58 if ($flush) { | |
59 $this->{$_cache} = {}; | |
60 return 0; | |
61 } | |
62 | |
63 return 1; | |
21 } | 64 } |
22 | 65 |
23 sub Resolve { | 66 sub Resolve { |
24 my ($this,$role) = @_; | 67 my ( $this, $role ) = @_; |
25 | 68 |
26 my $d = $this->GetDescriptor(); | 69 if ( my $d = $this->GetDescriptor() ) { |
70 return $d->{value}; | |
71 } | |
72 else { | |
73 return; | |
74 } | |
27 } | 75 } |
28 | 76 |
29 sub GetDescriptor { | 77 sub GetDescriptor { |
30 my ($this, $role) = @_; | 78 my ( $this, $role ) = @_; |
31 | 79 |
32 my $d = $this->{$_cache}{$role}; | 80 my $d = $this->{$_cache}{$role}; |
33 return $d if $d and $d->{valid}; | 81 |
34 | 82 # return descriptor if this is own descriptor and its level is 1 (i.e. it can't be overriden by the parent cache) |
35 my @entries = @{$this->{$_entries}}; | 83 # otherwise the cache must be validated |
36 | 84 return $d |
37 if(my $t = $this->{$parent} && $this->{$parent}->GetDescriptor($role)) { | 85 if $d |
38 push @entries, $t; | 86 and ( ( $d->{owner} == $this and $d->{isa}{$role} == 1 ) |
87 or $this->_Validate() ); | |
88 | |
89 # the cache chain is valid | |
90 # $d is not a valid descriptor | |
91 | |
92 $d = undef; | |
93 my $prev; | |
94 | |
95 if ( my $parents = $this->{$_parents} ) { | |
96 foreach my $bag ( @$parents, $this ) { | |
97 | |
98 # check the cache; | |
99 unless ( my $t = $bag->{$_cache}{$role} ) { | |
100 | |
101 # no cached entry this may be due cache flush | |
102 # go through own entries and find better entry than inherited from parents | |
103 foreach my $entry ( @{ $bag->{$_entries} } ) { | |
104 my $level = $entry->{isa}{$role}; | |
105 if ( $level and ( not($prev) or $level <= $prev ) ) { | |
106 $d = $entry; | |
107 $prev = $level; | |
108 } | |
109 } | |
110 | |
111 #cache it | |
112 $bag->{$_cache}{$role} = $d if $d; | |
113 } | |
114 else { | |
115 $d = $t; | |
116 $prev = $d->{isa}{$role}; | |
117 } | |
118 } | |
39 } | 119 } |
40 | 120 |
41 my $level; | 121 return $d; |
42 foreach my $entry (@entries) { | |
43 my $t = $entry->{isa}{$role}; | |
44 next unless defined $t; | |
45 if (defined($level) && $level > $t) { | |
46 $d = $entry; | |
47 $level = $t; | |
48 } | |
49 } | |
50 | |
51 if ($d and $d->{valid}) { | |
52 $this->{$_cache}{$role} = $d; | |
53 return $d; | |
54 } else { | |
55 return; | |
56 } | |
57 } | 122 } |
58 | 123 |
59 sub ResolveAll { | 124 sub ResolveAll { |
60 my ($this, $role) = @_; | 125 my ( $this, $role ) = @_; |
61 | 126 |
62 my $result = $this->{$parent} ? $this->{$parent}->ResolveAll() : []; | 127 return [ |
63 | 128 map $_->{value}, |
64 push @$result, map $_->{value}, grep $_->{isa}{$role}, @{$this->{$_entries}}; | 129 grep $_->{isa}{$role}, |
65 | 130 map $_->{$_entries}, |
66 return $result; | 131 @{ $this->{$_parents} || [] }, |
132 $this | |
133 ]; | |
134 | |
67 } | 135 } |
68 | 136 |
69 sub Register { | 137 sub Register { |
70 my ($this, $role, $isa, $value) = @_; | 138 my ( $this, $isa, $value ) = @_; |
71 } | |
72 | 139 |
73 sub _UpdateDescriptor { | 140 $isa = { $isa, 1 } unless isHash($isa); |
74 | |
75 } | |
76 | 141 |
77 package IMPL::Config::Bag::Entry; | 142 push @{ $this->{$_entries} }, |
78 use IMPL::Exception(); | 143 { owner => $this, isa => $isa, value => $value }; |
79 use IMPL::declare { | 144 $this->{$_timestamp}++; |
80 base => [ | |
81 'IMPL::Object::Fields' => undef | |
82 ] | |
83 }; | |
84 | 145 |
85 my @fields = qw(owner type isa valid value index); | 146 delete $this->{$_cache}{$_} foreach keys %$isa; |
86 use fields @fields; | |
87 | 147 |
88 sub CTOR { | 148 return $this; |
89 my SELF $this = shift; | |
90 my $args = shift; | |
91 | |
92 $this->{valid} = 1; | |
93 $this->{owner} = $args->{owner} or die IMPL::InvalidArgumentException->new("owner"); | |
94 $this->{value} = $args->{value} if exists $args->{value}; | |
95 $this->{isa} = $args->{isa} if $args->{isa}; | |
96 } | |
97 | |
98 sub Invalidate { | |
99 my SELF $this = shift; | |
100 | |
101 $this->{owner}->_UpdateDescriptor($this); | |
102 } | 149 } |
103 | 150 |
104 1; | 151 1; |