# define OFF32(p) ((char *) (p))
#endif
-#define PUSH16(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF16(p), SIZE16)
-#define PUSH32(utf8, cur, p) PUSH_BYTES(utf8, cur, OFF32(p), SIZE32)
+#define PUSH16(utf8, cur, p, needs_swap) \
+ PUSH_BYTES(utf8, cur, OFF16(p), SIZE16, needs_swap)
+#define PUSH32(utf8, cur, p, needs_swap) \
+ PUSH_BYTES(utf8, cur, OFF32(p), SIZE32, needs_swap)
#if BYTEORDER == 0x4321 || BYTEORDER == 0x87654321 /* big-endian */
# define NEEDS_SWAP(d) (TYPE_ENDIANNESS(d) == TYPE_IS_LITTLE_ENDIAN)
/* Only to be used inside a loop (see the break) */
#define SHIFT_BYTES(utf8, s, strend, buf, len, datumtype, needs_swap) \
STMT_START { \
- if (utf8) { \
+ if (UNLIKELY(utf8)) { \
if (!uni_to_bytes(aTHX_ &s, strend, \
(char *) (buf), len, datumtype)) break; \
} else { \
- if (needs_swap) \
+ if (UNLIKELY(needs_swap)) \
S_reverse_copy(s, (char *) (buf), len); \
else \
Copy(s, (char *) (buf), len, char); \
#define SHIFT_VAR(utf8, s, strend, var, datumtype, needs_swap) \
SHIFT_BYTES(utf8, s, strend, &(var), sizeof(var), datumtype, needs_swap)
-#define PUSH_VAR(utf8, aptr, var) \
- PUSH_BYTES(utf8, aptr, &(var), sizeof(var))
+#define PUSH_VAR(utf8, aptr, var, needs_swap) \
+ PUSH_BYTES(utf8, aptr, &(var), sizeof(var), needs_swap)
/* Avoid stack overflow due to pathological templates. 100 should be plenty. */
#define MAX_SUB_TEMPLATE_LEVEL 100
# define ENDIANNESS_ALLOWED_TYPES "sSiIlLqQjJfFdDpP("
-# define DO_BO_PACK(var) \
- STMT_START { \
- if (needs_swap) { \
- my_swabn(&var, sizeof(var)); \
- } \
- } STMT_END
-
#define PACK_SIZE_CANNOT_CSUM 0x80
#define PACK_SIZE_UNPREDICTABLE 0x40 /* Not a fixed size element */
#define PACK_SIZE_MASK 0x3F
UTF8_CHECK_ONLY : (UTF8_CHECK_ONLY | UTF8_ALLOW_ANY);
const bool needs_swap = NEEDS_SWAP(datumtype);
- if (needs_swap)
+ if (UNLIKELY(needs_swap))
buf += buf_len;
for (;buf_len > 0; buf_len--) {
bad |= 2;
val &= 0xff;
}
- if (needs_swap)
+ if (UNLIKELY(needs_swap))
*(U8 *)--buf = (U8)val;
else
*(U8 *)buf++ = (U8)val;
}
STATIC char *
-S_bytes_to_uni(const U8 *start, STRLEN len, char *dest) {
- const U8 * const end = start + len;
-
+S_bytes_to_uni(const U8 *start, STRLEN len, char *dest, const bool needs_swap) {
PERL_ARGS_ASSERT_BYTES_TO_UNI;
- while (start < end) {
- const UV uv = NATIVE_TO_ASCII(*start);
- if (UNI_IS_INVARIANT(uv))
- *dest++ = (char)(U8)UTF_TO_NATIVE(uv);
- else {
- *dest++ = (char)(U8)UTF8_EIGHT_BIT_HI(uv);
- *dest++ = (char)(U8)UTF8_EIGHT_BIT_LO(uv);
- }
- start++;
+ if (UNLIKELY(needs_swap)) {
+ const U8 *p = start + len;
+ while (p-- > start) {
+ const UV uv = NATIVE_TO_ASCII(*p);
+ if (UNI_IS_INVARIANT(uv))
+ *dest++ = (char)(U8)UTF_TO_NATIVE(uv);
+ else {
+ *dest++ = (char)(U8)UTF8_EIGHT_BIT_HI(uv);
+ *dest++ = (char)(U8)UTF8_EIGHT_BIT_LO(uv);
+ }
+ }
+ } else {
+ const U8 * const end = start + len;
+ while (start < end) {
+ const UV uv = NATIVE_TO_ASCII(*start);
+ if (UNI_IS_INVARIANT(uv))
+ *dest++ = (char)(U8)UTF_TO_NATIVE(uv);
+ else {
+ *dest++ = (char)(U8)UTF8_EIGHT_BIT_HI(uv);
+ *dest++ = (char)(U8)UTF8_EIGHT_BIT_LO(uv);
+ }
+ start++;
+ }
}
return dest;
}
-#define PUSH_BYTES(utf8, cur, buf, len) \
+#define PUSH_BYTES(utf8, cur, buf, len, needs_swap) \
STMT_START { \
- if (utf8) \
- (cur) = bytes_to_uni((U8 *) buf, len, (cur)); \
+ if (UNLIKELY(utf8)) \
+ (cur) = S_bytes_to_uni((U8 *) buf, len, (cur), needs_swap); \
else { \
- Copy(buf, cur, len, char); \
+ if (UNLIKELY(needs_swap)) \
+ S_reverse_copy((char *)(buf), cur, len); \
+ else \
+ Copy(buf, cur, len, char); \
(cur) += (len); \
} \
} STMT_END
(start) = sv_exp_grow(cat, gl); \
(cur) = (start) + SvCUR(cat); \
} \
- PUSH_BYTES(utf8, cur, buf, glen); \
+ PUSH_BYTES(utf8, cur, buf, glen, 0); \
} STMT_END
#define PUSH_BYTE(utf8, s, byte) \
STMT_START { \
if (utf8) { \
const U8 au8 = (byte); \
- (s) = bytes_to_uni(&au8, 1, (s)); \
+ (s) = S_bytes_to_uni(&au8, 1, (s), 0); \
} else *(U8 *)(s)++ = (byte); \
} STMT_END
len+(endb-buffer)*UTF8_EXPAND);
end = start+SvLEN(cat);
}
- cur = bytes_to_uni(buffer, endb-buffer, cur);
+ cur = S_bytes_to_uni(buffer, endb-buffer, cur, 0);
} else {
if (cur >= end) {
*cur = '\0';
# else
afloat = (float)anv;
# endif
- DO_BO_PACK(afloat);
- PUSH_VAR(utf8, cur, afloat);
+ PUSH_VAR(utf8, cur, afloat, needs_swap);
}
break;
case 'd':
# else
adouble = (double)anv;
# endif
- DO_BO_PACK(adouble);
- PUSH_VAR(utf8, cur, adouble);
+ PUSH_VAR(utf8, cur, adouble, needs_swap);
}
break;
case 'F': {
#else
anv.nv = SvNV(fromstr);
#endif
- DO_BO_PACK(anv);
- PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes));
+ PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes), needs_swap);
}
break;
}
# else
aldouble.ld = (long double)SvNV(fromstr);
# endif
- DO_BO_PACK(aldouble);
- PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes));
+ PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes),
+ needs_swap);
}
break;
}
fromstr = NEXTFROM;
ai16 = (I16)SvIV(fromstr);
ai16 = PerlSock_htons(ai16);
- PUSH16(utf8, cur, &ai16);
+ PUSH16(utf8, cur, &ai16, FALSE);
}
break;
case 'v' | TYPE_IS_SHRIEKING:
fromstr = NEXTFROM;
ai16 = (I16)SvIV(fromstr);
ai16 = htovs(ai16);
- PUSH16(utf8, cur, &ai16);
+ PUSH16(utf8, cur, &ai16, FALSE);
}
break;
case 'S' | TYPE_IS_SHRIEKING:
unsigned short aushort;
fromstr = NEXTFROM;
aushort = SvUV(fromstr);
- DO_BO_PACK(aushort);
- PUSH_VAR(utf8, cur, aushort);
+ PUSH_VAR(utf8, cur, aushort, needs_swap);
}
break;
#else
U16 au16;
fromstr = NEXTFROM;
au16 = (U16)SvUV(fromstr);
- DO_BO_PACK(au16);
- PUSH16(utf8, cur, &au16);
+ PUSH16(utf8, cur, &au16, needs_swap);
}
break;
case 's' | TYPE_IS_SHRIEKING:
short ashort;
fromstr = NEXTFROM;
ashort = SvIV(fromstr);
- DO_BO_PACK(ashort);
- PUSH_VAR(utf8, cur, ashort);
+ PUSH_VAR(utf8, cur, ashort, needs_swap);
}
break;
#else
I16 ai16;
fromstr = NEXTFROM;
ai16 = (I16)SvIV(fromstr);
- DO_BO_PACK(ai16);
- PUSH16(utf8, cur, &ai16);
+ PUSH16(utf8, cur, &ai16, needs_swap);
}
break;
case 'I':
unsigned int auint;
fromstr = NEXTFROM;
auint = SvUV(fromstr);
- DO_BO_PACK(auint);
- PUSH_VAR(utf8, cur, auint);
+ PUSH_VAR(utf8, cur, auint, needs_swap);
}
break;
case 'j':
IV aiv;
fromstr = NEXTFROM;
aiv = SvIV(fromstr);
- DO_BO_PACK(aiv);
- PUSH_VAR(utf8, cur, aiv);
+ PUSH_VAR(utf8, cur, aiv, needs_swap);
}
break;
case 'J':
UV auv;
fromstr = NEXTFROM;
auv = SvUV(fromstr);
- DO_BO_PACK(auv);
- PUSH_VAR(utf8, cur, auv);
+ PUSH_VAR(utf8, cur, auv, needs_swap);
}
break;
case 'w':
int aint;
fromstr = NEXTFROM;
aint = SvIV(fromstr);
- DO_BO_PACK(aint);
- PUSH_VAR(utf8, cur, aint);
+ PUSH_VAR(utf8, cur, aint, needs_swap);
}
break;
case 'N' | TYPE_IS_SHRIEKING:
fromstr = NEXTFROM;
au32 = SvUV(fromstr);
au32 = PerlSock_htonl(au32);
- PUSH32(utf8, cur, &au32);
+ PUSH32(utf8, cur, &au32, FALSE);
}
break;
case 'V' | TYPE_IS_SHRIEKING:
fromstr = NEXTFROM;
au32 = SvUV(fromstr);
au32 = htovl(au32);
- PUSH32(utf8, cur, &au32);
+ PUSH32(utf8, cur, &au32, FALSE);
}
break;
case 'L' | TYPE_IS_SHRIEKING:
unsigned long aulong;
fromstr = NEXTFROM;
aulong = SvUV(fromstr);
- DO_BO_PACK(aulong);
- PUSH_VAR(utf8, cur, aulong);
+ PUSH_VAR(utf8, cur, aulong, needs_swap);
}
break;
#else
U32 au32;
fromstr = NEXTFROM;
au32 = SvUV(fromstr);
- DO_BO_PACK(au32);
- PUSH32(utf8, cur, &au32);
+ PUSH32(utf8, cur, &au32, needs_swap);
}
break;
case 'l' | TYPE_IS_SHRIEKING:
long along;
fromstr = NEXTFROM;
along = SvIV(fromstr);
- DO_BO_PACK(along);
- PUSH_VAR(utf8, cur, along);
+ PUSH_VAR(utf8, cur, along, needs_swap);
}
break;
#else
I32 ai32;
fromstr = NEXTFROM;
ai32 = SvIV(fromstr);
- DO_BO_PACK(ai32);
- PUSH32(utf8, cur, &ai32);
+ PUSH32(utf8, cur, &ai32, needs_swap);
}
break;
#ifdef HAS_QUAD
Uquad_t auquad;
fromstr = NEXTFROM;
auquad = (Uquad_t) SvUV(fromstr);
- DO_BO_PACK(auquad);
- PUSH_VAR(utf8, cur, auquad);
+ PUSH_VAR(utf8, cur, auquad, needs_swap);
}
break;
case 'q':
Quad_t aquad;
fromstr = NEXTFROM;
aquad = (Quad_t)SvIV(fromstr);
- DO_BO_PACK(aquad);
- PUSH_VAR(utf8, cur, aquad);
+ PUSH_VAR(utf8, cur, aquad, needs_swap);
}
break;
#endif /* HAS_QUAD */
else
aptr = SvPV_force_flags_nolen(fromstr, 0);
}
- DO_BO_PACK(aptr);
- PUSH_VAR(utf8, cur, aptr);
+ PUSH_VAR(utf8, cur, aptr, needs_swap);
}
break;
case 'u': {
end = doencodes(hunk, aptr, todo);
aptr += todo;
}
- PUSH_BYTES(utf8, cur, hunk, end-hunk);
+ PUSH_BYTES(utf8, cur, hunk, end-hunk, 0);
fromlen -= todo;
}
break;