日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FlatBuffers要点

發布時間:2025/3/15 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FlatBuffers要点 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  FlatBuffers公布出來一周多,周末便抽時間先研究下它的用法。Flatbuffers的idl的語法主要參考[http://google.github.io/flatbuffers/md__schemas.html ]。本文主要介紹幾個它的monster.fbs沒有給出說明的幾個語法點和相關的注意事項。

1 comment

  它的凝視中介紹了”///"。說明是能夠生成document comment. 我寫了例如以下fbs代碼(如果文件名還是monster.fbs):
/// struct Vec3 {
/// x:float;
/// y:float。
/// z:float;
/// }

  "flatc -c monster.fbs"命令編譯后,生成代碼為:
/// struct Vec3 { x:float; y:float; z:float; }

2 struct
  struct默認的aliagnment是4Byte.

  例如以下fbs代碼(如果文件名還是monster.fbs):
struct Vec4 {
x : float;
y : short;
z : float;
w : short;
}

  "flatc -c monster.fbs"命令編譯后,生成代碼為:
MANUALLY_ALIGNED_STRUCT(4) Vec4 {
private:
float x_;
int16_t y_;
int16_t __padding0;
float z_;
int16_t w_;
int16_t __padding1;

public:

Vec4(float x, int16_t y, float z, int16_t w)
: x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), __padding0(0), z_(flatbuffers::EndianScalar(z)), w_(flatbuffers::EndianScalar(w)), __padding1(0) {}
float x() const { return flatbuffers::EndianScalar(x_); }
int16_t y() const { return flatbuffers::EndianScalar(y_); }
float z() const { return flatbuffers::EndianScalar(z_); }
int16_t w() const { return flatbuffers::EndianScalar(w_); }
};
STRUCT_END(Vec4, 16);

3 original_order
  FB(FlatBuffers的簡稱,下同)用original_order來保持fbs中table的field順序。FB說明中說明它是用來修飾table的(”original_order (on a table)"),事實上他也能夠修飾struct。
  例如以下fbs代碼(如果文件名還是monster.fbs):
struct Vec4_ (original_order) {
x : float;
y : short;
z : float;
w : short;
}

  "flatc -c monster.fbs"命令編譯后,生成代碼為:
STRUCT_END(Vec4, 16);
MANUALLY_ALIGNED_STRUCT(4) Vec4_ {
private:
float x_;
int16_t y_;
int16_t __padding0;
float z_;
int16_t w_;
int16_t __padding1;

public:
Vec4_(float x, int16_t y, float z, int16_t w)
: x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), __padding0(0), z_(flatbuffers::EndianScalar(z)), w_(flatbuffers::EndianScalar(w)), __padding1(0) {}

float x() const { return flatbuffers::EndianScalar(x_); }
int16_t y() const { return flatbuffers::EndianScalar(y_); }
float z() const { return flatbuffers::EndianScalar(z_); }
int16_t w() const { return flatbuffers::EndianScalar(w_); }
};
STRUCT_END(Vec4_, 16);

4 force_align
  force_align這個keyword用來對struct進行align,此處我想說明FB的一個bug。
  例如以下fbs代碼(如果文件名還是monster.fbs):
struct Vec3 (force_align : 8 ) {
x : float;
y : float;
z : float;
}

  "flatc -c monster.fbs"命令編譯后,生成代碼為:
MANUALLY_ALIGNED_STRUCT(8) Vec3 {
private:
float x_;
float y_;
float z_;

public:
Vec3(float x, float y, float z)
: x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), z_(flatbuffers::EndianScalar(z)) {}

float x() const { return flatbuffers::EndianScalar(x_); }
float y() const { return flatbuffers::EndianScalar(y_); }
float z() const { return flatbuffers::EndianScalar(z_); }
};
STRUCT_END(Vec3, 12);

  請注意上面最后一行代碼的最后一個參數"12”,我已經說明以8Byte作為alignment??墒撬o出的struct Vec3的size仍然為12。假設你使用上面的代碼。g++會給出這種錯誤提示"error: static assertion failed: compiler breaks packing rules”。

  解決方法有三個,第一。你把這行代碼凝視掉。

or 第二,把數字“12”手工改成“16”。or 第三,等待官方修正這個bug(我已經提交了這個bug:https://github.com/google/flatbuffers/issues/18)。

  補充:bug已經由gwvo(https://github.com/gwvo)修正了。修正鏈接見(https://github.com/AlexStocks/flatbuffers/commit/65cfa18855abc712faa1bf0cb5c3b88ab8df4b28)。

  之所以Vec3的size沒有計算正確,原因是作者分析完struct的各個成員后忘了這個語法特性了。我以下略微補充下FB的編譯器出現這個bug的原因。

  bug改動之前,void Parser::ParseDecl() 一塊代碼例如以下:

// 驗證struct的開頭為 "{"
Expect('{');?
// 分析struct的每一行(field),其主功能是為struct加入member并添加struct的bytesize?
while (token_ != '}') ParseField(struct_def);?
// 為struct加入padding成員以進行alignment,然后計算struct的bytesize值
// 注意:作者忘了"force_align"這個關鍵語法特性就計算struct的bytesize?
struct_def.PadLastField(struct_def.minalign);?
// 驗證struct的結尾為 "}"?
Expect('}');?
// 此時才開始查找"force_align"這個keyword?
auto force_align = struct_def.attributes.Lookup("force_align");?
if (fixed && force_align) {
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
// 盡管計算出了struct應該以align為基準進行alignment,可是為時已晚,無法改變struct的bytesize了
struct_def.minalign = align;?
}

  通過上面分析,就能夠曉得問題所在,修正后的代碼為:

Expect('{');
while (token_ != '}') ParseField(struct_def);
auto force_align = struct_def.attributes.Lookup("force_align");
if (fixed && force_align) {
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
struct_def.minalign = align;
}
struct_def.PadLastField(struct_def.minalign); // !!!
Expect('}'); // !!!
}

  注意上面的代碼塊,不過對"!!!"標識的兩行代碼在代碼塊中往下移動了幾行。就能夠正確計算struct的bytesize了。再次感謝gwvo的工作。


5 struct&table

  table 是FB實現向前\向后兼容的關鍵。

table每一個field默認都是optional的,而struct的每一個成員是required的。把idl轉換為C++ or Java語言時候,FB不會改動struct成員的順序(假設struct的成員無法alignment FB會自己主動加入padding成員),可是會改變table成員的順序以使得它占用最小的內存空間。所以,table 提供向前\向后兼容特性,而你一旦定義一個struct后,你就無法再加入新的member。

  table的每一個對象被序列化后的內存空間中都存在著一個額外(除卻數據內存空間外)的輔助空間以說明其內存對象分布。稱之為vtable。通過vtable我們能夠知道這個table對象有哪些成員。假設同一個table的不同對象被序列化進同一個內存空間內,那么僅僅有第一個對象存儲了vtable的具體數據,而其它對象的vtable區域僅僅存儲一個指向第一個對象的vtable的指針就可以。由于table對象須要vtable以說明自己,所以對他它序列化后占用的內存空間一般都比序列化一個struct對象后占用的內存空間大。

  vtable的每一個元素占用2Bytes。它的第一個element是vtable的elements總數目(包括第一個element自身),第二個是對象的以字節為單位的內存大小(包括vtable占用的內存空間大小)。后面的element就是table各個成員在object區域的偽指針(即偏移大小)。

假設table有N個member,則vtable大小就是((N + 2) * 2) Bytes.

  FB的對象區域每一個成員基本上都是len+value形式。

vtable內則是type id + offset形式。offset能夠理解為一個偽指針,通過它能夠找到每一個成員。FB對每一個成員進行賦值之前。要先進性alignment。然后把value轉換為endian形式,FB保證這些值在不同平臺上都有效。

  反序列化一個對象后,訪問一個對象的某個成員時,假設其序列化后的空間內沒有這個成員的數據,那么就返回其默認值。同理。序列化一個對象時,假設這個對象的成員的值與默認值相等,則不會把這個值序列化進內場空間。

假設一個table的field都用默認值,那么此時對它序列化后占用的內存空間要比序列化一個struct對象后占用的內存空間小。

  FB另一個類型union。它的文檔里面提到"FlatBuffers can of course be wrapped inside other containers where needed, or you can use its union feature to dynamically identify multiple possible sub-objects stored. Additionally, it can be used together with the schema parser if full reflective capabilities are desired.“。我理解不多,有待后面分析。

6 summary

  FB的document里面提到開發它的緣由。?
  “在過去的好日子里,說到提高性能就是開發更高效的CPU指令和提供更短的CPU計算周期,但如今那個好日子一去不復返了。由于回首回望,我們發現CPU已經發展太快而把他的小弟內存拉下了好幾圈了。如今提高性能的戰場應該是在內存而非CPU了。高速高效的方法應該是:一個對象在內存中怎樣高效的占用盡可能少的空間。怎樣更高速的訪問它,以及怎么為它分配這些空間和怎樣拷貝它?!?
  “進程一個重要的是任務就是對它的數據進行序列化,這可能要使用非常多暫時的變量以分析和暫時存儲這些數據。也可能使用不甚高效的內存分配策略。而FB能夠做到不使用暫時對象、沒有額外的內存分配、不拷貝和讓對象占用盡可能少的內存空間。除了做到這些。FB能保證數據本身的向前\向后兼容性、跨平臺特性。

另外,它以小端數據格式作為標準數據格式”?
  “FB主要關注移動開發平臺(這個平臺與PC平臺相比就如同上世界把PC與大型機相比一樣。它的內存空間大小和傳輸數據速度都稍顯緊缺),它尤其關注一類移動應用:games”?
  依據我對FB源代碼的研究。誠哉斯言!


轉載于:https://www.cnblogs.com/brucemengbm/p/6727303.html

總結

以上是生活随笔為你收集整理的FlatBuffers要点的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。