Commit b062af4c authored by Maor Itzkovitch's avatar Maor Itzkovitch

rebased fork

parents 09567197 e1511605
......@@ -25,6 +25,7 @@ set(FlatBuffers_Library_SRCS
include/flatbuffers/reflection_generated.h
src/idl_parser.cpp
src/idl_gen_text.cpp
src/reflection.cpp
)
set(FlatBuffers_Compiler_SRCS
......@@ -43,14 +44,9 @@ set(FlatHash_SRCS
)
set(FlatBuffers_Tests_SRCS
include/flatbuffers/flatbuffers.h
include/flatbuffers/hash.h
include/flatbuffers/idl.h
include/flatbuffers/util.h
src/idl_parser.cpp
src/idl_gen_general.cpp
src/idl_gen_text.cpp
${FlatBuffers_Library_SRCS}
src/idl_gen_fbs.cpp
src/idl_gen_general.cpp
tests/test.cpp
# file generate by running compiler on tests/monster_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
......
......@@ -31,7 +31,9 @@ LOCAL_SRC_FILES := main.cpp \
../../tests/test.cpp \
../../src/idl_parser.cpp \
../../src/idl_gen_text.cpp \
../../src/idl_gen_fbs.cpp
../../src/idl_gen_fbs.cpp \
../../src/idl_gen_general.cpp \
../../src/reflection.cpp
LOCAL_LDLIBS := -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
LOCAL_ARM_MODE := arm
......
......@@ -66,7 +66,7 @@ FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/Debug/flatc
endif
FLATBUFFERS_FLATC_ARGS?=--gen-includes
FLATBUFFERS_FLATC_ARGS?=
# Search for cmake.
CMAKE_ROOT := $(realpath $(LOCAL_PATH)/../../../../../../prebuilts/cmake)
......
......@@ -272,6 +272,7 @@
<ClCompile Include="..\..\src\idl_gen_general.cpp" />
<ClCompile Include="..\..\src\idl_parser.cpp" />
<ClCompile Include="..\..\src\idl_gen_text.cpp" />
<ClCompile Include="..\..\src\reflection.cpp" />
<ClCompile Include="..\..\tests\test.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
......
......@@ -12,8 +12,9 @@
61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
61FF3C34FBEC4819A1C30F92 /* sample_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECCEBFFA6977404F858F9739 /* sample_text.cpp */; settings = {COMPILER_FLAGS = ""; }; };
8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */; };
8C6905F819F835A900CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */; };
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C8774621B703D4800E693F5 /* reflection.cpp */; };
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; };
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CA854B21B04244A00040A06 /* idl_gen_python.cpp */; };
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; };
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; };
......@@ -33,23 +34,15 @@
3709AC883348409592530AE6 /* idl_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_parser.cpp; path = src/idl_parser.cpp; sourceTree = SOURCE_ROOT; };
3863042BCEC64791BFB48625 /* flatsamplebinary */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flatsamplebinary; sourceTree = BUILT_PRODUCTS_DIR; };
420E3BC724ED4A008D79297F /* flatsampletext */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flatsampletext; sourceTree = BUILT_PRODUCTS_DIR; };
423CA92401AE442B91546E63 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CMakeLists.txt; path = /Users/wvo/flatbuffers_snapshot9/CMakeLists.txt; sourceTree = "<absolute>"; };
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sample_binary.cpp; path = samples/sample_binary.cpp; sourceTree = SOURCE_ROOT; };
6AD24EEB3D024825A37741FF /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = tests/test.cpp; sourceTree = SOURCE_ROOT; };
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_go.cpp; path = src/idl_gen_go.cpp; sourceTree = "<group>"; };
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_fbs.cpp; path = src/idl_gen_fbs.cpp; sourceTree = "<group>"; };
8C6905EF19F835A900CB8866 /* flatc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flatc.cpp; sourceTree = "<group>"; };
8C6905F019F835A900CB8866 /* idl_gen_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_cpp.cpp; sourceTree = "<group>"; };
8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_fbs.cpp; sourceTree = "<group>"; };
8C6905F219F835A900CB8866 /* idl_gen_general.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_general.cpp; sourceTree = "<group>"; };
8C6905F319F835A900CB8866 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_go.cpp; sourceTree = "<group>"; };
8C6905F419F835A900CB8866 /* idl_gen_text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_gen_text.cpp; sourceTree = "<group>"; };
8C6905F519F835A900CB8866 /* idl_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = idl_parser.cpp; sourceTree = "<group>"; };
8C8774621B703D4800E693F5 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = src/reflection.cpp; sourceTree = "<group>"; };
8CA854B21B04244A00040A06 /* idl_gen_python.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_python.cpp; path = src/idl_gen_python.cpp; sourceTree = "<group>"; };
8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_general.cpp; path = src/idl_gen_general.cpp; sourceTree = "<group>"; };
A13F25CDAD23435DA293690D /* flattests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; path = flattests; sourceTree = BUILT_PRODUCTS_DIR; };
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monster_test_generated.h; path = tests/monster_test_generated.h; sourceTree = SOURCE_ROOT; };
AD3682C6E1DD4EABB822C0CC /* monster_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monster_generated.h; path = samples/monster_generated.h; sourceTree = SOURCE_ROOT; };
C0E7B66C3FF849A0AD9A7168 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = include/flatbuffers/util.h; sourceTree = SOURCE_ROOT; };
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_cpp.cpp; path = src/idl_gen_cpp.cpp; sourceTree = SOURCE_ROOT; };
DD8B353D4756412195777FBA /* flatbuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = flatbuffers.h; path = include/flatbuffers/flatbuffers.h; sourceTree = SOURCE_ROOT; };
......@@ -58,13 +51,6 @@
/* End PBXFileReference section */
/* Begin PBXGroup section */
194905BCBB5C451DB092EB08 /* Resources */ = {
isa = PBXGroup;
children = (
);
name = Resources;
sourceTree = "<group>";
};
28237E300FE042DEADA302D3 /* Source Files */ = {
isa = PBXGroup;
children = (
......@@ -72,19 +58,10 @@
8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */,
8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */,
8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */,
0DFD29781D8E490284B06504 /* flatc.cpp */,
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
};
355DCA17961E4B2FB2C71403 /* Source Files */ = {
isa = PBXGroup;
children = (
8C6905EE19F835A900CB8866 /* src */,
F6C5D81DBF864365B12E269D /* idl_gen_text.cpp */,
3709AC883348409592530AE6 /* idl_parser.cpp */,
6AD24EEB3D024825A37741FF /* test.cpp */,
CD90A7F6B2BE4D0384294DD1 /* idl_gen_cpp.cpp */,
8C8774621B703D4800E693F5 /* reflection.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
......@@ -92,49 +69,17 @@
378446B9D5EF46EF92B35E21 /* flatc */ = {
isa = PBXGroup;
children = (
5FEA84E7D39645988300317C /* Header Files */,
28237E300FE042DEADA302D3 /* Source Files */,
0DFD29781D8E490284B06504 /* flatc.cpp */,
);
name = flatc;
sourceTree = "<group>";
};
40E30B8480BD493EA459E9B4 /* Header Files */ = {
isa = PBXGroup;
children = (
AD3682C6E1DD4EABB822C0CC /* monster_generated.h */,
);
name = "Header Files";
sourceTree = "<group>";
};
4D1151F6FE594E40A1C177FF /* Header Files */ = {
isa = PBXGroup;
children = (
);
name = "Header Files";
sourceTree = "<group>";
};
5235469653ED4BC88A6C504D /* Header Files */ = {
5FEA84E7D39645988300317C /* Header Files */ = {
isa = PBXGroup;
children = (
DD8B353D4756412195777FBA /* flatbuffers.h */,
00154BD8654B4B5B9FF45FA6 /* idl.h */,
C0E7B66C3FF849A0AD9A7168 /* util.h */,
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */,
);
name = "Header Files";
sourceTree = "<group>";
};
5648A71028E14478841372D3 /* Source Files */ = {
isa = PBXGroup;
children = (
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
};
5FEA84E7D39645988300317C /* Header Files */ = {
isa = PBXGroup;
children = (
);
name = "Header Files";
sourceTree = "<group>";
......@@ -142,6 +87,8 @@
866694F9F2F7451382D236B3 /* Sources */ = {
isa = PBXGroup;
children = (
28237E300FE042DEADA302D3 /* Source Files */,
5FEA84E7D39645988300317C /* Header Files */,
378446B9D5EF46EF92B35E21 /* flatc */,
DB9DE41C20F349F694A488F3 /* flatsamplebinary */,
8FA1F43C78914AE5AD04E24E /* flatsampletext */,
......@@ -153,31 +100,16 @@
88421F5F87584EE3B67C979A /* flattests */ = {
isa = PBXGroup;
children = (
5235469653ED4BC88A6C504D /* Header Files */,
355DCA17961E4B2FB2C71403 /* Source Files */,
AB70F1FBA50E4120BCF37C8D /* monster_test_generated.h */,
6AD24EEB3D024825A37741FF /* test.cpp */,
);
name = flattests;
sourceTree = "<group>";
};
8C6905EE19F835A900CB8866 /* src */ = {
isa = PBXGroup;
children = (
8C6905EF19F835A900CB8866 /* flatc.cpp */,
8C6905F019F835A900CB8866 /* idl_gen_cpp.cpp */,
8C6905F119F835A900CB8866 /* idl_gen_fbs.cpp */,
8C6905F219F835A900CB8866 /* idl_gen_general.cpp */,
8C6905F319F835A900CB8866 /* idl_gen_go.cpp */,
8C6905F419F835A900CB8866 /* idl_gen_text.cpp */,
8C6905F519F835A900CB8866 /* idl_parser.cpp */,
);
path = src;
sourceTree = "<group>";
};
8F5E926B72104F4194B3BD5A = {
isa = PBXGroup;
children = (
866694F9F2F7451382D236B3 /* Sources */,
194905BCBB5C451DB092EB08 /* Resources */,
99CC11E382B8420AA79A8A14 /* Products */,
);
sourceTree = "<group>";
......@@ -185,8 +117,7 @@
8FA1F43C78914AE5AD04E24E /* flatsampletext */ = {
isa = PBXGroup;
children = (
40E30B8480BD493EA459E9B4 /* Header Files */,
A1C826615F904FDE8F0CA154 /* Source Files */,
ECCEBFFA6977404F858F9739 /* sample_text.cpp */,
);
name = flatsampletext;
sourceTree = "<group>";
......@@ -202,20 +133,10 @@
name = Products;
sourceTree = "<group>";
};
A1C826615F904FDE8F0CA154 /* Source Files */ = {
isa = PBXGroup;
children = (
ECCEBFFA6977404F858F9739 /* sample_text.cpp */,
);
name = "Source Files";
sourceTree = "<group>";
};
DB9DE41C20F349F694A488F3 /* flatsamplebinary */ = {
isa = PBXGroup;
children = (
4D1151F6FE594E40A1C177FF /* Header Files */,
5648A71028E14478841372D3 /* Source Files */,
423CA92401AE442B91546E63 /* CMakeLists.txt */,
5EE44BFFAF8E43F485859145 /* sample_binary.cpp */,
);
name = flatsamplebinary;
sourceTree = "<group>";
......@@ -338,8 +259,8 @@
AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */,
BE03D7B0C9584DD58B50ED34 /* idl_gen_cpp.cpp in Sources */,
AD71FEBEE4E846529002C1F0 /* idl_gen_text.cpp in Sources */,
8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */,
A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */,
8C6905F819F835A900CB8866 /* idl_gen_fbs.cpp in Sources */,
8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */,
8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */,
);
......@@ -349,6 +270,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C8774631B703D4800E693F5 /* reflection.cpp in Sources */,
5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */,
8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */,
E0680D6B5BFD484BA9D88EE8 /* idl_gen_text.cpp in Sources */,
......
......@@ -21,7 +21,7 @@ $extrastylesheet
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -36,6 +36,9 @@ $extrastylesheet
<div id="projectname">$projectname
<!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......@@ -75,7 +78,7 @@ $(document).ready(function(){initNavTree('md__compiler.html','');});
<li><code>--strict-json</code> : Require &amp; generate strict JSON (field names are enclosed in quotes, no trailing commas in tables/vectors). By default, no quotes are required/generated, and trailing commas are allowed.</li>
<li><code>--defaults-json</code> : Output fields whose value is equal to the default value when writing JSON text.</li>
<li><code>--no-prefix</code> : Don't prefix enum values in generated C++ by their enum type.</li>
<li><code>--gen-includes</code> : (deprecated), instead use:</li>
<li><code>--gen-includes</code> : (deprecated), this is the default behavior. If the original behavior is required (no include statements) use <code>--no-includes.</code></li>
<li><code>--no-includes</code> : Don't generate include statements for included schemas the generated file depends on (C++).</li>
<li><code>--gen-mutable</code> : Generate additional non-const accessors for mutating FlatBuffers in-place.</li>
<li><code>--gen-onefile</code> : Generate single output file (useful for C#)</li>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -5,7 +5,7 @@
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.7"/>
<title>FlatBuffers: Formal Grammar of the schema language</title>
<title>FlatBuffers: Grammar of the schema language</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......@@ -55,7 +58,7 @@ $(document).ready(function(){initNavTree('md__grammar.html','');});
<div id="doc-content">
<div class="header">
<div class="headertitle">
<div class="title">Formal Grammar of the schema language </div> </div>
<div class="title">Grammar of the schema language </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>schema = include* ( namespace_decl | type_decl | enum_decl | root_decl | file_extension_decl | file_identifier_decl | attribute_decl | object )*</p>
......@@ -68,13 +71,16 @@ $(document).ready(function(){initNavTree('md__grammar.html','');});
<p>field_decl = ident <code>:</code> type [ <code>=</code> scalar ] metadata <code>;</code></p>
<p>type = <code>bool</code> | <code>byte</code> | <code>ubyte</code> | <code>short</code> | <code>ushort</code> | <code>int</code> | <code>uint</code> | <code>float</code> | <code>long</code> | <code>ulong</code> | <code>double</code> | <code>string</code> | <code>[</code> type <code>]</code> | ident</p>
<p>enumval_decl = ident [ <code>=</code> integer_constant ]</p>
<p>metadata = [ <code>(</code> commasep( ident [ <code>:</code> scalar ] ) <code>)</code> ]</p>
<p>scalar = integer_constant | float_constant | <code>true</code> | <code>false</code></p>
<p>metadata = [ <code>(</code> commasep( ident [ <code>:</code> single_value ] ) <code>)</code> ]</p>
<p>scalar = integer_constant | float_constant</p>
<p>object = { commasep( ident <code>:</code> value ) }</p>
<p>value = scalar | object | string_constant | <code>[</code> commasep( value ) <code>]</code></p>
<p>single_value = scalar | string_constant</p>
<p>value = single_value | object | <code>[</code> commasep( value ) <code>]</code></p>
<p>commasep(x) = [ x ( <code>,</code> x )* ]</p>
<p>file_extension_decl = <code>file_extension</code> string_constant <code>;</code></p>
<p>file_identifier_decl = <code>file_identifier</code> string_constant <code>;</code> </p>
<p>file_identifier_decl = <code>file_identifier</code> string_constant <code>;</code></p>
<p>integer_constant = -?[0-9]+ | <code>true</code> | <code>false</code></p>
<p>float_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)? </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- Google Analytics -->
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......
......@@ -11,7 +11,7 @@ var NAVTREE =
[ "Benchmarks", "md__benchmarks.html", null ],
[ "FlatBuffers white paper", "md__white_paper.html", null ],
[ "FlatBuffer Internals", "md__internals.html", null ],
[ "Formal Grammar of the schema language", "md__grammar.html", null ]
[ "Grammar of the schema language", "md__grammar.html", null ]
] ]
];
......
......@@ -21,7 +21,7 @@
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<div id="titlearea" style="height: 110px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
......@@ -31,6 +31,9 @@
<td style="padding-left: 0.5em;">
<div id="projectname">FlatBuffers
</div>
<div style="font-size:12px;">
An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
</div>
</td>
</tr>
</tbody>
......@@ -70,7 +73,7 @@ $(document).ready(function(){initNavTree('pages.html','');});
<tr id="row_7_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__benchmarks.html" target="_self">Benchmarks</a></td><td class="desc"></td></tr>
<tr id="row_8_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__white_paper.html" target="_self">FlatBuffers white paper</a></td><td class="desc"></td></tr>
<tr id="row_9_"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__internals.html" target="_self">FlatBuffer Internals</a></td><td class="desc"></td></tr>
<tr id="row_10_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__grammar.html" target="_self">Formal Grammar of the schema language</a></td><td class="desc"></td></tr>
<tr id="row_10_" class="even"><td class="entry"><span style="width:16px;display:inline-block;">&#160;</span><a class="el" href="md__grammar.html" target="_self">Grammar of the schema language</a></td><td class="desc"></td></tr>
</table>
</div><!-- directory -->
</div><!-- contents -->
......
......@@ -51,7 +51,10 @@ be generated for each file processed:
- `--no-prefix` : Don't prefix enum values in generated C++ by their enum
type.
- `--gen-includes` : (deprecated), instead use:
- `--gen-includes` : (deprecated), this is the default behavior.
If the original behavior is required (no include
statements) use `--no-includes.`
- `--no-includes` : Don't generate include statements for included schemas the
generated file depends on (C++).
......
# Formal Grammar of the schema language
# Grammar of the schema language
schema = include*
( namespace\_decl | type\_decl | enum\_decl | root\_decl |
......@@ -26,13 +26,15 @@ type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
enumval\_decl = ident [ `=` integer\_constant ]
metadata = [ `(` commasep( ident [ `:` scalar ] ) `)` ]
metadata = [ `(` commasep( ident [ `:` single\_value ] ) `)` ]
scalar = integer\_constant | float\_constant | `true` | `false`
scalar = integer\_constant | float\_constant
object = { commasep( ident `:` value ) }
value = scalar | object | string\_constant | `[` commasep( value ) `]`
single\_value = scalar | string\_constant
value = single\_value | object | `[` commasep( value ) `]`
commasep(x) = [ x ( `,` x )\* ]
......@@ -40,3 +42,6 @@ file_extension_decl = `file_extension` string\_constant `;`
file_identifier_decl = `file_identifier` string\_constant `;`
integer\_constant = -?[0-9]+ | `true` | `false`
float\_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?
......@@ -293,11 +293,21 @@ public:
const_iterator end() const { return const_iterator(Data(), size()); }
// Change elements if you have a non-const pointer to this object.
// Scalars only. See reflection.h, and the documentation.
void Mutate(uoffset_t i, T val) {
assert(i < size());
WriteScalar(data() + i, val);
}
// Change an element of a vector of tables (or strings).
// "val" points to the new table/string, as you can obtain from
// e.g. reflection::AddFlatBuffer().
void MutateOffset(uoffset_t i, const uint8_t *val) {
assert(i < size());
assert(sizeof(T) == sizeof(uoffset_t));
WriteScalar(data() + i, val - (Data() + i * sizeof(uoffset_t)));
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
......@@ -343,6 +353,24 @@ private:
}
};
// Represent a vector much like the template above, but in this case we
// don't know what the element types are (used with reflection.h).
class VectorOfAny {
public:
uoffset_t size() const { return EndianScalar(length_); }
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
}
uint8_t *Data() {
return reinterpret_cast<uint8_t *>(&length_ + 1);
}
protected:
VectorOfAny();
uoffset_t length_;
};
// Convenient helper function to get the length of any vector, regardless
// of wether it is null or not (the field is not set).
template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
......@@ -985,6 +1013,9 @@ class Struct FLATBUFFERS_FINAL_CLASS {
return reinterpret_cast<T>(&data_[o]);
}
const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; }
uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; }
private:
uint8_t data_[1];
};
......@@ -1017,7 +1048,6 @@ class Table {
? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
: nullptr;
}
template<typename P> P GetPointer(voffset_t field) const {
return const_cast<Table *>(this)->GetPointer<P>(field);
}
......@@ -1035,6 +1065,21 @@ class Table {
return true;
}
bool SetPointer(voffset_t field, const uint8_t *val) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false;
WriteScalar(data_ + field_offset, val - (data_ + field_offset));
return true;
}
uint8_t *GetAddressOf(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
return field_offset ? data_ + field_offset : nullptr;
}
const uint8_t *GetAddressOf(voffset_t field) const {
return const_cast<Table *>(this)->GetAddressOf(field);
}
uint8_t *GetVTable() { return data_ - ReadScalar<soffset_t>(data_); }
bool CheckField(voffset_t field) const {
......
......@@ -50,8 +50,8 @@ namespace flatbuffers {
TD(FLOAT, "float", float, float, float32, float, float32) /* begin float */ \
TD(DOUBLE, "double", double, double, float64, double, float64) /* end float/scalar */
#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
TD(STRING, "string", Offset<void>, int, int, int, int) \
TD(VECTOR, "", Offset<void>, int, int, int, int) \
TD(STRING, "string", Offset<void>, int, int, StringOffset, int) \
TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int) \
TD(STRUCT, "", Offset<void>, int, int, int, int) \
TD(UNION, "", Offset<void>, int, int, int, int)
......
......@@ -17,8 +17,6 @@
#ifndef FLATBUFFERS_REFLECTION_H_
#define FLATBUFFERS_REFLECTION_H_
#include "flatbuffers/util.h"
// This is somewhat of a circular dependency because flatc (and thus this
// file) is needed to generate this header in the first place.
// Should normally not be a problem since it can be generated by the
......@@ -30,12 +28,28 @@
namespace flatbuffers {
// ------------------------- GETTERS -------------------------
// Size of a basic type, don't use with structs.
inline size_t GetTypeSize(reflection::BaseType base_type) {
// This needs to correspond to the BaseType enum.
static size_t sizes[] = { 0, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 4, 4, 4 };
return sizes[base_type];
}
// Same as above, but now correctly returns the size of a struct if
// the field (or vector element) is a struct.
inline size_t GetTypeSizeInline(reflection::BaseType base_type,
int type_index,
const reflection::Schema &schema) {
if (base_type == reflection::Obj &&
schema.objects()->Get(type_index)->is_struct()) {
return schema.objects()->Get(type_index)->bytesize();
} else {
return GetTypeSize(base_type);
}
}
// Get the root, regardless of what type it is.
inline Table *GetAnyRoot(uint8_t *flatbuf) {
return GetMutableRoot<Table>(flatbuf);
......@@ -68,108 +82,147 @@ inline const String *GetFieldS(const Table &table,
}
// Get a field, if you know it's a vector.
template<typename T> const Vector<T> *GetFieldV(const Table &table,
const reflection::Field &field) {
template<typename T> Vector<T> *GetFieldV(const Table &table,
const reflection::Field &field) {
assert(field.type()->base_type() == reflection::Vector &&
sizeof(T) == GetTypeSize(field.type()->element()));
return table.GetPointer<const Vector<T> *>(field.offset());
return table.GetPointer<Vector<T> *>(field.offset());
}
// Get a field, if you know it's a vector, generically.
// To actually access elements, use the return value together with
// field.type()->element() in any of GetAnyVectorElemI below etc.
inline VectorOfAny *GetFieldAnyV(const Table &table,
const reflection::Field &field) {
return table.GetPointer<VectorOfAny *>(field.offset());
}
// Get a field, if you know it's a table.
inline const Table *GetFieldT(const Table &table,
const reflection::Field &field) {
inline Table *GetFieldT(const Table &table,
const reflection::Field &field) {
assert(field.type()->base_type() == reflection::Obj ||
field.type()->base_type() == reflection::Union);
return table.GetPointer<const Table *>(field.offset());
return table.GetPointer<Table *>(field.offset());
}
// Get any field as a 64bit int, regardless of what it is (bool/int/float/str).
// Raw helper functions used below: get any value in memory as a 64bit int, a
// double or a string.
// All scalars get static_cast to an int64_t, strings use strtoull, every other
// data type returns 0.
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
// All scalars static cast to double, strings use strtod, every other data
// type is 0.0.
double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
// All scalars converted using stringstream, strings as-is, and all other
// data types provide some level of debug-pretty-printing.
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
const reflection::Schema *schema,
int type_index);
// Get any table field as a 64bit int, regardless of what type it is.
inline int64_t GetAnyFieldI(const Table &table,
const reflection::Field &field) {
# define FLATBUFFERS_GET(C, T) \
static_cast<int64_t>(GetField##C<T>(table, field))
switch (field.type()->base_type()) {
case reflection::UType:
case reflection::Bool:
case reflection::UByte: return FLATBUFFERS_GET(I, uint8_t);
case reflection::Byte: return FLATBUFFERS_GET(I, int8_t);
case reflection::Short: return FLATBUFFERS_GET(I, int16_t);
case reflection::UShort: return FLATBUFFERS_GET(I, uint16_t);
case reflection::Int: return FLATBUFFERS_GET(I, int32_t);
case reflection::UInt: return FLATBUFFERS_GET(I, uint32_t);
case reflection::Long: return FLATBUFFERS_GET(I, int64_t);
case reflection::ULong: return FLATBUFFERS_GET(I, uint64_t);
case reflection::Float: return FLATBUFFERS_GET(F, float);
case reflection::Double: return FLATBUFFERS_GET(F, double);
case reflection::String: {
auto s = GetFieldS(table, field);
return s ? StringToInt(s->c_str()) : 0;
}
default: return 0;
}
# undef FLATBUFFERS_GET
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
: field.default_integer();
}
// Get any field as a double, regardless of what it is (bool/int/float/str).
// Get any table field as a double, regardless of what type it is.
inline double GetAnyFieldF(const Table &table,
const reflection::Field &field) {
switch (field.type()->base_type()) {
case reflection::Float: return GetFieldF<float>(table, field);
case reflection::Double: return GetFieldF<double>(table, field);
case reflection::String: {
auto s = GetFieldS(table, field);
return s ? strtod(s->c_str(), nullptr) : 0.0;
}
default: return static_cast<double>(GetAnyFieldI(table, field));
}
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
: field.default_real();
}
// Get any field as a string, regardless of what it is (bool/int/float/str).
// Get any table field as a string, regardless of what type it is.
// You may pass nullptr for the schema if you don't care to have fields that
// are of table type pretty-printed.
inline std::string GetAnyFieldS(const Table &table,
const reflection::Field &field,
const reflection::Schema &schema) {
switch (field.type()->base_type()) {
case reflection::Float:
case reflection::Double: return NumToString(GetAnyFieldF(table, field));
case reflection::String: {
auto s = GetFieldS(table, field);
return s ? s->c_str() : "";
}
case reflection::Obj: {
// Convert the table to a string. This is mostly for debugging purposes,
// and does NOT promise to be JSON compliant.
// Also prefixes the type.
auto &objectdef = *schema.objects()->Get(field.type()->index());
auto s = objectdef.name()->str();
if (objectdef.is_struct()) {
s += "(struct)"; // TODO: implement this as well.
} else {
auto table_field = GetFieldT(table, field);
s += " { ";
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
if (!table.CheckField(fielddef.offset())) continue;
auto val = GetAnyFieldS(*table_field, fielddef, schema);
if (fielddef.type()->base_type() == reflection::String)
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
s += fielddef.name()->str();
s += ": ";
s += val;
s += ", ";
}
s += "}";
}
return s;
}
case reflection::Vector:
return "[(elements)]"; // TODO: implement this as well.
case reflection::Union:
return "(union)"; // TODO: implement this as well.
default: return NumToString(GetAnyFieldI(table, field));
}
const reflection::Schema *schema) {
auto field_ptr = table.GetAddressOf(field.offset());
return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
field.type()->index())
: "";
}
// Get any struct field as a 64bit int, regardless of what type it is.
inline int64_t GetAnyFieldI(const Struct &st,
const reflection::Field &field) {
return GetAnyValueI(field.type()->base_type(),
st.GetAddressOf(field.offset()));
}
// Get any struct field as a double, regardless of what type it is.
inline double GetAnyFieldF(const Struct &st,
const reflection::Field &field) {
return GetAnyValueF(field.type()->base_type(),
st.GetAddressOf(field.offset()));
}
// Get any struct field as a string, regardless of what type it is.
inline std::string GetAnyFieldS(const Struct &st,
const reflection::Field &field) {
return GetAnyValueS(field.type()->base_type(),
st.GetAddressOf(field.offset()), nullptr, -1);
}
// Get any vector element as a 64bit int, regardless of what type it is.
inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
}
// Get any vector element as a double, regardless of what type it is.
inline double GetAnyVectorElemF(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
}
// Get any vector element as a string, regardless of what type it is.
inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
reflection::BaseType elem_type, size_t i) {
return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
nullptr, -1);
}
// Get a vector element that's a table/string/vector from a generic vector.
// Pass Table/String/VectorOfAny as template parameter.
// Warning: does no typechecking.
template<typename T> T *GetAnyVectorElemPointer(const VectorOfAny *vec,
size_t i) {
auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
return (T *)(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
}
// Get the inline-address of a vector element. Useful for Structs (pass Struct
// as template arg), or being able to address a range of scalars in-line.
// Get elem_size from GetTypeSizeInline().
// Note: little-endian data on all platforms, use EndianScalar() instead of
// raw pointer access with scalars).
template<typename T> T *GetAnyVectorElemAddressOf(const VectorOfAny *vec,
size_t i,
size_t elem_size) {
// C-cast to allow const conversion.
return (T *)(vec->Data() + elem_size * i);
}
// Similarly, for elements of tables.
template<typename T> T *GetAnyFieldAddressOf(const Table &table,
const reflection::Field &field) {
return (T *)table.GetAddressOf(field.offset());
}
// Similarly, for elements of structs.
template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
const reflection::Field &field) {
return (T *)st.GetAddressOf(field.offset());
}
// ------------------------- SETTERS -------------------------
// Set any scalar field, if you know its exact type.
template<typename T> bool SetField(Table *table, const reflection::Field &field,
T val) {
......@@ -177,77 +230,108 @@ template<typename T> bool SetField(Table *table, const reflection::Field &field,
return table->SetField(field.offset(), val);
}
// Set any field as a 64bit int, regardless of what it is (bool/int/float/str).
inline void SetAnyFieldI(Table *table, const reflection::Field &field,
// Raw helper functions used below: set any value in memory as a 64bit int, a
// double or a string.
// These work for all scalar values, but do nothing for other data types.
// To set a string, see SetString below.
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
// Set any table field as a 64bit int, regardless of type what it is.
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
int64_t val) {
# define FLATBUFFERS_SET(T) SetField<T>(table, field, static_cast<T>(val))
switch (field.type()->base_type()) {
case reflection::UType:
case reflection::Bool:
case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
case reflection::UShort: FLATBUFFERS_SET(uint16_t ); break;
case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
case reflection::UInt: FLATBUFFERS_SET(uint32_t ); break;
case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
case reflection::ULong: FLATBUFFERS_SET(uint64_t ); break;
case reflection::Float: FLATBUFFERS_SET(float ); break;
case reflection::Double: FLATBUFFERS_SET(double ); break;
// TODO: support strings
default: break;
}
# undef FLATBUFFERS_SET
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueI(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any field as a double, regardless of what it is (bool/int/float/str).
inline void SetAnyFieldF(Table *table, const reflection::Field &field,
// Set any table field as a double, regardless of what type it is.
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
double val) {
switch (field.type()->base_type()) {
case reflection::Float: SetField<float> (table, field,
static_cast<float>(val)); break;
case reflection::Double: SetField<double>(table, field, val); break;
// TODO: support strings.
default: SetAnyFieldI(table, field, static_cast<int64_t>(val)); break;
}
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueF(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any table field as a string, regardless of what type it is.
inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
const char *val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
SetAnyValueS(field.type()->base_type(), field_ptr, val);
return true;
}
// Set any field as a string, regardless of what it is (bool/int/float/str).
inline void SetAnyFieldS(Table *table, const reflection::Field &field,
// Set any struct field as a 64bit int, regardless of type what it is.
inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
int64_t val) {
SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any struct field as a double, regardless of type what it is.
inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
double val) {
SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any struct field as a string, regardless of type what it is.
inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
const char *val) {
switch (field.type()->base_type()) {
case reflection::Float:
case reflection::Double: SetAnyFieldF(table, field, strtod(val, nullptr));
// TODO: support strings.
default: SetAnyFieldI(table, field, StringToInt(val)); break;
}
SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
val);
}
// Set any vector element as a 64bit int, regardless of type what it is.
inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, int64_t val) {
SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// Set any vector element as a double, regardless of type what it is.
inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, double val) {
SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// Set any vector element as a string, regardless of type what it is.
inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
size_t i, const char *val) {
SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
}
// ------------------------- RESIZING SETTERS -------------------------
// "smart" pointer for use with resizing vectors: turns a pointer inside
// a vector into a relative offset, such that it is not affected by resizes.
template<typename T, typename U> class pointer_inside_vector {
public:
pointer_inside_vector(const T *ptr, const std::vector<U> &vec)
: offset_(reinterpret_cast<const uint8_t *>(ptr) -
reinterpret_cast<const uint8_t *>(vec.data())),
pointer_inside_vector(T *ptr, std::vector<U> &vec)
: offset_(reinterpret_cast<uint8_t *>(ptr) -
reinterpret_cast<uint8_t *>(vec.data())),
vec_(vec) {}
const T *operator*() const {
return reinterpret_cast<const T *>(
reinterpret_cast<const uint8_t *>(vec_.data()) + offset_);
T *operator*() const {
return reinterpret_cast<T *>(
reinterpret_cast<uint8_t *>(vec_.data()) + offset_);
}
const T *operator->() const {
T *operator->() const {
return operator*();
}
void operator=(const pointer_inside_vector &piv);
private:
size_t offset_;
const std::vector<U> &vec_;
std::vector<U> &vec_;
};
// Helper to create the above easily without specifying template args.
template<typename T, typename U> pointer_inside_vector<T, U> piv(
const T *ptr, const std::vector<U> &vec) {
template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr,
std::vector<U> &vec) {
return pointer_inside_vector<T, U>(ptr, vec);
}
......@@ -265,194 +349,66 @@ inline const reflection::Object &GetUnionType(
return *enumval->object();
}
// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
// and adjusting them by "delta" if they straddle the start offset.
// Once that is done, bytes can now be inserted/deleted safely.
// "delta" may be negative (shrinking).
// Unless "delta" is a multiple of the largest alignment, you'll create a small
// amount of garbage space in the buffer (usually 0..7 bytes).
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
class ResizeContext {
public:
ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr)
: schema_(schema), startptr_(flatbuf->data() + start),
delta_(delta), buf_(*flatbuf),
dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
delta_ = (delta_ + mask) & ~mask;
if (!delta_) return; // We can't shrink by less than largest_scalar_t.
// Now change all the offsets by delta_.
auto root = GetAnyRoot(buf_.data());
Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
// We can now add or remove bytes at start.
if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
}
// Check if the range between first (lower address) and second straddles
// the insertion point. If it does, change the offset at offsetloc (of
// type T, with direction D).
template<typename T, int D> void Straddle(void *first, void *second,
void *offsetloc) {
if (first <= startptr_ && second >= startptr_) {
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
DagCheck(offsetloc) = true;
}
}
// This returns a boolean that records if the corresponding offset location
// has been modified already. If so, we can't even read the corresponding
// offset, since it is pointing to a location that is illegal until the
// resize actually happens.
// This must be checked for every offset, since we can't know which offsets
// will straddle and which won't.
uint8_t &DagCheck(void *offsetloc) {
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
reinterpret_cast<uoffset_t *>(buf_.data());
return dag_check_[dag_idx];
}
void ResizeTable(const reflection::Object &objectdef, Table *table) {
if (DagCheck(table))
return; // Table already visited.
auto vtable = table->GetVTable();
// Check if the vtable offset points beyond the insertion point.
Straddle<soffset_t, -1>(table, vtable, table);
// This direction shouldn't happen because vtables that sit before tables
// are always directly adjacent, but check just in case we ever change the
// way flatbuffers are built.
Straddle<soffset_t, -1>(vtable, table, table);
// Early out: since all fields inside the table must point forwards in
// memory, if the insertion point is before the table we can stop here.
auto tableloc = reinterpret_cast<uint8_t *>(table);
if (startptr_ <= tableloc) return;
// Check each field.
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
auto base_type = fielddef.type()->base_type();
// Ignore scalars.
if (base_type <= reflection::Double) continue;
// Ignore fields that are not stored.
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
if (!offset) continue;
// Ignore structs.
auto subobjectdef = base_type == reflection::Obj ?
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
if (subobjectdef && subobjectdef->is_struct()) continue;
// Get this fields' offset, and read it if safe.
auto offsetloc = tableloc + offset;
if (DagCheck(offsetloc))
continue; // This offset already visited.
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
// Recurse.
switch (base_type) {
case reflection::Obj: {
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
break;
}
case reflection::Vector: {
auto elem_type = fielddef.type()->element();
if (elem_type != reflection::Obj && elem_type != reflection::String)
break;
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
auto elemobjectdef = elem_type == reflection::Obj
? schema_.objects()->Get(fielddef.type()->index())
: nullptr;
if (elemobjectdef && elemobjectdef->is_struct()) break;
for (uoffset_t i = 0; i < vec->size(); i++) {
auto loc = vec->Data() + i * sizeof(uoffset_t);
if (DagCheck(loc))
continue; // This offset already visited.
auto dest = loc + vec->Get(i);
Straddle<uoffset_t, 1>(loc, dest ,loc);
if (elemobjectdef)
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
}
break;
}
case reflection::Union: {
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
reinterpret_cast<Table *>(ref));
break;
}
case reflection::String:
break;
default:
assert(false);
}
}
}
void operator=(const ResizeContext &rc);
private:
const reflection::Schema &schema_;
uint8_t *startptr_;
int delta_;
std::vector<uint8_t> &buf_;
std::vector<uint8_t> dag_check_;
};
// Changes the contents of a string inside a FlatBuffer. FlatBuffer must
// live inside a std::vector so we can resize the buffer if needed.
// "str" must live inside "flatbuf" and may be invalidated after this call.
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
inline void SetString(const reflection::Schema &schema, const std::string &val,
const String *str, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr) {
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
flatbuf->data() +
sizeof(uoffset_t));
if (delta) {
// Different size, we must expand (or contract).
ResizeContext(schema, start, delta, flatbuf, root_table);
if (delta < 0) {
// Clear the old string, since we don't want parts of it remaining.
memset(flatbuf->data() + start, 0, str->Length());
}
}
// Copy new data. Safe because we created the right amount of space.
memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
}
void SetString(const reflection::Schema &schema, const std::string &val,
const String *str, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
// live inside a std::vector so we can resize the buffer if needed.
// "vec" must live inside "flatbuf" and may be invalidated after this call.
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
const VectorOfAny *vec, uoffset_t num_elems,
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr);
template <typename T>
void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr) {
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
auto delta_bytes = delta_elem * static_cast<int>(sizeof(T));
auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
sizeof(T) * vec->size());
if (delta_bytes) {
ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
WriteScalar(flatbuf->data() + vec_start, newsize); // Length field.
// Set new elements to "val".
for (int i = 0; i < delta_elem; i++) {
auto loc = flatbuf->data() + start + i * sizeof(T);
auto is_scalar = std::is_scalar<T>::value;
if (is_scalar) {
WriteScalar(loc, val);
} else { // struct
*reinterpret_cast<T *>(loc) = val;
}
auto newelems = ResizeAnyVector(schema, newsize,
reinterpret_cast<const VectorOfAny *>(vec),
vec->size(),
static_cast<uoffset_t>(sizeof(T)), flatbuf,
root_table);
// Set new elements to "val".
for (int i = 0; i < delta_elem; i++) {
auto loc = newelems + i * sizeof(T);
auto is_scalar = std::is_scalar<T>::value;
if (is_scalar) {
WriteScalar(loc, val);
} else { // struct
*reinterpret_cast<T *>(loc) = val;
}
}
}
// Adds any new data (in the form of a new FlatBuffer) to an existing
// FlatBuffer. This can be used when any of the above methods are not
// sufficient, in particular for adding new tables and new fields.
// This is potentially slightly less efficient than a FlatBuffer constructed
// in one piece, since the new FlatBuffer doesn't share any vtables with the
// existing one.
// The return value can now be set using Vector::MutateOffset or SetFieldT
// below.
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
const uint8_t *newbuf, size_t newlen);
inline bool SetFieldT(Table *table, const reflection::Field &field,
const uint8_t *val) {
assert(sizeof(uoffset_t) == GetTypeSize(field.type()->base_type()));
return table->SetPointer(field.offset(), val);
}
// ------------------------- COPYING -------------------------
// Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
// Can be used to do any kind of merging/selecting you may want to do out
// of existing buffers. Also useful to reconstruct a whole buffer if the
......@@ -461,134 +417,10 @@ void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
// Note: this does not deal with DAGs correctly. If the table passed forms a
// DAG, the copy will be a tree instead (with duplicates).
inline void CopyInline(FlatBufferBuilder &fbb,
const reflection::Field &fielddef,
const Table &table,
size_t align, size_t size) {
fbb.Align(align);
fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
fbb.TrackField(fielddef.offset(), fbb.GetSize());
}
inline Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
const reflection::Schema &schema,
const reflection::Object &objectdef,
const Table &table) {
// Before we can construct the table, we have to first generate any
// subobjects, and collect their offsets.
std::vector<uoffset_t> offsets;
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
// Skip if field is not present in the source.
if (!table.CheckField(fielddef.offset())) continue;
uoffset_t offset = 0;
switch (fielddef.type()->base_type()) {
case reflection::String: {
offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
break;
}
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (!subobjectdef.is_struct()) {
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef)).o;
}
break;
}
case reflection::Union: {
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef)).o;
break;
}
case reflection::Vector: {
auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
fielddef.offset());
auto element_base_type = fielddef.type()->element();
auto elemobjectdef = element_base_type == reflection::Obj
? schema.objects()->Get(fielddef.type()->index())
: nullptr;
switch (element_base_type) {
case reflection::String: {
std::vector<Offset<const String *>> elements(vec->size());
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
for (uoffset_t i = 0; i < vec_s->size(); i++) {
elements[i] = fbb.CreateString(vec_s->Get(i)).o;
}
offset = fbb.CreateVector(elements).o;
break;
}
case reflection::Obj: {
if (!elemobjectdef->is_struct()) {
std::vector<Offset<const Table *>> elements(vec->size());
for (uoffset_t i = 0; i < vec->size(); i++) {
elements[i] =
CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
}
offset = fbb.CreateVector(elements).o;
break;
}
// FALL-THRU:
}
default: { // Scalars and structs.
auto element_size = GetTypeSize(element_base_type);
if (elemobjectdef && elemobjectdef->is_struct())
element_size = elemobjectdef->bytesize();
fbb.StartVector(element_size, vec->size());
fbb.PushBytes(vec->Data(), element_size * vec->size());
offset = fbb.EndVector(vec->size());
break;
}
}
break;
}
default: // Scalars.
break;
}
if (offset) {
offsets.push_back(offset);
}
}
// Now we can build the actual table from either offsets or scalar data.
auto start = objectdef.is_struct()
? fbb.StartStruct(objectdef.minalign())
: fbb.StartTable();
size_t offset_idx = 0;
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
if (!table.CheckField(fielddef.offset())) continue;
auto base_type = fielddef.type()->base_type();
switch (base_type) {
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (subobjectdef.is_struct()) {
CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
subobjectdef.bytesize());
break;
}
// else: FALL-THRU:
}
case reflection::Union:
case reflection::String:
case reflection::Vector:
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
break;
default: { // Scalars.
auto size = GetTypeSize(base_type);
CopyInline(fbb, fielddef, table, size, size);
break;
}
}
}
assert(offset_idx == offsets.size());
if (objectdef.is_struct()) {
fbb.ClearOffsets();
return fbb.EndStruct();
} else {
return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
}
}
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
const reflection::Schema &schema,
const reflection::Object &objectdef,
const Table &table);
} // namespace flatbuffers
......
......@@ -48,6 +48,11 @@ namespace FlatBuffers
set { _pos = value; }
}
public void Reset()
{
_pos = 0;
}
// Pre-allocated helper arrays for convertion.
private float[] floathelper = new[] { 0.0f };
private int[] inthelper = new[] { 0 };
......
/*
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
......@@ -49,6 +49,17 @@ namespace FlatBuffers
_bb = new ByteBuffer(new byte[initialSize]);
}
public void Clear()
{
_space = _bb.Length;
_bb.Reset();
_minAlign = 1;
_vtable = null;
_objectStart = 0;
_vtables = new int[16];
_numVtables = 0;
_vectorNumElems = 0;
}
public int Offset { get { return _bb.Length - _space; } }
......@@ -195,10 +206,10 @@ namespace FlatBuffers
Prep(alignment, elemSize * count); // Just in case alignment > int.
}
public int EndVector()
public VectorOffset EndVector()
{
PutInt(_vectorNumElems);
return Offset;
return new VectorOffset(Offset);
}
public void Nested(int obj)
......@@ -249,7 +260,7 @@ namespace FlatBuffers
public void AddDouble(int o, double x, double d) { if (x != d) { AddDouble(x); Slot(o); } }
public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
public int CreateString(string s)
public StringOffset CreateString(string s)
{
NotNested();
byte[] utf8 = Encoding.UTF8.GetBytes(s);
......@@ -257,7 +268,7 @@ namespace FlatBuffers
StartVector(1, utf8.Length, 1);
Buffer.BlockCopy(utf8, 0, _bb.Data, _space -= utf8.Length,
utf8.Length);
return EndVector();
return new StringOffset(EndVector().Value);
}
// Structs are stored inline, so nothing additional is being added.
......
......@@ -37,6 +37,7 @@
<Compile Include="ByteBuffer.cs" />
<Compile Include="FlatBufferBuilder.cs" />
<Compile Include="FlatBufferConstants.cs" />
<Compile Include="Offset.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Struct.cs" />
<Compile Include="Table.cs" />
......
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace FlatBuffers
{
/// <summary>
/// Offset class for typesafe assignments.
/// </summary>
public struct Offset<T> where T : class
{
public int Value;
public Offset(int value)
{
Value = value;
}
}
public struct StringOffset
{
public int Value;
public StringOffset(int value)
{
Value = value;
}
}
public struct VectorOffset
{
public int Value;
public VectorOffset(int value)
{
Value = value;
}
}
}
......@@ -90,7 +90,9 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" --defaults-json Output fields whose value is the default when\n"
" writing JSON\n"
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
" --gen-includes (deprecated), instead use:\n"
" --gen-includes (deprecated), this is the default behavior.\n"
" If the original behavior is required (no include\n"
" statements) use --no-includes.\n"
" --no-includes Don\'t generate include statements for included\n"
" schemas the generated file depends on (C++).\n"
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
......
......@@ -19,6 +19,7 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#include <algorithm>
namespace flatbuffers {
......@@ -202,6 +203,10 @@ static std::string GenTypeBasic(const LanguageParameters &lang,
#undef FLATBUFFERS_TD
};
if(lang.language == GeneratorOptions::kCSharp && type.base_type == BASE_TYPE_STRUCT) {
return "Offset<" + type.struct_def->name + ">";
}
return gtypename[type.base_type * GeneratorOptions::kMAX + lang.language];
}
......@@ -258,6 +263,32 @@ static Type DestinationType(const LanguageParameters &lang, const Type &type,
}
}
static std::string GenOffsetType(const LanguageParameters &lang, const StructDef &struct_def) {
if(lang.language == GeneratorOptions::kCSharp) {
return "Offset<" + struct_def.name + ">";
} else {
return "int";
}
}
static std::string GenOffsetConstruct(const LanguageParameters &lang,
const StructDef &struct_def,
const std::string &variable_name)
{
if(lang.language == GeneratorOptions::kCSharp) {
return "new Offset<" + struct_def.name + ">(" + variable_name + ")";
}
return variable_name;
}
static std::string GenVectorOffsetType(const LanguageParameters &lang) {
if(lang.language == GeneratorOptions::kCSharp) {
return "VectorOffset";
} else {
return "int";
}
}
// Generate destination type name
static std::string GenTypeNameDest(const LanguageParameters &lang, const Type &type)
{
......@@ -353,7 +384,20 @@ static std::string SourceCast(const LanguageParameters &lang,
return "";
}
static std::string GenDefaultValue(const Value &value) {
static std::string GenDefaultValue(const LanguageParameters &lang, const Value &value, bool for_buffer) {
if(lang.language == GeneratorOptions::kCSharp && !for_buffer) {
switch(value.type.base_type) {
case BASE_TYPE_STRING:
return "default(StringOffset)";
case BASE_TYPE_STRUCT:
return "default(Offset<" + value.type.struct_def->name + ">)";
case BASE_TYPE_VECTOR:
return "default(VectorOffset)";
default:
break;
}
}
return value.type.base_type == BASE_TYPE_BOOL
? (value.constant == "0" ? "false" : "true")
: value.constant;
......@@ -658,7 +702,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
} else {
code += offset_prefix + getter;
code += "(o + bb_pos)" + dest_mask + " : " + default_cast;
code += GenDefaultValue(field.value);
code += GenDefaultValue(lang, field.value, false);
}
} else {
switch (field.value.type.base_type) {
......@@ -765,13 +809,14 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "\n";
if (struct_def.fixed) {
// create a struct constructor function
code += " public static int " + FunctionStart(lang, 'C') + "reate";
code += " public static " + GenOffsetType(lang, struct_def) + " ";
code += FunctionStart(lang, 'C') + "reate";
code += struct_def.name + "(FlatBufferBuilder builder";
GenStructArgs(lang, struct_def, code_ptr, "");
code += ") {\n";
GenStructBody(lang, struct_def, code_ptr, "");
code += " return builder.";
code += lang.get_fbb_offset;
code += " return ";
code += GenOffsetConstruct(lang, struct_def, "builder." + std::string(lang.get_fbb_offset));
code += ";\n }\n";
} else {
// Generate a method that creates a table in one go. This is only possible
......@@ -791,9 +836,9 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
if (has_no_struct_fields && num_fields) {
// Generate a table constructor of the form:
// public static void createName(FlatBufferBuilder builder, args...)
code += " public static int " + FunctionStart(lang, 'C') + "reate";
code += struct_def.name;
// public static int createName(FlatBufferBuilder builder, args...)
code += " public static " + GenOffsetType(lang, struct_def) + " ";
code += FunctionStart(lang, 'C') + "reate" + struct_def.name;
code += "(FlatBufferBuilder builder";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
......@@ -807,7 +852,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// Java doesn't have defaults, which means this method must always
// supply all arguments, and thus won't compile when fields are added.
if (lang.language != GeneratorOptions::kJava) {
code += " = " + GenDefaultValue(field.value);
code += " = " + GenDefaultValue(lang, field.value, false);
}
}
code += ") {\n builder.";
......@@ -857,7 +902,10 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += GenMethod(lang, field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
code += DestinationValue(lang, argname, field.value.type);
code += ", " + GenDefaultValue(field.value);
if(!IsScalar(field.value.type.base_type) && field.value.type.base_type != BASE_TYPE_UNION && lang.language == GeneratorOptions::kCSharp) {
code += ".Value";
}
code += ", " + GenDefaultValue(lang, field.value, true);
code += "); }\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
auto vector_type = field.value.type.VectorType();
......@@ -865,7 +913,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
auto elem_size = InlineSize(vector_type);
if (!IsStruct(vector_type)) {
// Generate a method to create a vector from a Java array.
code += " public static int " + FunctionStart(lang, 'C') + "reate";
code += " public static " + GenVectorOffsetType(lang) + " " + FunctionStart(lang, 'C') + "reate";
code += MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, ";
code += GenTypeBasic(lang, vector_type) + "[] data) ";
......@@ -877,8 +925,12 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += FunctionStart(lang, 'L') + "ength - 1; i >= 0; i--) builder.";
code += FunctionStart(lang, 'A') + "dd";
code += GenMethod(lang, vector_type);
code += "(data[i]); return builder.";
code += FunctionStart(lang, 'E') + "ndVector(); }\n";
code += "(data[i]";
if(lang.language == GeneratorOptions::kCSharp &&
(vector_type.base_type == BASE_TYPE_STRUCT || vector_type.base_type == BASE_TYPE_STRING))
code += ".Value";
code += "); return ";
code += "builder." + FunctionStart(lang, 'E') + "ndVector(); }\n";
}
// Generate a method to start a vector, data to be added manually after.
code += " public static void " + FunctionStart(lang, 'S') + "tart";
......@@ -890,7 +942,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "); }\n";
}
}
code += " public static int ";
code += " public static " + GenOffsetType(lang, struct_def) + " ";
code += FunctionStart(lang, 'E') + "nd" + struct_def.name;
code += "(FlatBufferBuilder builder) {\n int o = builder.";
code += FunctionStart(lang, 'E') + "ndObject();\n";
......@@ -904,12 +956,16 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += "); // " + field.name + "\n";
}
}
code += " return o;\n }\n";
code += " return " + GenOffsetConstruct(lang, struct_def, "o") + ";\n }\n";
if (parser.root_struct_def_ == &struct_def) {
code += " public static void ";
code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
code += "Buffer(FlatBufferBuilder builder, int offset) { ";
code += "builder." + FunctionStart(lang, 'F') + "inish(offset";
code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(lang, struct_def) + " offset) {";
code += " builder." + FunctionStart(lang, 'F') + "inish(offset";
if (lang.language == GeneratorOptions::kCSharp) {
code += ".Value";
}
if (parser.file_identifier_.length())
code += ", \"" + parser.file_identifier_ + "\"";
code += "); }\n";
......
......@@ -918,10 +918,10 @@ void Parser::ParseDecl() {
auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
if (force_align->type.base_type != BASE_TYPE_INT ||
align < struct_def.minalign ||
align > 256 ||
align > 16 ||
align & (align - 1))
Error("force_align must be a power of two integer ranging from the"
"struct\'s natural alignment to 256");
"struct\'s natural alignment to 16");
struct_def.minalign = align;
}
struct_def.PadLastField(struct_def.minalign);
......
/*
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flatbuffers/reflection.h"
#include "flatbuffers/util.h"
// Helper functionality for reflection.
namespace flatbuffers {
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
# define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
switch (type) {
case reflection::UType:
case reflection::Bool:
case reflection::UByte: return FLATBUFFERS_GET(uint8_t);
case reflection::Byte: return FLATBUFFERS_GET(int8_t);
case reflection::Short: return FLATBUFFERS_GET(int16_t);
case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
case reflection::Int: return FLATBUFFERS_GET(int32_t);
case reflection::UInt: return FLATBUFFERS_GET(uint32_t);
case reflection::Long: return FLATBUFFERS_GET(int64_t);
case reflection::ULong: return FLATBUFFERS_GET(uint64_t);
case reflection::Float: return FLATBUFFERS_GET(float);
case reflection::Double: return FLATBUFFERS_GET(double);
case reflection::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? StringToInt(s->c_str()) : 0;
}
default: return 0; // Tables & vectors do not make sense.
}
# undef FLATBUFFERS_GET
}
double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
switch (type) {
case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
case reflection::Double: return ReadScalar<double>(data);
case reflection::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? strtod(s->c_str(), nullptr) : 0.0;
}
default: return static_cast<double>(GetAnyValueI(type, data));
}
}
std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
const reflection::Schema *schema, int type_index) {
switch (type) {
case reflection::Float:
case reflection::Double: return NumToString(GetAnyValueF(type, data));
case reflection::String: {
auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
data);
return s ? s->c_str() : "";
}
case reflection::Obj:
if (schema) {
// Convert the table to a string. This is mostly for debugging purposes,
// and does NOT promise to be JSON compliant.
// Also prefixes the type.
auto &objectdef = *schema->objects()->Get(type_index);
auto s = objectdef.name()->str();
if (objectdef.is_struct()) {
s += "(struct)"; // TODO: implement this as well.
} else {
auto table_field = reinterpret_cast<const Table *>(
ReadScalar<uoffset_t>(data) + data);
s += " { ";
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
if (!table_field->CheckField(fielddef.offset())) continue;
auto val = GetAnyFieldS(*table_field, fielddef, schema);
if (fielddef.type()->base_type() == reflection::String)
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
s += fielddef.name()->str();
s += ": ";
s += val;
s += ", ";
}
s += "}";
}
return s;
} else {
return "(table)";
}
case reflection::Vector:
return "[(elements)]"; // TODO: implement this as well.
case reflection::Union:
return "(union)"; // TODO: implement this as well.
default: return NumToString(GetAnyValueI(type, data));
}
}
void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
# define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
switch (type) {
case reflection::UType:
case reflection::Bool:
case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
case reflection::UInt: FLATBUFFERS_SET(uint32_t); break;
case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
case reflection::ULong: FLATBUFFERS_SET(uint64_t); break;
case reflection::Float: FLATBUFFERS_SET(float ); break;
case reflection::Double: FLATBUFFERS_SET(double ); break;
// TODO: support strings
default: break;
}
# undef FLATBUFFERS_SET
}
void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
switch (type) {
case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
case reflection::Double: WriteScalar(data, val); break;
// TODO: support strings.
default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
}
}
void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
switch (type) {
case reflection::Float:
case reflection::Double:
SetAnyValueF(type, data, strtod(val, nullptr));
break;
// TODO: support strings.
default: SetAnyValueI(type, data, StringToInt(val)); break;
}
}
// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
// and adjusting them by "delta" if they straddle the start offset.
// Once that is done, bytes can now be inserted/deleted safely.
// "delta" may be negative (shrinking).
// Unless "delta" is a multiple of the largest alignment, you'll create a small
// amount of garbage space in the buffer (usually 0..7 bytes).
// If your FlatBuffer's root table is not the schema's root table, you should
// pass in your root_table type as well.
class ResizeContext {
public:
ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table = nullptr)
: schema_(schema), startptr_(flatbuf->data() + start),
delta_(delta), buf_(*flatbuf),
dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
delta_ = (delta_ + mask) & ~mask;
if (!delta_) return; // We can't shrink by less than largest_scalar_t.
// Now change all the offsets by delta_.
auto root = GetAnyRoot(buf_.data());
Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
// We can now add or remove bytes at start.
if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
}
// Check if the range between first (lower address) and second straddles
// the insertion point. If it does, change the offset at offsetloc (of
// type T, with direction D).
template<typename T, int D> void Straddle(void *first, void *second,
void *offsetloc) {
if (first <= startptr_ && second >= startptr_) {
WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
DagCheck(offsetloc) = true;
}
}
// This returns a boolean that records if the corresponding offset location
// has been modified already. If so, we can't even read the corresponding
// offset, since it is pointing to a location that is illegal until the
// resize actually happens.
// This must be checked for every offset, since we can't know which offsets
// will straddle and which won't.
uint8_t &DagCheck(void *offsetloc) {
auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
reinterpret_cast<uoffset_t *>(buf_.data());
return dag_check_[dag_idx];
}
void ResizeTable(const reflection::Object &objectdef, Table *table) {
if (DagCheck(table))
return; // Table already visited.
auto vtable = table->GetVTable();
// Check if the vtable offset points beyond the insertion point.
Straddle<soffset_t, -1>(table, vtable, table);
// This direction shouldn't happen because vtables that sit before tables
// are always directly adjacent, but check just in case we ever change the
// way flatbuffers are built.
Straddle<soffset_t, -1>(vtable, table, table);
// Early out: since all fields inside the table must point forwards in
// memory, if the insertion point is before the table we can stop here.
auto tableloc = reinterpret_cast<uint8_t *>(table);
if (startptr_ <= tableloc) return;
// Check each field.
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
auto base_type = fielddef.type()->base_type();
// Ignore scalars.
if (base_type <= reflection::Double) continue;
// Ignore fields that are not stored.
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
if (!offset) continue;
// Ignore structs.
auto subobjectdef = base_type == reflection::Obj ?
schema_.objects()->Get(fielddef.type()->index()) : nullptr;
if (subobjectdef && subobjectdef->is_struct()) continue;
// Get this fields' offset, and read it if safe.
auto offsetloc = tableloc + offset;
if (DagCheck(offsetloc))
continue; // This offset already visited.
auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
// Recurse.
switch (base_type) {
case reflection::Obj: {
ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
break;
}
case reflection::Vector: {
auto elem_type = fielddef.type()->element();
if (elem_type != reflection::Obj && elem_type != reflection::String)
break;
auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
auto elemobjectdef = elem_type == reflection::Obj
? schema_.objects()->Get(fielddef.type()->index())
: nullptr;
if (elemobjectdef && elemobjectdef->is_struct()) break;
for (uoffset_t i = 0; i < vec->size(); i++) {
auto loc = vec->Data() + i * sizeof(uoffset_t);
if (DagCheck(loc))
continue; // This offset already visited.
auto dest = loc + vec->Get(i);
Straddle<uoffset_t, 1>(loc, dest ,loc);
if (elemobjectdef)
ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
}
break;
}
case reflection::Union: {
ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
reinterpret_cast<Table *>(ref));
break;
}
case reflection::String:
break;
default:
assert(false);
}
}
}
void operator=(const ResizeContext &rc);
private:
const reflection::Schema &schema_;
uint8_t *startptr_;
int delta_;
std::vector<uint8_t> &buf_;
std::vector<uint8_t> dag_check_;
};
void SetString(const reflection::Schema &schema, const std::string &val,
const String *str, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table) {
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
flatbuf->data() +
sizeof(uoffset_t));
if (delta) {
// Clear the old string, since we don't want parts of it remaining.
memset(flatbuf->data() + start, 0, str->Length());
// Different size, we must expand (or contract).
ResizeContext(schema, start, delta, flatbuf, root_table);
}
// Copy new data. Safe because we created the right amount of space.
memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
}
uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
const VectorOfAny *vec, uoffset_t num_elems,
uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
const reflection::Object *root_table) {
auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
auto delta_bytes = delta_elem * static_cast<int>(elem_size);
auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
elem_size * num_elems);
if (delta_bytes) {
if (delta_elem < 0) {
// Clear elements we're throwing away, since some might remain in the
// buffer.
auto size_clear = -delta_elem * elem_size;
memset(flatbuf->data() + start - size_clear, 0, size_clear);
}
ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
WriteScalar(flatbuf->data() + vec_start, newsize); // Length field.
// Set new elements to 0.. this can be overwritten by the caller.
if (delta_elem > 0) {
memset(flatbuf->data() + start, 0, delta_elem * elem_size);
}
}
return flatbuf->data() + start;
}
const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
const uint8_t *newbuf, size_t newlen) {
// Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
// going to chop off the root offset.
while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
!(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
flatbuf.push_back(0);
}
auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
// Insert the entire FlatBuffer minus the root pointer.
flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
return flatbuf.data() + insertion_point + root_offset;
}
void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
const Table &table, size_t align, size_t size) {
fbb.Align(align);
fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
fbb.TrackField(fielddef.offset(), fbb.GetSize());
}
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
const reflection::Schema &schema,
const reflection::Object &objectdef,
const Table &table) {
// Before we can construct the table, we have to first generate any
// subobjects, and collect their offsets.
std::vector<uoffset_t> offsets;
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
// Skip if field is not present in the source.
if (!table.CheckField(fielddef.offset())) continue;
uoffset_t offset = 0;
switch (fielddef.type()->base_type()) {
case reflection::String: {
offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
break;
}
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (!subobjectdef.is_struct()) {
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef)).o;
}
break;
}
case reflection::Union: {
auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
offset = CopyTable(fbb, schema, subobjectdef,
*GetFieldT(table, fielddef)).o;
break;
}
case reflection::Vector: {
auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
fielddef.offset());
auto element_base_type = fielddef.type()->element();
auto elemobjectdef = element_base_type == reflection::Obj
? schema.objects()->Get(fielddef.type()->index())
: nullptr;
switch (element_base_type) {
case reflection::String: {
std::vector<Offset<const String *>> elements(vec->size());
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
for (uoffset_t i = 0; i < vec_s->size(); i++) {
elements[i] = fbb.CreateString(vec_s->Get(i)).o;
}
offset = fbb.CreateVector(elements).o;
break;
}
case reflection::Obj: {
if (!elemobjectdef->is_struct()) {
std::vector<Offset<const Table *>> elements(vec->size());
for (uoffset_t i = 0; i < vec->size(); i++) {
elements[i] =
CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
}
offset = fbb.CreateVector(elements).o;
break;
}
// FALL-THRU:
}
default: { // Scalars and structs.
auto element_size = GetTypeSize(element_base_type);
if (elemobjectdef && elemobjectdef->is_struct())
element_size = elemobjectdef->bytesize();
fbb.StartVector(element_size, vec->size());
fbb.PushBytes(vec->Data(), element_size * vec->size());
offset = fbb.EndVector(vec->size());
break;
}
}
break;
}
default: // Scalars.
break;
}
if (offset) {
offsets.push_back(offset);
}
}
// Now we can build the actual table from either offsets or scalar data.
auto start = objectdef.is_struct()
? fbb.StartStruct(objectdef.minalign())
: fbb.StartTable();
size_t offset_idx = 0;
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
if (!table.CheckField(fielddef.offset())) continue;
auto base_type = fielddef.type()->base_type();
switch (base_type) {
case reflection::Obj: {
auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
if (subobjectdef.is_struct()) {
CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
subobjectdef.bytesize());
break;
}
// else: FALL-THRU:
}
case reflection::Union:
case reflection::String:
case reflection::Vector:
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
break;
default: { // Scalars.
auto size = GetTypeSize(base_type);
CopyInline(fbb, fielddef, table, size, size);
break;
}
}
}
assert(offset_idx == offsets.size());
if (objectdef.is_struct()) {
fbb.ClearOffsets();
return fbb.EndStruct();
} else {
return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
}
}
} // namespace flatbuffers
......@@ -41,6 +41,9 @@
<Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs">
<Link>FlatBuffers\ByteBuffer.cs</Link>
</Compile>
<Compile Include="..\..\net\FlatBuffers\Offset.cs">
<Link>FlatBuffers\Offset.cs</Link>
</Compile>
<Compile Include="..\..\net\FlatBuffers\FlatBufferBuilder.cs">
<Link>FlatBuffers\FlatBufferBuilder.cs</Link>
</Compile>
......
......@@ -61,8 +61,8 @@ namespace FlatBuffers.Test
var test4 = fbb.EndVector();
Monster.StartTestarrayofstringVector(fbb, 2);
fbb.AddOffset(test2);
fbb.AddOffset(test1);
fbb.AddOffset(test2.Value);
fbb.AddOffset(test1.Value);
var testArrayOfString = fbb.EndVector();
Monster.StartMonster(fbb);
......@@ -72,7 +72,7 @@ namespace FlatBuffers.Test
Monster.AddName(fbb, str);
Monster.AddInventory(fbb, inv);
Monster.AddTestType(fbb, Any.Monster);
Monster.AddTest(fbb, mon2);
Monster.AddTest(fbb, mon2.Value);
Monster.AddTest4(fbb, test4);
Monster.AddTestarrayofstring(fbb, testArrayOfString);
Monster.AddTestbool(fbb, false);
......@@ -80,6 +80,7 @@ namespace FlatBuffers.Test
Monster.FinishMonsterBuffer(fbb, mon);
// Dump to output directory so we can inspect later, if needed
using (var ms = new MemoryStream(fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset))
{
......
......@@ -61,29 +61,29 @@ public sealed class Monster : Table {
public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.PutUlong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(24); }
public static void AddPos(FlatBufferBuilder builder, int posOffset) { builder.AddStruct(0, posOffset, 0); }
public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
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 int CreateInventoryVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
public static void AddName(FlatBufferBuilder builder, StringOffset nameOffset) { builder.AddOffset(3, nameOffset.Value, 0); }
public static void AddInventory(FlatBufferBuilder builder, VectorOffset inventoryOffset) { builder.AddOffset(5, inventoryOffset.Value, 0); }
public static VectorOffset CreateInventoryVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
public static void StartInventoryVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
public static void AddColor(FlatBufferBuilder builder, Color color) { builder.AddSbyte(6, (sbyte)(color), 8); }
public static void AddTestType(FlatBufferBuilder builder, Any testType) { builder.AddByte(7, (byte)(testType), 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, VectorOffset test4Offset) { builder.AddOffset(9, test4Offset.Value, 0); }
public static void StartTest4Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 2); }
public static void AddTestarrayofstring(FlatBufferBuilder builder, int testarrayofstringOffset) { builder.AddOffset(10, testarrayofstringOffset, 0); }
public static int CreateTestarrayofstringVector(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i]); return builder.EndVector(); }
public static void AddTestarrayofstring(FlatBufferBuilder builder, VectorOffset testarrayofstringOffset) { builder.AddOffset(10, testarrayofstringOffset.Value, 0); }
public static VectorOffset CreateTestarrayofstringVector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
public static void StartTestarrayofstringVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
public static void AddTestarrayoftables(FlatBufferBuilder builder, int testarrayoftablesOffset) { builder.AddOffset(11, testarrayoftablesOffset, 0); }
public static int CreateTestarrayoftablesVector(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i]); return builder.EndVector(); }
public static void AddTestarrayoftables(FlatBufferBuilder builder, VectorOffset testarrayoftablesOffset) { builder.AddOffset(11, testarrayoftablesOffset.Value, 0); }
public static VectorOffset CreateTestarrayoftablesVector(FlatBufferBuilder builder, Offset<Monster>[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
public static void StartTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
public static void AddEnemy(FlatBufferBuilder builder, int enemyOffset) { builder.AddOffset(12, enemyOffset, 0); }
public static void AddTestnestedflatbuffer(FlatBufferBuilder builder, int testnestedflatbufferOffset) { builder.AddOffset(13, testnestedflatbufferOffset, 0); }
public static int CreateTestnestedflatbufferVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
public static void AddEnemy(FlatBufferBuilder builder, Offset<Monster> enemyOffset) { builder.AddOffset(12, enemyOffset.Value, 0); }
public static void AddTestnestedflatbuffer(FlatBufferBuilder builder, VectorOffset testnestedflatbufferOffset) { builder.AddOffset(13, testnestedflatbufferOffset.Value, 0); }
public static VectorOffset CreateTestnestedflatbufferVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
public static void StartTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
public static void AddTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.AddOffset(14, testemptyOffset, 0); }
public static void AddTestempty(FlatBufferBuilder builder, Offset<Stat> testemptyOffset) { builder.AddOffset(14, testemptyOffset.Value, 0); }
public static void AddTestbool(FlatBufferBuilder builder, bool testbool) { builder.AddBool(15, testbool, false); }
public static void AddTesthashs32Fnv1(FlatBufferBuilder builder, int testhashs32Fnv1) { builder.AddInt(16, testhashs32Fnv1, 0); }
public static void AddTesthashu32Fnv1(FlatBufferBuilder builder, uint testhashu32Fnv1) { builder.AddUint(17, testhashu32Fnv1, 0); }
......@@ -93,12 +93,12 @@ public sealed class Monster : Table {
public static void AddTesthashu32Fnv1a(FlatBufferBuilder builder, uint testhashu32Fnv1a) { builder.AddUint(21, testhashu32Fnv1a, 0); }
public static void AddTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.AddLong(22, testhashs64Fnv1a, 0); }
public static void AddTesthashu64Fnv1a(FlatBufferBuilder builder, ulong testhashu64Fnv1a) { builder.AddUlong(23, testhashu64Fnv1a, 0); }
public static int EndMonster(FlatBufferBuilder builder) {
public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndObject();
builder.Required(o, 10); // name
return o;
return new Offset<Monster>(o);
}
public static void FinishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.Finish(offset, "MONS"); }
public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
};
......
......@@ -16,8 +16,8 @@ public sealed class Stat : Table {
public ushort Count { get { int o = __offset(8); return o != 0 ? bb.GetUshort(o + bb_pos) : (ushort)0; } }
public bool MutateCount(ushort count) { int o = __offset(8); if (o != 0) { bb.PutUshort(o + bb_pos, count); return true; } else { return false; } }
public static int CreateStat(FlatBufferBuilder builder,
int id = 0,
public static Offset<Stat> CreateStat(FlatBufferBuilder builder,
StringOffset id = default(StringOffset),
long val = 0,
ushort count = 0) {
builder.StartObject(3);
......@@ -28,12 +28,12 @@ public sealed class Stat : Table {
}
public static void StartStat(FlatBufferBuilder builder) { builder.StartObject(3); }
public static void AddId(FlatBufferBuilder builder, int idOffset) { builder.AddOffset(0, idOffset, 0); }
public static void AddId(FlatBufferBuilder builder, StringOffset idOffset) { builder.AddOffset(0, idOffset.Value, 0); }
public static void AddVal(FlatBufferBuilder builder, long val) { builder.AddLong(1, val, 0); }
public static void AddCount(FlatBufferBuilder builder, ushort count) { builder.AddUshort(2, count, 0); }
public static int EndStat(FlatBufferBuilder builder) {
public static Offset<Stat> EndStat(FlatBufferBuilder builder) {
int o = builder.EndObject();
return o;
return new Offset<Stat>(o);
}
};
......
......@@ -13,12 +13,12 @@ public sealed class Test : Struct {
public sbyte B { get { return bb.GetSbyte(bb_pos + 2); } }
public void MutateB(sbyte b) { bb.PutSbyte(bb_pos + 2, b); }
public static int CreateTest(FlatBufferBuilder builder, short A, sbyte B) {
public static Offset<Test> CreateTest(FlatBufferBuilder builder, short A, sbyte B) {
builder.Prep(2, 4);
builder.Pad(1);
builder.PutSbyte(B);
builder.PutShort(A);
return builder.Offset;
return new Offset<Test>(builder.Offset);
}
};
......
......@@ -21,7 +21,7 @@ public sealed class Vec3 : Struct {
public Test Test3 { get { return GetTest3(new Test()); } }
public Test GetTest3(Test obj) { return obj.__init(bb_pos + 26, bb); }
public static int CreateVec3(FlatBufferBuilder builder, float X, float Y, float Z, double Test1, Color Test2, short test3_A, sbyte test3_B) {
public static Offset<Vec3> CreateVec3(FlatBufferBuilder builder, float X, float Y, float Z, double Test1, Color Test2, short test3_A, sbyte test3_B) {
builder.Prep(16, 32);
builder.Pad(2);
builder.Prep(2, 4);
......@@ -35,7 +35,7 @@ public sealed class Vec3 : Struct {
builder.PutFloat(Z);
builder.PutFloat(Y);
builder.PutFloat(X);
return builder.Offset;
return new Offset<Vec3>(builder.Offset);
}
};
......
......@@ -324,7 +324,7 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
TEST_EQ(hp_int64, 80);
auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
TEST_EQ(hp_double, 80.0);
auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, schema);
auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
TEST_EQ_STR(hp_string.c_str(), "80");
// We can also modify it.
......@@ -370,8 +370,44 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
// rinventory still valid, so lets read from it.
TEST_EQ(rinventory->Get(10), 50);
// Using reflection, we can also copy tables and other things out of
// other FlatBuffers into a new one, either part or whole.
// For reflection uses not covered already, there is a more powerful way:
// we can simply generate whatever object we want to add/modify in a
// FlatBuffer of its own, then add that to an existing FlatBuffer:
// As an example, let's add a string to an array of strings.
// First, find our field:
auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
// Find the vector value:
auto rtestarrayofstring = flatbuffers::piv(
flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
**rroot, testarrayofstring_field),
resizingbuf);
// It's a vector of 2 strings, to which we add one more, initialized to
// offset 0.
flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
schema, 3, 0, *rtestarrayofstring, &resizingbuf);
// Here we just create a buffer that contans a single string, but this
// could also be any complex set of tables and other values.
flatbuffers::FlatBufferBuilder stringfbb;
stringfbb.Finish(stringfbb.CreateString("hank"));
// Add the contents of it to our existing FlatBuffer.
// We do this last, so the pointer doesn't get invalidated (since it is
// at the end of the buffer):
auto string_ptr = flatbuffers::AddFlatBuffer(resizingbuf,
stringfbb.GetBufferPointer(),
stringfbb.GetSize());
// Finally, set the new value in the vector.
rtestarrayofstring->MutateOffset(2, string_ptr);
TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
// As an additional test, also set it on the name field.
// Note: unlike the name change above, this just overwrites the offset,
// rather than changing the string in-place.
SetFieldT(*rroot, name_field, string_ptr);
TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
// Using reflection, rather than mutating binary FlatBuffers, we can also copy
// tables and other things out of other FlatBuffers into a FlatBufferBuilder,
// either part or whole.
flatbuffers::FlatBufferBuilder fbb;
auto root_offset = flatbuffers::CopyTable(fbb, schema, *root_table,
*flatbuffers::GetAnyRoot(flatbuf));
......
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