- if (PL_op->op_private & OPpTRANS_SQUASH) {
- UV pch = 0xfeedface;
- while (s < send) {
- STRLEN len;
- const UV comp = utf8n_to_uvchr(s, send - s, &len,
- UTF8_ALLOW_DEFAULT);
- UV ch;
- short sch;
-
- if (comp > 0xff) {
- if (!complement) {
- Move(s, d, len, U8);
- d += len;
- }
- else {
- /* use the implicit 0x100..0x7fffffff search range */
- matches++;
- ch = del
- /* setting ch to pch forces char to be deleted */
- ? ((excess >= (IV)comp - 0xff) ? (UV)tbl[comp+2]
- : pch )
-
- : ( (excess == -1) ? comp :
- (UV)(( excess == 0
- || excess < (IV)comp - 0xff) ? tbl[0x101]
- : tbl[comp+2]
- )
- );
- if (ch != pch) {
- d = uvchr_to_utf8(d, ch);
- pch = ch;
- }
- s += len;
- continue;
- }
- }
- else if ((sch = tbl[comp]) >= 0) {
- ch = (UV)sch;
- matches++;
- if (ch != pch) {
- d = uvchr_to_utf8(d, ch);
- pch = ch;
- }
- s += len;
- continue;
- }
- else if (sch == -1) { /* -1 is unmapped character */
- Move(s, d, len, U8);
- d += len;
- }
- else if (sch == -2) /* -2 is delete character */
- matches++;
- s += len;
- pch = 0xfeedface;
- }
- }
- else {
- while (s < send) {
- STRLEN len;
- const UV comp = utf8n_to_uvchr(s, send - s, &len,
- UTF8_ALLOW_DEFAULT);
- UV ch;
- short sch;
- if (comp > 0xff) {
- if (!complement) {
- Move(s, d, len, U8);
- d += len;
- }
- else {
- /* use the implicit 0x100..0x7fffffff search range */
- matches++;
- if (del) {
- if (excess >= (IV)comp - 0xff) {
- ch = (UV)tbl[comp+2];
- d = uvchr_to_utf8(d, ch);
- }
- }
- else {
- /* tr/...//c should call S_do_trans_count
- * instead */
- assert(excess != -1);
- ch = (UV)( excess == 0
- || excess < (IV)comp-0xff) ? tbl[0x101]
- : tbl[comp+2];
- d = uvchr_to_utf8(d, ch);
- }
- }
- }
- else if ((sch = tbl[comp]) >= 0) {
- d = uvchr_to_utf8(d, (UV)sch);
- matches++;
- }
- else if (sch == -1) { /* -1 is unmapped character */
- Move(s, d, len, U8);
- d += len;
- }
- else if (sch == -2) /* -2 is delete character */
- matches++;
- s += len;
- }
- }
+ while (s < send) {
+ STRLEN len;
+ const UV comp = utf8n_to_uvchr(s, send - s, &len,
+ UTF8_ALLOW_DEFAULT);
+ UV ch;
+ short sch;
+
+ sch = tbl->map[comp >= size ? size : comp];
+
+ if (sch >= 0) {
+ ch = (UV)sch;
+ replace:
+ matches++;
+ if (LIKELY(!squash || ch != pch)) {
+ d = uvchr_to_utf8(d, ch);
+ pch = ch;
+ }
+ s += len;
+ continue;
+ }
+ else if (sch == -1) { /* -1 is unmapped character */
+ Move(s, d, len, U8);
+ d += len;
+ }
+ else if (sch == -2) /* -2 is delete character */
+ matches++;
+ else {
+ assert(sch == -3); /* -3 is empty replacement */
+ ch = comp;
+ goto replace;
+ }
+
+ s += len;
+ pch = 0xfeedface;
+ }
+