summaryrefslogtreecommitdiff
path: root/vendor/symfony/cache/Traits/ValueWrapper.php
blob: 718a23d391efe6a5c40b24524d17c3aa5cfbcda8 (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
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * A short namespace-less class to serialize items with metadata.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 *
 * @internal
 */
class ©
{
    private const EXPIRY_OFFSET = 1648206727;
    private const INT32_MAX = 2147483647;

    public readonly mixed $value;
    public readonly array $metadata;

    public function __construct(mixed $value, array $metadata)
    {
        $this->value = $value;
        $this->metadata = $metadata;
    }

    public function __serialize(): array
    {
        // pack 31-bits ctime into 14bits
        $c = $this->metadata['ctime'] ?? 0;
        $c = match (true) {
            $c > self::INT32_MAX - 2 => self::INT32_MAX,
            $c > 0 => 1 + $c,
            default => 1,
        };
        $e = 0;
        while (!(0x40000000 & $c)) {
            $c <<= 1;
            ++$e;
        }
        $c = (0x7FE0 & ($c >> 16)) | $e;

        $pack = pack('Vn', (int) (0.1 + ($this->metadata['expiry'] ?: self::INT32_MAX + self::EXPIRY_OFFSET) - self::EXPIRY_OFFSET), $c);

        if (isset($this->metadata['tags'])) {
            $pack[4] = $pack[4] | "\x80";
        }

        return [$pack => $this->value] + ($this->metadata['tags'] ?? []);
    }

    public function __unserialize(array $data): void
    {
        $pack = array_key_first($data);
        $this->value = $data[$pack];

        if ($hasTags = "\x80" === ($pack[4] & "\x80")) {
            unset($data[$pack]);
            $pack[4] = $pack[4] & "\x7F";
        }

        $metadata = unpack('Vexpiry/nctime', $pack);
        $metadata['expiry'] += self::EXPIRY_OFFSET;

        if (!$metadata['ctime'] = ((0x4000 | $metadata['ctime']) << 16 >> (0x1F & $metadata['ctime'])) - 1) {
            unset($metadata['ctime']);
        }

        if ($hasTags) {
            $metadata['tags'] = $data;
        }

        $this->metadata = $metadata;
    }
}