Cleaner handling of floats in pack/unpack

This commit is contained in:
Roberto Ierusalimschy
2020-12-16 11:23:51 -03:00
parent e1ceea5674
commit b17178b27a

View File

@@ -1358,16 +1358,6 @@ struct cD {
#define MAXALIGN (offsetof(struct cD, u)) #define MAXALIGN (offsetof(struct cD, u))
/*
** Union for serializing floats
*/
typedef union Ftypes {
float f;
double d;
lua_Number n;
} Ftypes;
/* /*
** information to pack/unpack stuff ** information to pack/unpack stuff
*/ */
@@ -1384,7 +1374,9 @@ typedef struct Header {
typedef enum KOption { typedef enum KOption {
Kint, /* signed integers */ Kint, /* signed integers */
Kuint, /* unsigned integers */ Kuint, /* unsigned integers */
Kfloat, /* floating-point numbers */ Kfloat, /* single-precision floating-point numbers */
Knumber, /* Lua "native" floating-point numbers */
Kdouble, /* double-precision floating-point numbers */
Kchar, /* fixed-length strings */ Kchar, /* fixed-length strings */
Kstring, /* strings with prefixed length */ Kstring, /* strings with prefixed length */
Kzstr, /* zero-terminated strings */ Kzstr, /* zero-terminated strings */
@@ -1453,8 +1445,8 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
case 'J': *size = sizeof(lua_Integer); return Kuint; case 'J': *size = sizeof(lua_Integer); return Kuint;
case 'T': *size = sizeof(size_t); return Kuint; case 'T': *size = sizeof(size_t); return Kuint;
case 'f': *size = sizeof(float); return Kfloat; case 'f': *size = sizeof(float); return Kfloat;
case 'd': *size = sizeof(double); return Kfloat; case 'n': *size = sizeof(lua_Number); return Knumber;
case 'n': *size = sizeof(lua_Number); return Kfloat; case 'd': *size = sizeof(double); return Kdouble;
case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
@@ -1580,15 +1572,27 @@ static int str_pack (lua_State *L) {
packint(&b, (lua_Unsigned)n, h.islittle, size, 0); packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
break; break;
} }
case Kfloat: { /* floating-point options */ case Kfloat: { /* C float */
Ftypes u; float f = (float)luaL_checknumber(L, arg); /* get argument */
char *buff = luaL_prepbuffsize(&b, size); char *buff = luaL_prepbuffsize(&b, sizeof(f));
lua_Number n = luaL_checknumber(L, arg); /* get argument */ /* move 'f' to final result, correcting endianness if needed */
if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
else if (size == sizeof(u.d)) u.d = (double)n; luaL_addsize(&b, size);
else u.n = n; break;
/* move 'u' to final result, correcting endianness if needed */ }
copywithendian(buff, (char *)&u, size, h.islittle); case Knumber: { /* Lua float */
lua_Number f = luaL_checknumber(L, arg); /* get argument */
char *buff = luaL_prepbuffsize(&b, sizeof(f));
/* move 'f' to final result, correcting endianness if needed */
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
luaL_addsize(&b, size);
break;
}
case Kdouble: { /* C double */
double f = (double)luaL_checknumber(L, arg); /* get argument */
char *buff = luaL_prepbuffsize(&b, sizeof(f));
/* move 'f' to final result, correcting endianness if needed */
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
luaL_addsize(&b, size); luaL_addsize(&b, size);
break; break;
} }
@@ -1714,13 +1718,21 @@ static int str_unpack (lua_State *L) {
break; break;
} }
case Kfloat: { case Kfloat: {
Ftypes u; float f;
lua_Number num; copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
copywithendian((char *)&u, data + pos, size, h.islittle); lua_pushnumber(L, (lua_Number)f);
if (size == sizeof(u.f)) num = (lua_Number)u.f; break;
else if (size == sizeof(u.d)) num = (lua_Number)u.d; }
else num = u.n; case Knumber: {
lua_pushnumber(L, num); lua_Number f;
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
lua_pushnumber(L, f);
break;
}
case Kdouble: {
double f;
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
lua_pushnumber(L, (lua_Number)f);
break; break;
} }
case Kchar: { case Kchar: {