xref: /aosp_15_r20/external/protobuf/php/src/Google/Protobuf/Internal/MapField.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 * MapField and MapFieldIter are used by generated protocol message classes to
35 * manipulate map fields.
36 */
37
38namespace Google\Protobuf\Internal;
39
40use Traversable;
41
42/**
43 * MapField is used by generated protocol message classes to manipulate map
44 * fields. It can be used like native PHP array.
45 */
46class MapField implements \ArrayAccess, \IteratorAggregate, \Countable
47{
48    /**
49     * @ignore
50     */
51    private $container;
52    /**
53     * @ignore
54     */
55    private $key_type;
56    /**
57     * @ignore
58     */
59    private $value_type;
60    /**
61     * @ignore
62     */
63    private $klass;
64    /**
65     * @ignore
66     */
67    private $legacy_klass;
68
69    /**
70     * Constructs an instance of MapField.
71     *
72     * @param long $key_type Type of the stored key element.
73     * @param long $value_type Type of the stored value element.
74     * @param string $klass Message/Enum class name of value instance
75     * (message/enum fields only).
76     * @ignore
77     */
78    public function __construct($key_type, $value_type, $klass = null)
79    {
80        $this->container = [];
81        $this->key_type = $key_type;
82        $this->value_type = $value_type;
83        $this->klass = $klass;
84
85        if ($this->value_type == GPBType::MESSAGE) {
86            $pool = DescriptorPool::getGeneratedPool();
87            $desc = $pool->getDescriptorByClassName($klass);
88            if ($desc == NULL) {
89                new $klass;  // No msg class instance has been created before.
90                $desc = $pool->getDescriptorByClassName($klass);
91            }
92            $this->klass = $desc->getClass();
93            $this->legacy_klass = $desc->getLegacyClass();
94        }
95    }
96
97    /**
98     * @ignore
99     */
100    public function getKeyType()
101    {
102        return $this->key_type;
103    }
104
105    /**
106     * @ignore
107     */
108    public function getValueType()
109    {
110        return $this->value_type;
111    }
112
113    /**
114     * @ignore
115     */
116    public function getValueClass()
117    {
118        return $this->klass;
119    }
120
121    /**
122     * @ignore
123     */
124    public function getLegacyValueClass()
125    {
126        return $this->legacy_klass;
127    }
128
129    /**
130     * Return the element at the given key.
131     *
132     * This will also be called for: $ele = $arr[$key]
133     *
134     * @param int|string $key The key of the element to be fetched.
135     * @return object The stored element at given key.
136     * @throws \ErrorException Invalid type for index.
137     * @throws \ErrorException Non-existing index.
138     * @todo need to add return type mixed (require update php version to 8.0)
139     */
140    #[\ReturnTypeWillChange]
141    public function offsetGet($key)
142    {
143        return $this->container[$key];
144    }
145
146    /**
147     * Assign the element at the given key.
148     *
149     * This will also be called for: $arr[$key] = $value
150     *
151     * @param int|string $key The key of the element to be fetched.
152     * @param object $value The element to be assigned.
153     * @return void
154     * @throws \ErrorException Invalid type for key.
155     * @throws \ErrorException Invalid type for value.
156     * @throws \ErrorException Non-existing key.
157     * @todo need to add return type void (require update php version to 7.1)
158     */
159    #[\ReturnTypeWillChange]
160    public function offsetSet($key, $value)
161    {
162        $this->checkKey($this->key_type, $key);
163
164        switch ($this->value_type) {
165            case GPBType::SFIXED32:
166            case GPBType::SINT32:
167            case GPBType::INT32:
168            case GPBType::ENUM:
169                GPBUtil::checkInt32($value);
170                break;
171            case GPBType::FIXED32:
172            case GPBType::UINT32:
173                GPBUtil::checkUint32($value);
174                break;
175            case GPBType::SFIXED64:
176            case GPBType::SINT64:
177            case GPBType::INT64:
178                GPBUtil::checkInt64($value);
179                break;
180            case GPBType::FIXED64:
181            case GPBType::UINT64:
182                GPBUtil::checkUint64($value);
183                break;
184            case GPBType::FLOAT:
185                GPBUtil::checkFloat($value);
186                break;
187            case GPBType::DOUBLE:
188                GPBUtil::checkDouble($value);
189                break;
190            case GPBType::BOOL:
191                GPBUtil::checkBool($value);
192                break;
193            case GPBType::STRING:
194                GPBUtil::checkString($value, true);
195                break;
196            case GPBType::MESSAGE:
197                if (is_null($value)) {
198                  trigger_error("Map element cannot be null.", E_USER_ERROR);
199                }
200                GPBUtil::checkMessage($value, $this->klass);
201                break;
202            default:
203                break;
204        }
205
206        $this->container[$key] = $value;
207    }
208
209    /**
210     * Remove the element at the given key.
211     *
212     * This will also be called for: unset($arr)
213     *
214     * @param int|string $key The key of the element to be removed.
215     * @return void
216     * @throws \ErrorException Invalid type for key.
217     * @todo need to add return type void (require update php version to 7.1)
218     */
219    #[\ReturnTypeWillChange]
220    public function offsetUnset($key)
221    {
222        $this->checkKey($this->key_type, $key);
223        unset($this->container[$key]);
224    }
225
226    /**
227     * Check the existence of the element at the given key.
228     *
229     * This will also be called for: isset($arr)
230     *
231     * @param int|string $key The key of the element to be removed.
232     * @return bool True if the element at the given key exists.
233     * @throws \ErrorException Invalid type for key.
234     */
235    public function offsetExists($key): bool
236    {
237        $this->checkKey($this->key_type, $key);
238        return isset($this->container[$key]);
239    }
240
241    /**
242     * @ignore
243     */
244    public function getIterator(): Traversable
245    {
246        return new MapFieldIter($this->container, $this->key_type);
247    }
248
249    /**
250     * Return the number of stored elements.
251     *
252     * This will also be called for: count($arr)
253     *
254     * @return integer The number of stored elements.
255     */
256    public function count(): int
257    {
258        return count($this->container);
259    }
260
261    /**
262     * @ignore
263     */
264    private function checkKey($key_type, &$key)
265    {
266        switch ($key_type) {
267            case GPBType::SFIXED32:
268            case GPBType::SINT32:
269            case GPBType::INT32:
270                GPBUtil::checkInt32($key);
271                break;
272            case GPBType::FIXED32:
273            case GPBType::UINT32:
274                GPBUtil::checkUint32($key);
275                break;
276            case GPBType::SFIXED64:
277            case GPBType::SINT64:
278            case GPBType::INT64:
279                GPBUtil::checkInt64($key);
280                break;
281            case GPBType::FIXED64:
282            case GPBType::UINT64:
283                GPBUtil::checkUint64($key);
284                break;
285            case GPBType::BOOL:
286                GPBUtil::checkBool($key);
287                break;
288            case GPBType::STRING:
289                GPBUtil::checkString($key, true);
290                break;
291            default:
292                trigger_error(
293                    "Given type cannot be map key.",
294                    E_USER_ERROR);
295                break;
296        }
297    }
298}
299