blob: ec7a3a6d0791b04da1f45410375ec09fb828b62d [file] [log] [blame]
avm9996399bb77c2020-01-27 03:15:08 +01001<?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;
42
43/**
44 * RepeatedField is used by generated protocol message classes to manipulate
45 * repeated fields. It can be used like native PHP array.
46 */
47class RepeatedField implements \ArrayAccess, \IteratorAggregate, \Countable
48{
49
50 /**
51 * @ignore
52 */
53 private $container;
54 /**
55 * @ignore
56 */
57 private $type;
58 /**
59 * @ignore
60 */
61 private $klass;
62 /**
63 * @ignore
64 */
65 private $legacy_klass;
66
67 /**
68 * Constructs an instance of RepeatedField.
69 *
70 * @param long $type Type of the stored element.
71 * @param string $klass Message/Enum class name (message/enum fields only).
72 * @ignore
73 */
74 public function __construct($type, $klass = null)
75 {
76 $this->container = [];
77 $this->type = $type;
78 if ($this->type == GPBType::MESSAGE) {
79 $pool = DescriptorPool::getGeneratedPool();
80 $desc = $pool->getDescriptorByClassName($klass);
81 if ($desc == NULL) {
82 new $klass; // No msg class instance has been created before.
83 $desc = $pool->getDescriptorByClassName($klass);
84 }
85 $this->klass = $desc->getClass();
86 $this->legacy_klass = $desc->getLegacyClass();
87 }
88 }
89
90 /**
91 * @ignore
92 */
93 public function getType()
94 {
95 return $this->type;
96 }
97
98 /**
99 * @ignore
100 */
101 public function getClass()
102 {
103 return $this->klass;
104 }
105
106 /**
107 * @ignore
108 */
109 public function getLegacyClass()
110 {
111 return $this->legacy_klass;
112 }
113
114 /**
115 * Return the element at the given index.
116 *
117 * This will also be called for: $ele = $arr[0]
118 *
119 * @param long $offset The index of the element to be fetched.
120 * @return object The stored element at given index.
121 * @throws \ErrorException Invalid type for index.
122 * @throws \ErrorException Non-existing index.
123 */
124 public function offsetGet($offset)
125 {
126 return $this->container[$offset];
127 }
128
129 /**
130 * Assign the element at the given index.
131 *
132 * This will also be called for: $arr []= $ele and $arr[0] = ele
133 *
134 * @param long $offset The index of the element to be assigned.
135 * @param object $value The element to be assigned.
136 * @return void
137 * @throws \ErrorException Invalid type for index.
138 * @throws \ErrorException Non-existing index.
139 * @throws \ErrorException Incorrect type of the element.
140 */
141 public function offsetSet($offset, $value)
142 {
143 switch ($this->type) {
144 case GPBType::SFIXED32:
145 case GPBType::SINT32:
146 case GPBType::INT32:
147 case GPBType::ENUM:
148 GPBUtil::checkInt32($value);
149 break;
150 case GPBType::FIXED32:
151 case GPBType::UINT32:
152 GPBUtil::checkUint32($value);
153 break;
154 case GPBType::SFIXED64:
155 case GPBType::SINT64:
156 case GPBType::INT64:
157 GPBUtil::checkInt64($value);
158 break;
159 case GPBType::FIXED64:
160 case GPBType::UINT64:
161 GPBUtil::checkUint64($value);
162 break;
163 case GPBType::FLOAT:
164 GPBUtil::checkFloat($value);
165 break;
166 case GPBType::DOUBLE:
167 GPBUtil::checkDouble($value);
168 break;
169 case GPBType::BOOL:
170 GPBUtil::checkBool($value);
171 break;
172 case GPBType::BYTES:
173 GPBUtil::checkString($value, false);
174 break;
175 case GPBType::STRING:
176 GPBUtil::checkString($value, true);
177 break;
178 case GPBType::MESSAGE:
179 if (is_null($value)) {
180 trigger_error("RepeatedField element cannot be null.",
181 E_USER_ERROR);
182 }
183 GPBUtil::checkMessage($value, $this->klass);
184 break;
185 default:
186 break;
187 }
188 if (is_null($offset)) {
189 $this->container[] = $value;
190 } else {
191 $count = count($this->container);
192 if (!is_numeric($offset) || $offset < 0 || $offset >= $count) {
193 trigger_error(
194 "Cannot modify element at the given index",
195 E_USER_ERROR);
196 return;
197 }
198 $this->container[$offset] = $value;
199 }
200 }
201
202 /**
203 * Remove the element at the given index.
204 *
205 * This will also be called for: unset($arr)
206 *
207 * @param long $offset The index of the element to be removed.
208 * @return void
209 * @throws \ErrorException Invalid type for index.
210 * @throws \ErrorException The element to be removed is not at the end of the
211 * RepeatedField.
212 */
213 public function offsetUnset($offset)
214 {
215 $count = count($this->container);
216 if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) {
217 trigger_error(
218 "Cannot remove element at the given index",
219 E_USER_ERROR);
220 return;
221 }
222 array_pop($this->container);
223 }
224
225 /**
226 * Check the existence of the element at the given index.
227 *
228 * This will also be called for: isset($arr)
229 *
230 * @param long $offset The index of the element to be removed.
231 * @return bool True if the element at the given offset exists.
232 * @throws \ErrorException Invalid type for index.
233 */
234 public function offsetExists($offset)
235 {
236 return isset($this->container[$offset]);
237 }
238
239 /**
240 * @ignore
241 */
242 public function getIterator()
243 {
244 return new RepeatedFieldIter($this->container);
245 }
246
247 /**
248 * Return the number of stored elements.
249 *
250 * This will also be called for: count($arr)
251 *
252 * @return integer The number of stored elements.
253 */
254 public function count()
255 {
256 return count($this->container);
257 }
258}