aboutsummaryrefslogtreecommitdiff
path: root/challenge-027/markus-holzer/perl6/lib/Scalar/History.pm6
blob: 13c83464242c00c8c51e3fd185e2405ccd386023 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use Test;

my $minumum-version = Version.new('2019.07.1.357.gd.00674.b.31');

die "Scalar::History requires $minumum-version or later"
    if ( $*PERL.compiler.version cmp $minumum-version ) == Less;

class Scalar::History::Proxy is Proxy
{
    has @!history;
    has $!position;

    # This is needed for now since the standard ways
    # like assigning in the `has` statement, TWEAK
    # and BUILD don't work with `Proxy`

    method new( :&FETCH!, :&STORE!, *%_ ) is raw
    {
        my $self := self.Proxy::new( :&FETCH, :&STORE );
        $self.VAR.TWEAK( |%_ );
        $self
    }

    method TWEAK( :$!position = 0 ) {
        # yadayada
    }

    method current-value( \SELF: )
    {
        @!history[ $!position ]
    }

    method latest-value( \SELF: )
    {
        @!history[ *-1 ]
    }

    method get-history( \SELF: Bool :$all = False )
    {
        my $to-index = $all ?? @!history.elems - 1 !! $!position;
        @!history[ ^$to-index ]
    }

    method reset-history( \SELF: )
    {
        @!history = ();
        $!position = 0;
    }

    method forward-history( \SELF: $steps )
    {
        $!position = $!position + $steps;
        $!position = @!history.elems - 1
            if $!position >= @!history.elems;
        $!position;
    }

    method rewind-history( \SELF: $steps )
    {
        $!position = $!position - $steps;
        $!position = 0
            if $!position < 0;
        $!position;
    }

    method store-value( \SELF: $new-value, $register-duplicates )
    {
        # Forget stuff after rewind
        if @!history.elems > $!position + 1
        {
            @!history.splice( $!position + 1 );
        }

        if !($new-value eqv SELF.current-value) || $register-duplicates
        {
            @!history.push( $new-value );
            $!position = @!history.elems - 1;
        }
    }
}

class Scalar::History
{
    method create( $value, ::T $type = Any, Bool :$register-duplicates = False )
    {
        return-rw Scalar::History::Proxy.new(
            FETCH => method ( \SELF: ) {
                SELF.current-value() },
            STORE => method ( \SELF: T $new-value ) {
                SELF.store-value( $new-value, $register-duplicates ); }
        ) = $value;
    }
}