我正在编写一个库,允许Lua以不同的类型和字节顺序读取和写入内存块中的任意字节。我已经使用过C ++模板来避免重复到某种程度,但我还没有完全避免它:
/* Read one or more sequential values from the blob and push to the Lua stack
* using lua_pushinteger().
* Lua: the Lua state to push to.
* offset: The byte offset to read from.
* count: The number of values to read.
* This method is called from Blob::read() which is called from Lua methods.
* For offsets outside the valid range, it returns nil.
*/
template <typename T>
lua_Integer Blob::readi(lua_State *Lua, lua_Integer offset, lua_Integer count) {
if(offset < 0) offset += this->size;
else offset--; //make 0-based
for(int i=0; i<count; i++) {
if(offset >= 0 && offset < this->size) {
T value = *(&this->data[offset + this->pageOffset]);
lua_pushinteger(Lua, value);
offset += sizeof(T);
}
else lua_pushnil(Lua);
}
return count;
}
/* Same as readi but uses lua_pushnumber
* even with templates we end up duplicating logic :|
*/
template <typename T>
lua_Integer Blob::readf(lua_State *Lua, lua_Integer offset, lua_Integer count) {
if(offset < 0) offset += this->size;
else offset--; //make 0-based
for(int i=0; i<count; i++) {
if(offset >= 0 && offset < this->size) {
T value = *(&this->data[offset + this->pageOffset]);
lua_pushnumber(Lua, value);
offset += sizeof(T);
}
else lua_pushnil(Lua);
}
return count;
}
当我们想要阅读float
或double
值时,我们必须使用lua_pushnumber(lua_State *Lua, lua_Number num)
而不是lua_pushinteger(lua_State *Lua, lua_Integer num)
。 (通常lua_Integer
是某种整数类型的typedef,例如int32_t
,而lua_Number
是double
的typedef。)所以我不知道我怎么做避免使用模板复制此功能,因为lua_pushinteger
和lua_pushnumber
接受不同的类型。
此外,我想添加对指定字节顺序的支持(使用endian.h
中的函数):您可以指定正在读取的值假定为大端序,小端或本机(以较小者为准)主机是)。同样,我不知道如何使用模板实现这一点,因为字节顺序函数处理不同的类型。
答案 0 :(得分:2)
void lua_push_anything( lua_State* s, lua_Integer i ) {
lua_push_integer( s, i );
}
void lua_push_anything( lua_State* s, lua_Number i ) {
lua_push_number( s, i );
}
void lua_push_anything( lua_State* s, bool b ) {
lua_push_boolean( s, b ); // actually takes an `int`.
}
void lua_push_anything( lua_State* s, std::string s ) {
lua_pushlstring( lua_State* s, s.c_str(), s.size() );
}
这解决了类型问题 - 您有一个覆盖分派到正确的extern "C"
lua_*
函数。
如果需要,您可以用类似的方式处理字节序。
答案 1 :(得分:1)
使用这样的特征类:
template <typename T>
class ReadTraits
{
//Has a typedef-ed callable type called ReadFunc.
};
您可以将此专门用于您希望能够读入的T
类型。现在,您的read
函数将如下所示:
template <typename T>
lua_Integer Blob::read(lua_State *Lua, lua_Integer offset, lua_Integer count) {
if(offset < 0) offset += this->size;
else offset--; //make 0-based
for(int i=0; i<count; i++) {
if(offset >= 0 && offset < this->size) {
T value = *(&this->data[offset + this->pageOffset]);
using ReadData = typename ReadTraits<T>::ReadFunc;
ReadData(Lua, value);
offset += sizeof(T);
}
else lua_pushnil(Lua);
}
return count;
}