@@ -51,70 +51,87 @@ private function equals32(int $a, int $b): bool {
51
51
/** Compresses a fragment and returns last emitted position */
52
52
private function fragment () {
53
53
$ end = min (strlen ($ this ->buffer ), Snappy::BLOCK_SIZE );
54
- if ($ end <= Snappy::INPUT_MARGIN ) return 0 ;
55
-
56
54
$ pos = $ emit = 0 ;
57
- $ bits = 1 ;
58
- while ((1 << $ bits ) <= $ end && $ bits <= Snappy::HASH_BITS ) {
59
- $ bits ++;
60
- }
61
- $ bits --;
62
- $ shift = 32 - $ bits ;
63
- $ hashtable = array_fill (0 , 1 << $ bits , 0 );
64
-
65
- $ start = $ pos ;
66
- $ limit = $ end - Snappy::INPUT_MARGIN ;
67
- $ next = ((unpack ('V ' , $ this ->buffer , ++$ pos )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
68
-
69
- // Emit literals
70
- next: $ forward = $ pos ;
71
- $ skip = 32 ;
72
- do {
73
- $ pos = $ forward ;
74
- $ hash = $ next ;
75
- $ forward += ($ skip & 0xffffffff ) >> 5 ;
76
- $ skip ++;
77
- if ($ pos > $ limit ) return $ emit ;
78
-
79
- $ next = ((unpack ('V ' , $ this ->buffer , $ forward )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
80
- $ candidate = $ start + $ hashtable [$ hash ];
81
- $ hashtable [$ hash ]= ($ pos - $ start ) & 0xffff ;
82
- } while (!$ this ->equals32 ($ pos , $ candidate ));
83
-
84
- $ this ->out ->write ($ this ->literal ($ pos - $ emit ).substr ($ this ->buffer , $ emit , $ pos - $ emit ));
85
-
86
- // Emit copy instructions
87
- do {
88
- $ offset = $ pos - $ candidate ;
89
- $ matched = 4 ;
90
- while ($ pos + $ matched < $ end && $ this ->buffer [$ pos + $ matched ] === $ this ->buffer [$ candidate + $ matched ]) {
91
- $ matched ++;
92
- }
93
- $ pos += $ matched ;
55
+ $ out = '' ;
94
56
95
- while ($ matched >= 68 ) {
96
- $ this ->out ->write ($ this ->copy ($ offset , 64 ));
97
- $ matched -= 64 ;
98
- }
99
- if ($ matched > 64 ) {
100
- $ this ->out ->write ($ this ->copy ($ offset , 60 ));
101
- $ matched -= 60 ;
102
- }
103
- $ this ->out ->write ($ this ->copy ($ offset , $ matched ));
104
- $ emit = $ pos ;
57
+ // Compare 4-byte offsets in data at offsets a and b
58
+ $ equals32 = fn ($ a , $ b ) => (
59
+ $ this ->buffer [$ a ] === $ this ->buffer [$ b ] &&
60
+ $ this ->buffer [$ a + 1 ] === $ this ->buffer [$ b + 1 ] &&
61
+ $ this ->buffer [$ a + 2 ] === $ this ->buffer [$ b + 2 ] &&
62
+ $ this ->buffer [$ a + 3 ] === $ this ->buffer [$ b + 3 ]
63
+ );
105
64
106
- if ($ pos >= $ limit ) return $ emit ;
65
+ if ($ end >= Snappy::INPUT_MARGIN ) {
66
+ $ bits = 1 ;
67
+ while ((1 << $ bits ) <= $ end && $ bits <= Snappy::HASH_BITS ) {
68
+ $ bits ++;
69
+ }
70
+ $ bits --;
71
+ $ shift = 32 - $ bits ;
72
+ $ hashtable = array_fill (0 , 1 << $ bits , 0 );
73
+
74
+ $ start = $ pos ;
75
+ $ limit = $ end - Snappy::INPUT_MARGIN ;
76
+ $ next = ((unpack ('V ' , $ this ->buffer , ++$ pos )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
77
+
78
+ // Emit literals
79
+ next: $ forward = $ pos ;
80
+ $ skip = 32 ;
81
+ do {
82
+ $ pos = $ forward ;
83
+ $ hash = $ next ;
84
+ $ forward += ($ skip & 0xffffffff ) >> 5 ;
85
+ $ skip ++;
86
+ if ($ pos > $ limit || $ forward > $ limit ) goto emit;
87
+
88
+ $ next = ((unpack ('V ' , $ this ->buffer , $ forward )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
89
+ $ candidate = $ start + $ hashtable [$ hash ];
90
+ $ hashtable [$ hash ]= ($ pos - $ start ) & 0xffff ;
91
+ } while (!$ equals32 ($ pos , $ candidate ));
92
+
93
+ $ out .= $ this ->literal ($ pos - $ emit ).substr ($ this ->buffer , $ emit , $ pos - $ emit );
94
+
95
+ // Emit copy instructions
96
+ do {
97
+ $ offset = $ pos - $ candidate ;
98
+ $ matched = 4 ;
99
+ while ($ pos + $ matched < $ end && $ this ->buffer [$ pos + $ matched ] === $ this ->buffer [$ candidate + $ matched ]) {
100
+ $ matched ++;
101
+ }
102
+ $ pos += $ matched ;
103
+
104
+ while ($ matched >= 68 ) {
105
+ $ out .= $ this ->copy ($ offset , 64 );
106
+ $ matched -= 64 ;
107
+ }
108
+ if ($ matched > 64 ) {
109
+ $ out .= $ this ->copy ($ offset , 60 );
110
+ $ matched -= 60 ;
111
+ }
112
+ $ out .= $ this ->copy ($ offset , $ matched );
113
+ $ emit = $ pos ;
114
+
115
+ if ($ pos >= $ limit ) goto emit;
116
+
117
+ $ hash = ((unpack ('V ' , $ this ->buffer , $ pos - 1 )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
118
+ $ hashtable [$ hash ]= ($ pos - 1 - $ start ) & 0xffff ;
119
+ $ hash = ((unpack ('V ' , $ this ->buffer , $ pos )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
120
+ $ candidate = $ start + $ hashtable [$ hash ];
121
+ $ hashtable [$ hash ]= ($ pos - $ start ) & 0xffff ;
122
+ } while ($ equals32 ($ pos , $ candidate ));
123
+
124
+ $ pos ++;
125
+ $ next = ((unpack ('V ' , $ this ->buffer , $ pos )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
126
+ goto next;
127
+ }
107
128
108
- $ hash = ((unpack ('V ' , $ this ->buffer , $ pos - 1 )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
109
- $ hashtable [$ hash ]= ($ pos - 1 - $ start ) & 0xffff ;
110
- $ hash = ((unpack ('V ' , $ this ->buffer , $ pos )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
111
- $ candidate = $ start + $ hashtable [$ hash ];
112
- $ hashtable [$ hash ]= ($ pos - $ start ) & 0xffff ;
113
- } while ($ this ->equals32 ($ pos , $ candidate ));
129
+ emit: if ($ emit < $ end ) {
130
+ $ out .= $ this ->literal ($ end - $ emit ).substr ($ this ->buffer , $ emit , $ end - $ emit );
131
+ }
114
132
115
- $ pos ++;
116
- $ next = ((unpack ('V ' , $ this ->buffer , $ pos )[1 ] * Snappy::HASH_KEY ) & 0xffffffff ) >> $ shift ;
117
- goto next;
133
+ $ this ->buffer = substr ($ this ->buffer , $ end );
134
+ return $ out ;
118
135
}
119
136
120
137
/**
@@ -124,20 +141,21 @@ private function fragment() {
124
141
* @return void
125
142
*/
126
143
public function write ($ arg ) {
127
- if (strlen ($ this ->buffer ) <= Snappy::BLOCK_SIZE ) {
128
- $ this ->buffer .= $ arg ;
129
- } else {
130
- $ this ->buffer = substr ($ this ->buffer , $ this ->fragment ());
144
+ $ this ->buffer .= $ arg ;
145
+ if (strlen ($ this ->buffer ) > Snappy::BLOCK_SIZE ) {
146
+ $ this ->out ->write ($ this ->fragment ());
131
147
}
132
148
}
133
149
134
150
/**
135
- * Flush this buffer (except if it's smaller than the input margin)
151
+ * Flush this buffer
136
152
*
137
153
* @return void
138
154
*/
139
155
public function flush () {
140
- $ this ->buffer = substr ($ this ->buffer , $ this ->fragment ());
156
+ if (strlen ($ this ->buffer ) > 0 ) {
157
+ $ this ->out ->write ($ this ->fragment ());
158
+ }
141
159
}
142
160
143
161
/**
@@ -148,15 +166,10 @@ public function flush() {
148
166
* @return void
149
167
*/
150
168
public function close () {
151
- $ end = strlen ($ this ->buffer );
152
- if ($ end > 0 ) {
153
- $ emit = $ this ->fragment ();
154
- if ($ emit < $ end ) {
155
- $ this ->out ->write ($ this ->literal ($ end - $ emit ).substr ($ this ->buffer , $ emit , $ end - $ emit ));
156
- }
169
+ if (strlen ($ this ->buffer ) > 0 ) {
170
+ $ this ->out ->write ($ this ->fragment ());
157
171
$ this ->buffer = '' ;
158
172
}
159
-
160
173
$ this ->out ->close ();
161
174
}
162
175
}
0 commit comments