Skip to content

Commit 024528c

Browse files
committed
Rename bottom/top to first/last, refactor
1 parent f4c1c4c commit 024528c

File tree

4 files changed

+65
-118
lines changed

4 files changed

+65
-118
lines changed

ext/collections/collections_deque.c

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,6 @@ static collections_deque *collections_deque_from_object(zend_object *obj)
139139

140140
#define Z_DEQUE_P(zv) collections_deque_from_object(Z_OBJ_P((zv)))
141141

142-
/* Helps enforce the invariants in debug mode:
143-
* - if size == 0, then circular_buffer == NULL
144-
* - if size > 0, then circular_buffer != NULL
145-
* - size is not less than 0
146-
*/
147-
static bool collections_deque_entries_empty_size(const collections_deque_entries *array)
148-
{
149-
DEBUG_ASSERT_CONSISTENT_DEQUE(array);
150-
return array->size == 0;
151-
}
152-
153142
static bool collections_deque_entries_empty_capacity(const collections_deque_entries *array)
154143
{
155144
DEBUG_ASSERT_CONSISTENT_DEQUE(array);
@@ -760,6 +749,7 @@ static zend_array* collections_deque_to_new_array(const collections_deque_entrie
760749
do {
761750
Z_TRY_ADDREF_P(p);
762751
ZEND_HASH_FILL_ADD(p);
752+
p++;
763753
if (p == end) {
764754
p = circular_buffer;
765755
}
@@ -769,20 +759,6 @@ static zend_array* collections_deque_to_new_array(const collections_deque_entrie
769759
return values;
770760
}
771761

772-
PHP_METHOD(Collections_Deque, __serialize)
773-
{
774-
ZEND_PARSE_PARAMETERS_NONE();
775-
776-
collections_deque *intern = Z_DEQUE_P(ZEND_THIS);
777-
778-
if (collections_deque_entries_empty_size(&intern->array)) {
779-
RETURN_EMPTY_ARRAY();
780-
}
781-
/* Unlike FixedArray, there's no setSize, so there's no reason to delete indexes */
782-
783-
RETURN_ARR(collections_deque_to_new_array(&intern->array));
784-
}
785-
786762
PHP_METHOD(Collections_Deque, toArray)
787763
{
788764
ZEND_PARSE_PARAMETERS_NONE();
@@ -1087,14 +1063,14 @@ PHP_METHOD(Collections_Deque, pop)
10871063
collections_deque_try_shrink_capacity(intern, old_size);
10881064
}
10891065

1090-
PHP_METHOD(Collections_Deque, top)
1066+
PHP_METHOD(Collections_Deque, last)
10911067
{
10921068
ZEND_PARSE_PARAMETERS_NONE();
10931069

10941070
const collections_deque *intern = Z_DEQUE_P(ZEND_THIS);
10951071
const size_t old_size = intern->array.size;
10961072
if (old_size == 0) {
1097-
zend_throw_exception(spl_ce_UnderflowException, "Cannot read top of empty Collections\\Deque", 0);
1073+
zend_throw_exception(spl_ce_UnderflowException, "Cannot read last value of empty Collections\\Deque", 0);
10981074
RETURN_THROWS();
10991075
}
11001076

@@ -1126,14 +1102,14 @@ PHP_METHOD(Collections_Deque, shift)
11261102
collections_deque_try_shrink_capacity(intern, old_size);
11271103
}
11281104

1129-
PHP_METHOD(Collections_Deque, bottom)
1105+
PHP_METHOD(Collections_Deque, first)
11301106
{
11311107
ZEND_PARSE_PARAMETERS_NONE();
11321108

11331109
const collections_deque *intern = Z_DEQUE_P(ZEND_THIS);
11341110
DEBUG_ASSERT_CONSISTENT_DEQUE(&intern->array);
11351111
if (intern->array.size == 0) {
1136-
zend_throw_exception(spl_ce_UnderflowException, "Cannot read bottom of empty Collections\\Deque", 0);
1112+
zend_throw_exception(spl_ce_UnderflowException, "Cannot read first value of empty Collections\\Deque", 0);
11371113
RETURN_THROWS();
11381114
}
11391115

@@ -1152,45 +1128,6 @@ PHP_METHOD(Collections_Deque, offsetUnset)
11521128
RETURN_THROWS();
11531129
}
11541130

1155-
static void collections_deque_return_list(zval *return_value, const collections_deque *intern)
1156-
{
1157-
// Can't use collections_convert_zval_list_to_php_array_list(return_value, intern->array.circular_buffer, intern->array.size) for deque.
1158-
const size_t len = intern->array.size;
1159-
if (!len) {
1160-
RETURN_EMPTY_ARRAY();
1161-
}
1162-
ZEND_ASSERT(intern->array.mask > 0);
1163-
1164-
zend_array *values = zend_new_array(len);
1165-
/* Initialize return array */
1166-
zend_hash_real_init_packed(values);
1167-
1168-
zval *const from_buffer_start = intern->array.circular_buffer;
1169-
zval *from_begin = &from_buffer_start[intern->array.offset];
1170-
zval *const from_end = &from_buffer_start[intern->array.mask + 1];
1171-
ZEND_ASSERT(from_begin <= from_end);
1172-
/* Go through values and add values to the return array */
1173-
ZEND_HASH_FILL_PACKED(values) {
1174-
for (size_t i = 0; i < len; i++) {
1175-
if (from_begin == from_end) {
1176-
from_begin = from_buffer_start;
1177-
}
1178-
Z_TRY_ADDREF_P(from_begin);
1179-
ZEND_HASH_FILL_ADD(from_begin);
1180-
from_begin++;
1181-
}
1182-
} ZEND_HASH_FILL_END();
1183-
RETURN_ARR(values);
1184-
}
1185-
1186-
PHP_METHOD(Collections_Deque, jsonSerialize)
1187-
{
1188-
/* json_encoder.c will always encode objects as {"0":..., "1":...}, and detects recursion if an object returns its internal property array, so we have to return a new array */
1189-
ZEND_PARSE_PARAMETERS_NONE();
1190-
collections_deque *intern = Z_DEQUE_P(ZEND_THIS);
1191-
collections_deque_return_list(return_value, intern);
1192-
}
1193-
11941131
PHP_MINIT_FUNCTION(collections_deque)
11951132
{
11961133
collections_ce_Deque = register_class_Collections_Deque(zend_ce_aggregate, zend_ce_countable, php_json_serializable_ce, zend_ce_arrayaccess);

ext/collections/collections_deque.stub.php

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,21 @@
1313
*
1414
* See https://en.wikipedia.org/wiki/Double-ended_queue
1515
*
16-
* This supports amortized constant time pushing and popping onto the front or back of the array.
16+
* This supports amortized constant time pushing and popping onto the start (i.e. start, first)
17+
* or back (i.e. end, last) of the Deque.
1718
*
18-
* Naming is based on https://www.php.net/spldoublylinkedlist
19-
* and on array_push/pop/unshift/shift.
19+
* Method naming is based on https://www.php.net/spldoublylinkedlist
20+
* and on array_push/pop/unshift/shift/ and array_key_first/array_key_last.
2021
*/
2122
final class Deque implements IteratorAggregate, Countable, JsonSerializable, ArrayAccess
2223
{
2324
/** Construct the Deque from the values of the Traversable/array, ignoring keys */
2425
public function __construct(iterable $iterator = []) {}
2526
/**
26-
* Returns an iterator that accounts for calls to shift/unshift tracking the position of the front of the Deque.
27+
* Returns an iterator that accounts for calls to shift/unshift tracking the position of the start of the Deque.
2728
* Calls to shift/unshift will do the following:
2829
* - Increase/Decrease the value returned by the iterator's key()
29-
* by the number of elements added/removed to/from the front of the Deque.
30+
* by the number of elements added/removed to/from the start of the Deque.
3031
* (`$deque[$iteratorKey] === $iteratorValue` at the time the key and value are returned).
3132
* - Repeated calls to shift will cause valid() to return false if the iterator's
3233
* position ends up before the start of the Deque at the time iteration resumes.
@@ -40,6 +41,7 @@ public function isEmpty(): bool {}
4041
/** Removes all elements from the Deque. */
4142
public function clear(): void {}
4243

44+
/** @implementation-alias Collections\Deque::toArray */
4345
public function __serialize(): array {}
4446
public function __unserialize(array $data): void {}
4547
/** Construct the Deque from the values of the array, ignoring keys */
@@ -51,27 +53,35 @@ public function push(mixed ...$values): void {}
5153
public function unshift(mixed ...$values): void {}
5254
/**
5355
* Pops a value from the end of the Deque.
54-
* @throws UnderflowException if the Deque is empty
56+
* @throws \UnderflowException if the Deque is empty
5557
*/
5658
public function pop(): mixed {}
5759
/**
58-
* Shifts a value from the front of the Deque.
59-
* @throws UnderflowException if the Deque is empty
60+
* Shifts a value from the start of the Deque.
61+
* @throws \UnderflowException if the Deque is empty
6062
*/
6163
public function shift(): mixed {}
6264

63-
/** Peeks at the value at the start of the Deque, throws if empty */
64-
public function bottom(): mixed {}
65-
/** Peeks at the value at the end of the Deque, throws if empty */
66-
public function top(): mixed {}
65+
/**
66+
* Peeks at the value at the start of the Deque.
67+
* @throws \UnderflowException if the Deque is empty
68+
*/
69+
public function first(): mixed {}
70+
/**
71+
* Peeks at the value at the end of the Deque.
72+
* @throws \UnderflowException if the Deque is empty
73+
*/
74+
public function last(): mixed {}
6775

68-
/** Returns a list of the elements from front to back. */
76+
/**
77+
* Returns a list of the elements from the start to the end.
78+
*/
6979
public function toArray(): array {}
7080

7181
// Must be mixed for compatibility with ArrayAccess
7282
/**
7383
* Returns the value at offset (int)$offset (relative to the start of the Deque)
74-
* @throws OutOfBoundsException if the value of (int)$offset is not within the bounds of this vector
84+
* @throws \OutOfBoundsException if the value of (int)$offset is not within the bounds of this vector
7585
*/
7686
public function offsetGet(mixed $offset): mixed {}
7787
/**
@@ -80,15 +90,17 @@ public function offsetGet(mixed $offset): mixed {}
8090
public function offsetExists(mixed $offset): bool {}
8191
/**
8292
* Sets the value at offset $offset (relative to the start of the Deque) to $value
83-
* @throws OutOfBoundsException if the value of (int)$offset is not within the bounds of this vector
93+
* @throws \OutOfBoundsException if the value of (int)$offset is not within the bounds of this vector
8494
*/
8595
public function offsetSet(mixed $offset, mixed $value): void {}
86-
/** Throws unconditionally */
8796
/**
88-
* @throws RuntimeException unconditionally because unset and null are different things, unlike SplFixedArray
97+
* @throws \RuntimeException unconditionally because unset and null are different things, unlike SplFixedArray
8998
*/
9099
public function offsetUnset(mixed $offset): void {}
91100

92-
/** This is JSON serialized as a JSON array with elements from front to back */
101+
/**
102+
* This is JSON serialized as a JSON array with elements from the start to the end.
103+
* @implementation-alias Collections\Deque::toArray
104+
*/
93105
public function jsonSerialize(): array {}
94106
}

ext/collections/collections_deque_arginfo.h

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 45133ac6c134170e67c0b2dadef7c8be8b540608 */
2+
* Stub hash: 756fbecba961c8eab34df811f39ab01e1f58b19d */
33

44
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Collections_Deque___construct, 0, 0, 0)
55
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, iterator, IS_ITERABLE, 0, "[]")
@@ -39,9 +39,9 @@ ZEND_END_ARG_INFO()
3939

4040
#define arginfo_class_Collections_Deque_shift arginfo_class_Collections_Deque_pop
4141

42-
#define arginfo_class_Collections_Deque_bottom arginfo_class_Collections_Deque_pop
42+
#define arginfo_class_Collections_Deque_first arginfo_class_Collections_Deque_pop
4343

44-
#define arginfo_class_Collections_Deque_top arginfo_class_Collections_Deque_pop
44+
#define arginfo_class_Collections_Deque_last arginfo_class_Collections_Deque_pop
4545

4646
#define arginfo_class_Collections_Deque_toArray arginfo_class_Collections_Deque___serialize
4747

@@ -70,21 +70,19 @@ ZEND_METHOD(Collections_Deque, getIterator);
7070
ZEND_METHOD(Collections_Deque, count);
7171
ZEND_METHOD(Collections_Deque, isEmpty);
7272
ZEND_METHOD(Collections_Deque, clear);
73-
ZEND_METHOD(Collections_Deque, __serialize);
73+
ZEND_METHOD(Collections_Deque, toArray);
7474
ZEND_METHOD(Collections_Deque, __unserialize);
7575
ZEND_METHOD(Collections_Deque, __set_state);
7676
ZEND_METHOD(Collections_Deque, push);
7777
ZEND_METHOD(Collections_Deque, unshift);
7878
ZEND_METHOD(Collections_Deque, pop);
7979
ZEND_METHOD(Collections_Deque, shift);
80-
ZEND_METHOD(Collections_Deque, bottom);
81-
ZEND_METHOD(Collections_Deque, top);
82-
ZEND_METHOD(Collections_Deque, toArray);
80+
ZEND_METHOD(Collections_Deque, first);
81+
ZEND_METHOD(Collections_Deque, last);
8382
ZEND_METHOD(Collections_Deque, offsetGet);
8483
ZEND_METHOD(Collections_Deque, offsetExists);
8584
ZEND_METHOD(Collections_Deque, offsetSet);
8685
ZEND_METHOD(Collections_Deque, offsetUnset);
87-
ZEND_METHOD(Collections_Deque, jsonSerialize);
8886

8987

9088
static const zend_function_entry class_Collections_Deque_methods[] = {
@@ -93,21 +91,21 @@ static const zend_function_entry class_Collections_Deque_methods[] = {
9391
ZEND_ME(Collections_Deque, count, arginfo_class_Collections_Deque_count, ZEND_ACC_PUBLIC)
9492
ZEND_ME(Collections_Deque, isEmpty, arginfo_class_Collections_Deque_isEmpty, ZEND_ACC_PUBLIC)
9593
ZEND_ME(Collections_Deque, clear, arginfo_class_Collections_Deque_clear, ZEND_ACC_PUBLIC)
96-
ZEND_ME(Collections_Deque, __serialize, arginfo_class_Collections_Deque___serialize, ZEND_ACC_PUBLIC)
94+
ZEND_MALIAS(Collections_Deque, __serialize, toArray, arginfo_class_Collections_Deque___serialize, ZEND_ACC_PUBLIC)
9795
ZEND_ME(Collections_Deque, __unserialize, arginfo_class_Collections_Deque___unserialize, ZEND_ACC_PUBLIC)
9896
ZEND_ME(Collections_Deque, __set_state, arginfo_class_Collections_Deque___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
9997
ZEND_ME(Collections_Deque, push, arginfo_class_Collections_Deque_push, ZEND_ACC_PUBLIC)
10098
ZEND_ME(Collections_Deque, unshift, arginfo_class_Collections_Deque_unshift, ZEND_ACC_PUBLIC)
10199
ZEND_ME(Collections_Deque, pop, arginfo_class_Collections_Deque_pop, ZEND_ACC_PUBLIC)
102100
ZEND_ME(Collections_Deque, shift, arginfo_class_Collections_Deque_shift, ZEND_ACC_PUBLIC)
103-
ZEND_ME(Collections_Deque, bottom, arginfo_class_Collections_Deque_bottom, ZEND_ACC_PUBLIC)
104-
ZEND_ME(Collections_Deque, top, arginfo_class_Collections_Deque_top, ZEND_ACC_PUBLIC)
101+
ZEND_ME(Collections_Deque, first, arginfo_class_Collections_Deque_first, ZEND_ACC_PUBLIC)
102+
ZEND_ME(Collections_Deque, last, arginfo_class_Collections_Deque_last, ZEND_ACC_PUBLIC)
105103
ZEND_ME(Collections_Deque, toArray, arginfo_class_Collections_Deque_toArray, ZEND_ACC_PUBLIC)
106104
ZEND_ME(Collections_Deque, offsetGet, arginfo_class_Collections_Deque_offsetGet, ZEND_ACC_PUBLIC)
107105
ZEND_ME(Collections_Deque, offsetExists, arginfo_class_Collections_Deque_offsetExists, ZEND_ACC_PUBLIC)
108106
ZEND_ME(Collections_Deque, offsetSet, arginfo_class_Collections_Deque_offsetSet, ZEND_ACC_PUBLIC)
109107
ZEND_ME(Collections_Deque, offsetUnset, arginfo_class_Collections_Deque_offsetUnset, ZEND_ACC_PUBLIC)
110-
ZEND_ME(Collections_Deque, jsonSerialize, arginfo_class_Collections_Deque_jsonSerialize, ZEND_ACC_PUBLIC)
108+
ZEND_MALIAS(Collections_Deque, jsonSerialize, toArray, arginfo_class_Collections_Deque_jsonSerialize, ZEND_ACC_PUBLIC)
111109
ZEND_FE_END
112110
};
113111

ext/collections/tests/Deque/top.phpt

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Collections\Deque top()/bottom()
2+
Collections\Deque last()/first()
33
--FILE--
44
<?php
55

@@ -13,32 +13,32 @@ function expect_throws(Closure $cb): void {
1313
}
1414

1515
$it = new Collections\Deque();
16-
expect_throws(fn () => $it->bottom());
17-
expect_throws(fn () => $it->top());
16+
expect_throws(fn () => $it->first());
17+
expect_throws(fn () => $it->last());
1818
for ($i = 0; $i <= 3; $i++) {
19-
$it->push("top$i");
20-
$it->unshift("bottom$i");
19+
$it->push("last$i");
20+
$it->unshift("first$i");
2121
}
22-
var_dump($it->bottom());
23-
var_dump($it->top());
22+
echo $it->first(), "\n";
23+
echo $it->last(), "\n";
2424
echo "Removing elements\n";
25-
var_dump($it->shift());
26-
var_dump($it->pop());
25+
echo $it->shift(), "\n";
26+
echo $it->pop(), "\n";
2727
echo "Inspecting elements after removal\n";
28-
var_dump($it->bottom());
29-
var_dump($it->top());
28+
echo $it->first(), "\n";
29+
echo $it->last(), "\n";
3030
printf("count=%d values=%s\n", $it->count(), json_encode($it));
3131

3232
?>
3333
--EXPECT--
34-
Caught UnderflowException: Cannot read bottom of empty Collections\Deque
35-
Caught UnderflowException: Cannot read top of empty Collections\Deque
36-
string(7) "bottom3"
37-
string(4) "top3"
34+
Caught UnderflowException: Cannot read first value of empty Collections\Deque
35+
Caught UnderflowException: Cannot read last value of empty Collections\Deque
36+
first3
37+
last3
3838
Removing elements
39-
string(7) "bottom3"
40-
string(4) "top3"
39+
first3
40+
last3
4141
Inspecting elements after removal
42-
string(7) "bottom2"
43-
string(4) "top2"
44-
count=6 values=["bottom2","bottom1","bottom0","top0","top1","top2"]
42+
first2
43+
last2
44+
count=6 values=["first2","first1","first0","last0","last1","last2"]

0 commit comments

Comments
 (0)