Added a `bit_flags` attribute to enum declarations that 1<<N every value.

Change-Id: Ib9ec0cb3ddec60b1ca124eaf815fb1ae0cc53e1c
Tested: on Windows and Linux
Bug: 16186562
parent bd86bf60
...@@ -123,6 +123,7 @@ root_type Monster; ...@@ -123,6 +123,7 @@ root_type Monster;
<li><code>deprecated</code> (on a field): do not generate accessors for this field anymore, code should stop using this data.</li> <li><code>deprecated</code> (on a field): do not generate accessors for this field anymore, code should stop using this data.</li>
<li><code>original_order</code> (on a table): since elements in a table do not need to be stored in any particular order, they are often optimized for space by sorting them to size. This attribute stops that from happening.</li> <li><code>original_order</code> (on a table): since elements in a table do not need to be stored in any particular order, they are often optimized for space by sorting them to size. This attribute stops that from happening.</li>
<li><code>force_align: size</code> (on a struct): force the alignment of this struct to be something higher than what it is naturally aligned to. Causes these structs to be aligned to that amount inside a buffer, IF that buffer is allocated with that alignment (which is not necessarily the case for buffers accessed directly inside a <code>FlatBufferBuilder</code>).</li> <li><code>force_align: size</code> (on a struct): force the alignment of this struct to be something higher than what it is naturally aligned to. Causes these structs to be aligned to that amount inside a buffer, IF that buffer is allocated with that alignment (which is not necessarily the case for buffers accessed directly inside a <code>FlatBufferBuilder</code>).</li>
<li><code>bit_flags</code> (on an enum): the values of this field indicate bits, meaning that any value N specified in the schema will end up representing 1&lt;&lt;N, or if you don't specify values at all, you'll get the sequence 1, 2, 4, 8, ...</li>
</ul> </ul>
<h2>Gotchas</h2> <h2>Gotchas</h2>
<h3>Schemas and version control</h3> <h3>Schemas and version control</h3>
......
...@@ -188,6 +188,10 @@ Current understood attributes: ...@@ -188,6 +188,10 @@ Current understood attributes:
these structs to be aligned to that amount inside a buffer, IF that these structs to be aligned to that amount inside a buffer, IF that
buffer is allocated with that alignment (which is not necessarily buffer is allocated with that alignment (which is not necessarily
the case for buffers accessed directly inside a `FlatBufferBuilder`). the case for buffers accessed directly inside a `FlatBufferBuilder`).
- `bit_flags` (on an enum): the values of this field indicate bits,
meaning that any value N specified in the schema will end up
representing 1<<N, or if you don't specify values at all, you'll get
the sequence 1, 2, 4, 8, ...
## Gotchas ## Gotchas
......
...@@ -100,7 +100,8 @@ static void EscapeString(const String &s, std::string *_text) { ...@@ -100,7 +100,8 @@ static void EscapeString(const String &s, std::string *_text) {
text += c; text += c;
} else { } else {
auto u = static_cast<unsigned char>(c); auto u = static_cast<unsigned char>(c);
text += "\\x" + IntToStringHex(u); text += "\\x";
text += IntToStringHex(u);
} }
break; break;
} }
......
...@@ -629,10 +629,10 @@ void Parser::ParseEnum(bool is_union) { ...@@ -629,10 +629,10 @@ void Parser::ParseEnum(bool is_union) {
std::string dc = doc_comment_; std::string dc = doc_comment_;
Expect(kTokenIdentifier); Expect(kTokenIdentifier);
auto prevsize = enum_def.vals.vec.size(); auto prevsize = enum_def.vals.vec.size();
auto &ev = *new EnumVal(name, static_cast<int>( auto value = enum_def.vals.vec.size()
enum_def.vals.vec.size() ? enum_def.vals.vec.back()->value + 1
? enum_def.vals.vec.back()->value + 1 : 0;
: 0)); auto &ev = *new EnumVal(name, value);
if (enum_def.vals.Add(name, &ev)) if (enum_def.vals.Add(name, &ev))
Error("enum value already exists: " + name); Error("enum value already exists: " + name);
ev.doc_comment = dc; ev.doc_comment = dc;
...@@ -647,6 +647,15 @@ void Parser::ParseEnum(bool is_union) { ...@@ -647,6 +647,15 @@ void Parser::ParseEnum(bool is_union) {
} }
} while (IsNext(',')); } while (IsNext(','));
Expect('}'); Expect('}');
if (enum_def.attributes.Lookup("bit_flags")) {
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
if (static_cast<size_t>((*it)->value) >=
SizeOf(enum_def.underlying_type.base_type) * 8)
Error("bit flag out of range of underlying integral type");
(*it)->value = 1 << (*it)->value;
}
}
} }
void Parser::ParseDecl() { void Parser::ParseDecl() {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
package Example package Example
const ( const (
ColorRed = 0 ColorRed = 1
ColorGreen = 1 ColorGreen = 2
ColorBlue = 2 ColorBlue = 8
) )
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
package MyGame.Example; package MyGame.Example;
public class Color { public class Color {
public static final byte Red = 0; public static final byte Red = 1;
public static final byte Green = 1; public static final byte Green = 2;
public static final byte Blue = 2; public static final byte Blue = 8;
}; };
...@@ -80,7 +80,7 @@ func (rcv *Monster) Color() int8 { ...@@ -80,7 +80,7 @@ func (rcv *Monster) Color() int8 {
if o != 0 { if o != 0 {
return rcv._tab.GetInt8(o + rcv._tab.Pos) return rcv._tab.GetInt8(o + rcv._tab.Pos)
} }
return 2 return 8
} }
func (rcv *Monster) TestType() byte { func (rcv *Monster) TestType() byte {
...@@ -200,7 +200,7 @@ func MonsterAddHp(builder *flatbuffers.Builder, hp int16) { builder.PrependInt16 ...@@ -200,7 +200,7 @@ func MonsterAddHp(builder *flatbuffers.Builder, hp int16) { builder.PrependInt16
func MonsterAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(name), 0) } func MonsterAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(name), 0) }
func MonsterAddInventory(builder *flatbuffers.Builder, inventory flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(5, flatbuffers.UOffsetT(inventory), 0) } func MonsterAddInventory(builder *flatbuffers.Builder, inventory flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(5, flatbuffers.UOffsetT(inventory), 0) }
func MonsterStartInventoryVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(1, numElems) } func MonsterStartInventoryVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(1, numElems) }
func MonsterAddColor(builder *flatbuffers.Builder, color int8) { builder.PrependInt8Slot(6, color, 2) } func MonsterAddColor(builder *flatbuffers.Builder, color int8) { builder.PrependInt8Slot(6, color, 8) }
func MonsterAddTestType(builder *flatbuffers.Builder, testType byte) { builder.PrependByteSlot(7, testType, 0) } func MonsterAddTestType(builder *flatbuffers.Builder, testType byte) { builder.PrependByteSlot(7, testType, 0) }
func MonsterAddTest(builder *flatbuffers.Builder, test flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(8, flatbuffers.UOffsetT(test), 0) } func MonsterAddTest(builder *flatbuffers.Builder, test flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(8, flatbuffers.UOffsetT(test), 0) }
func MonsterAddTest4(builder *flatbuffers.Builder, test4 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(9, flatbuffers.UOffsetT(test4), 0) } func MonsterAddTest4(builder *flatbuffers.Builder, test4 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(9, flatbuffers.UOffsetT(test4), 0) }
......
...@@ -17,7 +17,7 @@ public class Monster extends Table { ...@@ -17,7 +17,7 @@ public class Monster extends Table {
public String name() { int o = __offset(10); return o != 0 ? __string(o) : null; } public String name() { int o = __offset(10); return o != 0 ? __string(o) : null; }
public byte inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; } public byte inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; } public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; }
public byte color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) : 2; } public byte color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) : 8; }
public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; } public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; }
public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; } public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; }
public Test test4(int j) { return test4(new Test(), j); } public Test test4(int j) { return test4(new Test(), j); }
...@@ -41,7 +41,7 @@ public class Monster extends Table { ...@@ -41,7 +41,7 @@ public class Monster extends Table {
public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(3, nameOffset, 0); } public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(3, nameOffset, 0); }
public static void addInventory(FlatBufferBuilder builder, int inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); } public static void addInventory(FlatBufferBuilder builder, int inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); }
public static void startInventoryVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems); } public static void startInventoryVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems); }
public static void addColor(FlatBufferBuilder builder, byte color) { builder.addByte(6, color, 2); } public static void addColor(FlatBufferBuilder builder, byte color) { builder.addByte(6, color, 8); }
public static void addTestType(FlatBufferBuilder builder, byte testType) { builder.addByte(7, testType, 0); } public static void addTestType(FlatBufferBuilder builder, byte testType) { builder.addByte(7, testType, 0); }
public static void addTest(FlatBufferBuilder builder, int testOffset) { builder.addOffset(8, testOffset, 0); } public static void addTest(FlatBufferBuilder builder, int testOffset) { builder.addOffset(8, testOffset, 0); }
public static void addTest4(FlatBufferBuilder builder, int test4Offset) { builder.addOffset(9, test4Offset, 0); } public static void addTest4(FlatBufferBuilder builder, int test4Offset) { builder.addOffset(9, test4Offset, 0); }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace MyGame.Example; namespace MyGame.Example;
enum Color:byte { Red = 0, Green, Blue = 2 } enum Color:byte (bit_flags) { Red = 0, Green, Blue = 3 }
union Any { Monster } // TODO: add more elements union Any { Monster } // TODO: add more elements
......
...@@ -9,17 +9,17 @@ namespace MyGame { ...@@ -9,17 +9,17 @@ namespace MyGame {
namespace Example { namespace Example {
enum { enum {
Color_Red = 0, Color_Red = 1,
Color_Green = 1, Color_Green = 2,
Color_Blue = 2, Color_Blue = 8,
}; };
inline const char **EnumNamesColor() { inline const char **EnumNamesColor() {
static const char *names[] = { "Red", "Green", "Blue", nullptr }; static const char *names[] = { "Red", "Green", "", "", "", "", "", "Blue", nullptr };
return names; return names;
} }
inline const char *EnumNameColor(int e) { return EnumNamesColor()[e]; } inline const char *EnumNameColor(int e) { return EnumNamesColor()[e - Color_Red]; }
enum { enum {
Any_NONE = 0, Any_NONE = 0,
...@@ -85,7 +85,7 @@ struct Monster : private flatbuffers::Table { ...@@ -85,7 +85,7 @@ struct Monster : private flatbuffers::Table {
int16_t hp() const { return GetField<int16_t>(8, 100); } int16_t hp() const { return GetField<int16_t>(8, 100); }
const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(10); } const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(10); }
const flatbuffers::Vector<uint8_t> *inventory() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(14); } const flatbuffers::Vector<uint8_t> *inventory() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(14); }
int8_t color() const { return GetField<int8_t>(16, 2); } int8_t color() const { return GetField<int8_t>(16, 8); }
uint8_t test_type() const { return GetField<uint8_t>(18, 0); } uint8_t test_type() const { return GetField<uint8_t>(18, 0); }
const void *test() const { return GetPointer<const void *>(20); } const void *test() const { return GetPointer<const void *>(20); }
const flatbuffers::Vector<const Test *> *test4() const { return GetPointer<const flatbuffers::Vector<const Test *> *>(22); } const flatbuffers::Vector<const Test *> *test4() const { return GetPointer<const flatbuffers::Vector<const Test *> *>(22); }
...@@ -131,7 +131,7 @@ struct MonsterBuilder { ...@@ -131,7 +131,7 @@ struct MonsterBuilder {
void add_hp(int16_t hp) { fbb_.AddElement<int16_t>(8, hp, 100); } void add_hp(int16_t hp) { fbb_.AddElement<int16_t>(8, hp, 100); }
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(10, name); } void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(10, name); }
void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) { fbb_.AddOffset(14, inventory); } void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) { fbb_.AddOffset(14, inventory); }
void add_color(int8_t color) { fbb_.AddElement<int8_t>(16, color, 2); } void add_color(int8_t color) { fbb_.AddElement<int8_t>(16, color, 8); }
void add_test_type(uint8_t test_type) { fbb_.AddElement<uint8_t>(18, test_type, 0); } void add_test_type(uint8_t test_type) { fbb_.AddElement<uint8_t>(18, test_type, 0); }
void add_test(flatbuffers::Offset<void> test) { fbb_.AddOffset(20, test); } void add_test(flatbuffers::Offset<void> test) { fbb_.AddOffset(20, test); }
void add_test4(flatbuffers::Offset<flatbuffers::Vector<const Test *>> test4) { fbb_.AddOffset(22, test4); } void add_test4(flatbuffers::Offset<flatbuffers::Vector<const Test *>> test4) { fbb_.AddOffset(22, test4); }
...@@ -150,7 +150,7 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder ...@@ -150,7 +150,7 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
int16_t hp = 100, int16_t hp = 100,
flatbuffers::Offset<flatbuffers::String> name = 0, flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0, flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
int8_t color = 2, int8_t color = 8,
uint8_t test_type = 0, uint8_t test_type = 0,
flatbuffers::Offset<void> test = 0, flatbuffers::Offset<void> test = 0,
flatbuffers::Offset<flatbuffers::Vector<const Test *>> test4 = 0, flatbuffers::Offset<flatbuffers::Vector<const Test *>> test4 = 0,
......
...@@ -477,6 +477,7 @@ void ErrorTest() { ...@@ -477,6 +477,7 @@ void ErrorTest() {
TestError("enum X:float {}", "underlying"); TestError("enum X:float {}", "underlying");
TestError("enum X:byte { Y, Y }", "value already"); TestError("enum X:byte { Y, Y }", "value already");
TestError("enum X:byte { Y=2, Z=1 }", "ascending"); TestError("enum X:byte { Y=2, Z=1 }", "ascending");
TestError("enum X:byte (bit_flags) { Y=8 }", "bit flag out");
TestError("table X { Y:int; } table X {", "datatype already"); TestError("table X { Y:int; } table X {", "datatype already");
TestError("struct X (force_align: 7) { Y:int; }", "force_align"); TestError("struct X (force_align: 7) { Y:int; }", "force_align");
TestError("{}", "no root"); TestError("{}", "no root");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment