Small optimisations, by Brandon Black
[p5sagit/p5-mst-13.2.git] / t / op / state.t
CommitLineData
952306ac 1#!./perl -w
ea84231e 2# tests state variables
952306ac 3
4BEGIN {
5 chdir 't' if -d 't';
6 @INC = '../lib';
7 require './test.pl';
8}
9
10use strict;
712d05cf 11use feature "state";
952306ac 12
84f64f45 13plan tests => 46;
952306ac 14
15ok( ! defined state $uninit, q(state vars are undef by default) );
16
ea84231e 17# basic functionality
18
952306ac 19sub stateful {
20 state $x;
21 state $y = 1;
22 my $z = 2;
84f64f45 23 state ($t) = 3;
24 return ($x++, $y++, $z++, $t++);
952306ac 25}
26
84f64f45 27my ($x, $y, $z, $t) = stateful();
952306ac 28is( $x, 0, 'uninitialized state var' );
29is( $y, 1, 'initialized state var' );
30is( $z, 2, 'lexical' );
84f64f45 31is( $t, 3, 'initialized state var, list syntax' );
952306ac 32
84f64f45 33($x, $y, $z, $t) = stateful();
952306ac 34is( $x, 1, 'incremented state var' );
35is( $y, 2, 'incremented state var' );
36is( $z, 2, 'reinitialized lexical' );
84f64f45 37is( $t, 4, 'incremented state var, list syntax' );
952306ac 38
84f64f45 39($x, $y, $z, $t) = stateful();
952306ac 40is( $x, 2, 'incremented state var' );
41is( $y, 3, 'incremented state var' );
42is( $z, 2, 'reinitialized lexical' );
84f64f45 43is( $t, 5, 'incremented state var, list syntax' );
952306ac 44
ea84231e 45# in a nested block
46
952306ac 47sub nesting {
48 state $foo = 10;
49 my $t;
50 { state $bar = 12; $t = ++$bar }
51 ++$foo;
52 return ($foo, $t);
53}
54
55($x, $y) = nesting();
56is( $x, 11, 'outer state var' );
57is( $y, 13, 'inner state var' );
58
59($x, $y) = nesting();
60is( $x, 12, 'outer state var' );
61is( $y, 14, 'inner state var' );
62
ea84231e 63# in a closure
64
952306ac 65sub generator {
66 my $outer;
67 # we use $outer to generate a closure
68 sub { ++$outer; ++state $x }
69}
70
71my $f1 = generator();
72is( $f1->(), 1, 'generator 1' );
73is( $f1->(), 2, 'generator 1' );
74my $f2 = generator();
75is( $f2->(), 1, 'generator 2' );
76is( $f1->(), 3, 'generator 1 again' );
77is( $f2->(), 2, 'generator 2 once more' );
5d1e1362 78
ea84231e 79# with ties
5d1e1362 80{
81 package countfetches;
82 our $fetchcount = 0;
83 sub TIESCALAR {bless {}};
84 sub FETCH { ++$fetchcount; 18 };
85 tie my $y, "countfetches";
86 sub foo { state $x = $y; $x++ }
87 ::is( foo(), 18, "initialisation with tied variable" );
88 ::is( foo(), 19, "increments correctly" );
89 ::is( foo(), 20, "increments correctly, twice" );
90 ::is( $fetchcount, 1, "fetch only called once" );
91}
aa2c6373 92
ea84231e 93# state variables are shared among closures
94
95sub gen_cashier {
96 my $amount = shift;
97 state $cash_in_store = 0;
98 return {
99 add => sub { $cash_in_store += $amount },
100 del => sub { $cash_in_store -= $amount },
101 bal => sub { $cash_in_store },
102 };
103}
104
105gen_cashier(59)->{add}->();
106gen_cashier(17)->{del}->();
107is( gen_cashier()->{bal}->(), 42, '$42 in my drawer' );
108
109# stateless assignment to a state variable
110
aa2c6373 111sub stateless {
3d2c6be3 112 no warnings 'misc';
461824dc 113 (state $reinitme, my $foo) = (42, 'bar');
aa2c6373 114 ++$reinitme;
115}
116is( stateless(), 43, 'stateless function, first time' );
117is( stateless(), 43, 'stateless function, second time' );
a5911867 118
119# array state vars
120
121sub stateful_array {
122 state @x;
123 push @x, 'x';
124 return $#x;
125}
126
127my $xsize = stateful_array();
128is( $xsize, 0, 'uninitialized state array' );
129
130$xsize = stateful_array();
131is( $xsize, 1, 'uninitialized state array after one iteration' );
132
84f64f45 133sub stateful_array_init {
134 state @x = (1, 2);
135 push @x, 'x';
136 return $#x;
137}
138
139$xsize = stateful_array_init();
140is( $xsize, 2, 'initialized state array' );
141
142$xsize = stateful_array_init();
143is( $xsize, 3, 'initialized state array after one iteration' );
144
a5911867 145# hash state vars
146
147sub stateful_hash {
148 state %hx;
149 return $hx{foo}++;
150}
151
152my $xhval = stateful_hash();
153is( $xhval, 0, 'uninitialized state hash' );
154
155$xhval = stateful_hash();
156is( $xhval, 1, 'uninitialized state hash after one iteration' );
a53dbfbb 157
84f64f45 158sub stateful_hash_init {
159 state %hx = (foo => 10);
160 return $hx{foo}++;
161}
162
163$xhval = stateful_hash_init();
164is( $xhval, 10, 'initialized state hash' );
165
166$xhval = stateful_hash_init();
167is( $xhval, 11, 'initialized state hash after one iteration' );
168
a53dbfbb 169# state declaration with a list
170
171sub statelist {
172 # note that this should be a state assignment, while (state $lager, state $stout) shouldn't
173 state($lager, $stout) = (11, 22);
174 $lager++;
175 $stout++;
176 "$lager/$stout";
177}
178
179my $ls = statelist();
180is($ls, "12/23", 'list assignment to state scalars');
181$ls = statelist();
461824dc 182is($ls, "13/24", 'list assignment to state scalars');
3d2c6be3 183
184sub statelist2 {
185 state($sherry, $bourbon) = (1 .. 2);
186 $sherry++;
187 $bourbon++;
188 "$sherry/$bourbon";
189}
190
191$ls = statelist2();
192is($ls, "2/3", 'list assignment to state scalars');
193$ls = statelist2();
3d2c6be3 194is($ls, "3/4", 'list assignment to state scalars');
fda94784 195
196# Recursion
197
198sub noseworth {
199 my $level = shift;
200 state $recursed_state = 123;
201 is($recursed_state, 123, "state kept through recursion ($level)");
202 noseworth($level - 1) if $level;
203}
204noseworth(2);
84f64f45 205
206# Assignment return value
207
208sub pugnax { my $x = state $y = 42; $y++; $x; }
209
210is( pugnax(), 42, 'scalar state assignment return value' );
211is( pugnax(), 43, 'scalar state assignment return value' );