xref: /aosp_15_r20/external/protobuf/php/src/Google/Protobuf/Internal/RepeatedField.php (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1<?php
2
3// Protocol Buffers - Google's data interchange format
4// Copyright 2008 Google Inc.  All rights reserved.
5// https://developers.google.com/protocol-buffers/
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are
9// met:
10//
11//     * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//     * Redistributions in binary form must reproduce the above
14// copyright notice, this list of conditions and the following disclaimer
15// in the documentation and/or other materials provided with the
16// distribution.
17//     * Neither the name of Google Inc. nor the names of its
18// contributors may be used to endorse or promote products derived from
19// this software without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33/**
34 * RepeatedField and RepeatedFieldIter are used by generated protocol message
35 * classes to manipulate repeated fields.
36 */
37
38namespace Google\Protobuf\Internal;
39
40use Google\Protobuf\Internal\GPBType;
41use Google\Protobuf\Internal\GPBUtil;
42use Traversable;
43
44/**
45 * RepeatedField is used by generated protocol message classes to manipulate
46 * repeated fields. It can be used like native PHP array.
47 */
48class RepeatedField implements \ArrayAccess, \IteratorAggregate, \Countable
49{
50
51    /**
52     * @ignore
53     */
54    private $container;
55    /**
56     * @ignore
57     */
58    private $type;
59    /**
60     * @ignore
61     */
62    private $klass;
63    /**
64     * @ignore
65     */
66    private $legacy_klass;
67
68    /**
69     * Constructs an instance of RepeatedField.
70     *
71     * @param integer $type Type of the stored element.
72     * @param string $klass Message/Enum class name (message/enum fields only).
73     * @ignore
74     */
75    public function __construct($type, $klass = null)
76    {
77        $this->container = [];
78        $this->type = $type;
79        if ($this->type == GPBType::MESSAGE) {
80            $pool = DescriptorPool::getGeneratedPool();
81            $desc = $pool->getDescriptorByClassName($klass);
82            if ($desc == NULL) {
83                new $klass;  // No msg class instance has been created before.
84                $desc = $pool->getDescriptorByClassName($klass);
85            }
86            $this->klass = $desc->getClass();
87            $this->legacy_klass = $desc->getLegacyClass();
88        }
89    }
90
91    /**
92     * @ignore
93     */
94    public function getType()
95    {
96        return $this->type;
97    }
98
99    /**
100     * @ignore
101     */
102    public function getClass()
103    {
104        return $this->klass;
105    }
106
107    /**
108     * @ignore
109     */
110    public function getLegacyClass()
111    {
112        return $this->legacy_klass;
113    }
114
115    /**
116     * Return the element at the given index.
117     *
118     * This will also be called for: $ele = $arr[0]
119     *
120     * @param integer $offset The index of the element to be fetched.
121     * @return mixed The stored element at given index.
122     * @throws \ErrorException Invalid type for index.
123     * @throws \ErrorException Non-existing index.
124     * @todo need to add return type mixed (require update php version to 8.0)
125     */
126    #[\ReturnTypeWillChange]
127    public function offsetGet($offset)
128    {
129        return $this->container[$offset];
130    }
131
132    /**
133     * Assign the element at the given index.
134     *
135     * This will also be called for: $arr []= $ele and $arr[0] = ele
136     *
137     * @param int|null $offset The index of the element to be assigned.
138     * @param mixed $value The element to be assigned.
139     * @return void
140     * @throws \ErrorException Invalid type for index.
141     * @throws \ErrorException Non-existing index.
142     * @throws \ErrorException Incorrect type of the element.
143     * @todo need to add return type void (require update php version to 7.1)
144     */
145    #[\ReturnTypeWillChange]
146    public function offsetSet($offset, $value)
147    {
148        switch ($this->type) {
149            case GPBType::SFIXED32:
150            case GPBType::SINT32:
151            case GPBType::INT32:
152            case GPBType::ENUM:
153                GPBUtil::checkInt32($value);
154                break;
155            case GPBType::FIXED32:
156            case GPBType::UINT32:
157                GPBUtil::checkUint32($value);
158                break;
159            case GPBType::SFIXED64:
160            case GPBType::SINT64:
161            case GPBType::INT64:
162                GPBUtil::checkInt64($value);
163                break;
164            case GPBType::FIXED64:
165            case GPBType::UINT64:
166                GPBUtil::checkUint64($value);
167                break;
168            case GPBType::FLOAT:
169                GPBUtil::checkFloat($value);
170                break;
171            case GPBType::DOUBLE:
172                GPBUtil::checkDouble($value);
173                break;
174            case GPBType::BOOL:
175                GPBUtil::checkBool($value);
176                break;
177            case GPBType::BYTES:
178                GPBUtil::checkString($value, false);
179                break;
180            case GPBType::STRING:
181                GPBUtil::checkString($value, true);
182                break;
183            case GPBType::MESSAGE:
184                if (is_null($value)) {
185                    throw new \TypeError("RepeatedField element cannot be null.");
186                }
187                GPBUtil::checkMessage($value, $this->klass);
188                break;
189            default:
190                break;
191        }
192        if (is_null($offset)) {
193            $this->container[] = $value;
194        } else {
195            $count = count($this->container);
196            if (!is_numeric($offset) || $offset < 0 || $offset >= $count) {
197                trigger_error(
198                    "Cannot modify element at the given index",
199                    E_USER_ERROR);
200                return;
201            }
202            $this->container[$offset] = $value;
203        }
204    }
205
206    /**
207     * Remove the element at the given index.
208     *
209     * This will also be called for: unset($arr)
210     *
211     * @param integer $offset The index of the element to be removed.
212     * @return void
213     * @throws \ErrorException Invalid type for index.
214     * @throws \ErrorException The element to be removed is not at the end of the
215     * RepeatedField.
216     * @todo need to add return type void (require update php version to 7.1)
217     */
218    #[\ReturnTypeWillChange]
219    public function offsetUnset($offset)
220    {
221        $count = count($this->container);
222        if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) {
223            trigger_error(
224                "Cannot remove element at the given index",
225                E_USER_ERROR);
226            return;
227        }
228        array_pop($this->container);
229    }
230
231    /**
232     * Check the existence of the element at the given index.
233     *
234     * This will also be called for: isset($arr)
235     *
236     * @param integer $offset The index of the element to be removed.
237     * @return bool True if the element at the given offset exists.
238     * @throws \ErrorException Invalid type for index.
239     */
240    public function offsetExists($offset): bool
241    {
242        return isset($this->container[$offset]);
243    }
244
245    /**
246     * @ignore
247     */
248    public function getIterator(): Traversable
249    {
250        return new RepeatedFieldIter($this->container);
251    }
252
253    /**
254     * Return the number of stored elements.
255     *
256     * This will also be called for: count($arr)
257     *
258     * @return integer The number of stored elements.
259     */
260    public function count(): int
261    {
262        return count($this->container);
263    }
264}
265