mirror of
https://github.com/TextureGroup/Texture.git
synced 2026-04-07 19:17:39 +00:00
WIP Thin embedding
This commit is contained in:
@@ -331,6 +331,12 @@
|
||||
CC0F886C1E4286FA00576FED /* ReferenceImages_64 in Resources */ = {isa = PBXBuildFile; fileRef = CC0F88691E4286FA00576FED /* ReferenceImages_64 */; };
|
||||
CC0F886D1E4286FA00576FED /* ReferenceImages_iOS_10 in Resources */ = {isa = PBXBuildFile; fileRef = CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */; };
|
||||
CC11F97A1DB181180024D77B /* ASNetworkImageNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC11F9791DB181180024D77B /* ASNetworkImageNodeTests.m */; };
|
||||
CC1217762155CDBD00739E68 /* ASCollectionViewObserverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC1217752155CDBD00739E68 /* ASCollectionViewObserverTests.m */; };
|
||||
CC1217772155CDBD00739E68 /* ASCollectionViewObserverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC1217752155CDBD00739E68 /* ASCollectionViewObserverTests.m */; };
|
||||
CC12177B2155CDEC00739E68 /* ASCollectionViewObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = CC1217792155CDEC00739E68 /* ASCollectionViewObserver.h */; };
|
||||
CC12177C2155CDEC00739E68 /* ASCollectionViewObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = CC12177A2155CDEC00739E68 /* ASCollectionViewObserver.m */; };
|
||||
CC12177F2155CE4C00739E68 /* ASBoundedQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = CC12177D2155CE4C00739E68 /* ASBoundedQueue.h */; };
|
||||
CC1217802155CE4C00739E68 /* ASBoundedQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC12177E2155CE4C00739E68 /* ASBoundedQueue.mm */; };
|
||||
CC18248C200D49C800875940 /* ASTextNodeCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = CC18248B200D49C800875940 /* ASTextNodeCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CC224E962066CA6D00BBA57F /* configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = CC224E952066CA6D00BBA57F /* configuration.json */; };
|
||||
CC2F65EE1E5FFB1600DA57C9 /* ASMutableElementMap.h in Headers */ = {isa = PBXBuildFile; fileRef = CC2F65EC1E5FFB1600DA57C9 /* ASMutableElementMap.h */; };
|
||||
@@ -841,6 +847,11 @@
|
||||
CC0F88691E4286FA00576FED /* ReferenceImages_64 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ReferenceImages_64; sourceTree = "<group>"; };
|
||||
CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ReferenceImages_iOS_10; sourceTree = "<group>"; };
|
||||
CC11F9791DB181180024D77B /* ASNetworkImageNodeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASNetworkImageNodeTests.m; sourceTree = "<group>"; };
|
||||
CC1217752155CDBD00739E68 /* ASCollectionViewObserverTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewObserverTests.m; sourceTree = "<group>"; };
|
||||
CC1217792155CDEC00739E68 /* ASCollectionViewObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewObserver.h; sourceTree = "<group>"; };
|
||||
CC12177A2155CDEC00739E68 /* ASCollectionViewObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewObserver.m; sourceTree = "<group>"; };
|
||||
CC12177D2155CE4C00739E68 /* ASBoundedQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASBoundedQueue.h; sourceTree = "<group>"; };
|
||||
CC12177E2155CE4C00739E68 /* ASBoundedQueue.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASBoundedQueue.mm; sourceTree = "<group>"; };
|
||||
CC18248B200D49C800875940 /* ASTextNodeCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASTextNodeCommon.h; sourceTree = "<group>"; };
|
||||
CC224E952066CA6D00BBA57F /* configuration.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = configuration.json; sourceTree = "<group>"; };
|
||||
CC2E317F1DAC353700EEE891 /* ASCollectionView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASCollectionView+Undeprecated.h"; sourceTree = "<group>"; };
|
||||
@@ -1326,6 +1337,7 @@
|
||||
CCA221D21D6FA7EF00AF6A0F /* ASViewControllerTests.m */,
|
||||
83A7D95D1D446A6E00BF333E /* ASWeakMapTests.m */,
|
||||
CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.m */,
|
||||
CC1217782155CDCC00739E68 /* Thin Embedding */,
|
||||
695BE2541DC1245C008E6EA5 /* ASWrapperSpecSnapshotTests.mm */,
|
||||
057D02C01AC0A66700C7AC3C /* AsyncDisplayKitTestHost */,
|
||||
CC583ABF1EF9BAB400134156 /* Common */,
|
||||
@@ -1349,6 +1361,8 @@
|
||||
058D09E1195D050800B7D73C /* Details */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC1217792155CDEC00739E68 /* ASCollectionViewObserver.h */,
|
||||
CC12177A2155CDEC00739E68 /* ASCollectionViewObserver.m */,
|
||||
E5B077EB1E6843AF00C24B5B /* Collection Layout */,
|
||||
25B171EA1C12242700508A7A /* Data Controller */,
|
||||
058D09F7195D050800B7D73C /* Transactions */,
|
||||
@@ -1369,6 +1383,8 @@
|
||||
299DA1A71A828D2900162D41 /* ASBatchContext.h */,
|
||||
299DA1A81A828D2900162D41 /* ASBatchContext.m */,
|
||||
E5C347B01ECB3D9200EC4BE4 /* ASBatchFetchingDelegate.h */,
|
||||
CC12177D2155CE4C00739E68 /* ASBoundedQueue.h */,
|
||||
CC12177E2155CE4C00739E68 /* ASBoundedQueue.mm */,
|
||||
205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */,
|
||||
205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.m */,
|
||||
68C215561DE10D330019C4BC /* ASCollectionViewLayoutInspector.h */,
|
||||
@@ -1665,6 +1681,14 @@
|
||||
path = Layout;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC1217782155CDCC00739E68 /* Thin Embedding */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC1217752155CDBD00739E68 /* ASCollectionViewObserverTests.m */,
|
||||
);
|
||||
path = "Thin Embedding";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC224E942066CA6D00BBA57F /* Schemas */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1841,6 +1865,7 @@
|
||||
E5E2D72E1EA780C4005C24C6 /* ASCollectionGalleryLayoutDelegate.h in Headers */,
|
||||
E58E9E461E941D74004CFC59 /* ASCollectionLayoutDelegate.h in Headers */,
|
||||
CCBDDD0520C62A2D00CBA922 /* ASMainThreadDeallocation.h in Headers */,
|
||||
CC12177B2155CDEC00739E68 /* ASCollectionViewObserver.h in Headers */,
|
||||
CCAA0B7F206ADBF30057B336 /* ASRecursiveUnfairLock.h in Headers */,
|
||||
E5E281741E71C833006B67C2 /* ASCollectionLayoutState.h in Headers */,
|
||||
E5B077FF1E69F4EB00C24B5B /* ASElementMap.h in Headers */,
|
||||
@@ -1948,6 +1973,7 @@
|
||||
254C6B7C1BF94DF4003EC431 /* ASTextKitRenderer+TextChecking.h in Headers */,
|
||||
68AF37DB1CBEF4D80077BF76 /* ASImageNode+AnimatedImagePrivate.h in Headers */,
|
||||
CCCCCCDD1EC3EF060087FE10 /* ASTextAttribute.h in Headers */,
|
||||
CC12177F2155CE4C00739E68 /* ASBoundedQueue.h in Headers */,
|
||||
B35062461B010EFD0018CF92 /* ASBasicImageDownloaderInternal.h in Headers */,
|
||||
044285081BAA63FE00D16268 /* ASBatchFetching.h in Headers */,
|
||||
AC026B701BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */,
|
||||
@@ -2090,8 +2116,6 @@
|
||||
058D09B8195D04C000B7D73C /* Sources */,
|
||||
058D09B9195D04C000B7D73C /* Frameworks */,
|
||||
058D09BA195D04C000B7D73C /* Resources */,
|
||||
3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */,
|
||||
B130AB1AC0A1E5162E211C19 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -2211,36 +2235,6 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B9D88CDF51B429C8409E4B6 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B130AB1AC0A1E5162E211C19 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -2249,6 +2243,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
057D02C71AC0A66700C7AC3C /* AppDelegate.m in Sources */,
|
||||
CC1217772155CDBD00739E68 /* ASCollectionViewObserverTests.m in Sources */,
|
||||
057D02C41AC0A66700C7AC3C /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -2329,6 +2324,7 @@
|
||||
CCE4F9BE1F0ECE5200062E4E /* ASTLayoutFixture.mm in Sources */,
|
||||
058D0A40195D057000B7D73C /* ASTextNodeTests.m in Sources */,
|
||||
DBC453221C5FD97200B16017 /* ASDisplayNodeImplicitHierarchyTests.m in Sources */,
|
||||
CC1217762155CDBD00739E68 /* ASCollectionViewObserverTests.m in Sources */,
|
||||
058D0A41195D057000B7D73C /* ASTextNodeWordKernerTests.mm in Sources */,
|
||||
DBC452DE1C5C6A6A00B16017 /* ArrayDiffingTests.m in Sources */,
|
||||
CC11F97A1DB181180024D77B /* ASNetworkImageNodeTests.m in Sources */,
|
||||
@@ -2354,6 +2350,7 @@
|
||||
636EA1A51C7FF4EF00EE152F /* ASDefaultPlayButton.m in Sources */,
|
||||
B350623D1B010EFD0018CF92 /* _ASAsyncTransaction.mm in Sources */,
|
||||
6947B0C51E36B5040007C478 /* ASStackPositionedLayout.mm in Sources */,
|
||||
CC12177C2155CDEC00739E68 /* ASCollectionViewObserver.m in Sources */,
|
||||
B35062401B010EFD0018CF92 /* _ASAsyncTransactionContainer.m in Sources */,
|
||||
AC026B721BD57DBF00BBC17E /* _ASHierarchyChangeSet.mm in Sources */,
|
||||
B35062421B010EFD0018CF92 /* _ASAsyncTransactionGroup.m in Sources */,
|
||||
@@ -2467,6 +2464,7 @@
|
||||
254C6B8B1BF94F8A003EC431 /* ASTextKitShadower.mm in Sources */,
|
||||
254C6B851BF94F8A003EC431 /* ASTextKitAttributes.mm in Sources */,
|
||||
90FC784F1E4BFE1B00383C5A /* ASDisplayNode+Yoga.mm in Sources */,
|
||||
CC1217802155CE4C00739E68 /* ASBoundedQueue.mm in Sources */,
|
||||
CCA282C91E9EB64B0037E8B7 /* ASDisplayNodeTipState.m in Sources */,
|
||||
509E68601B3AED8E009B9150 /* ASScrollDirection.m in Sources */,
|
||||
B35062091B010EFD0018CF92 /* ASScrollNode.mm in Sources */,
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// ASCollectionViewHelper.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/7/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ASCollectionViewHelper;
|
||||
|
||||
@protocol ASCollectionViewHelperDataSource <NSObject>
|
||||
|
||||
/// always called on main.
|
||||
- (nullable id)collectionViewHelper:(ASCollectionViewHelper *)helper
|
||||
objectForItemAtIndexPath:(NSIndexPath *)path;
|
||||
|
||||
- (nullable id)collectionViewHelper:(ASCollectionViewHelper *)helper
|
||||
objectForSupplementaryElementOfKind:(NSString *)elementKind
|
||||
atIndexPath:(NSIndexPath *)indexPath;
|
||||
@end
|
||||
|
||||
|
||||
@interface ASCollectionViewHelper : NSObject
|
||||
|
||||
/**
|
||||
* Note: Data source is expected to deallocate on the main thread.
|
||||
* The collection view's layout must conform to ASCompatibleCollectionViewLayout.
|
||||
*/
|
||||
- (instancetype)initWithCollectionView:(UICollectionView *)collectionView
|
||||
dataSource:(id<ASCollectionViewHelperDataSource>)dataSource NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (instancetype)initWithTableView:(UITableView *)tableView
|
||||
dataSource:(id<ASCollectionViewHelperDataSource>)dataSource NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
#pragma mark - Output
|
||||
|
||||
#pragma mark - Table View
|
||||
|
||||
- (CGFloat)heightForRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
- (CGFloat)heightForHeaderInSection:(NSInteger)section;
|
||||
- (CGFloat)heightForFooterInSection:(NSInteger)section;
|
||||
|
||||
/// our implementation of the data source method.
|
||||
/// returns nil if this cell is not a node.
|
||||
- (nullable UITableViewCell *)tableView:(UITableView *)tableView
|
||||
cellForRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
|
||||
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
|
||||
|
||||
#pragma mark - Collection View
|
||||
|
||||
/**
|
||||
* Requests the size for the given item.
|
||||
* NOTE: You should not call this method except from -collectionView:layout:sizeForItemAtIndexPath:
|
||||
* or some other point driven by the UICollectionViewLayout.
|
||||
*
|
||||
* Calls to this method outside of UICollectionViewLayout's preparation process result in undefined behavior.
|
||||
*/
|
||||
- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (CGSize)flowLayoutReferenceSizeForHeaderInSection:(NSInteger)section;
|
||||
- (CGSize)flowLayoutReferenceSizeForFooterInSection:(NSInteger)section;
|
||||
|
||||
/// Generic supplementary sizing method.
|
||||
- (CGSize)sizeForSupplementaryElementOfKind:(NSString *)elementKind
|
||||
atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/// our implementation of the data source method.
|
||||
/// returns nil if this cell is not a node.
|
||||
- (nullable UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (nullable UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
|
||||
viewForSupplementaryElementOfKind:(NSString *)kind
|
||||
atIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
#pragma mark - Unavailable
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,240 @@
|
||||
#import "ASCollectionViewHelper.h"
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import <os/log.h>
|
||||
#import <future>
|
||||
#import <unordered_map>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "BoundedQueue.h"
|
||||
|
||||
static os_log_t ASCollectionLog2(void) {
|
||||
static os_log_t _val;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_val = os_log_create("org.TextureGroup.collectionTwo", "");
|
||||
});
|
||||
return _val;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
__unsafe_unretained NSString * _Nullable supplementaryElementKind;
|
||||
NSInteger section;
|
||||
NSInteger item;
|
||||
} ASCollectionElementPath;
|
||||
|
||||
using namespace std;
|
||||
|
||||
@interface ASCollectionViewHelper ()
|
||||
@end
|
||||
|
||||
@implementation ASCollectionViewHelper {
|
||||
__weak id<ASCollectionViewHelperDataSource> _dataSource;
|
||||
NSMutableSet<NSString *> *_registeredViewClassesForSupplementaryKinds;
|
||||
|
||||
// id<ASNodeKey> -> { future<ASDisplayNode>, dispatch_block_t }
|
||||
unordered_map<CFTypeRef, pair<shared_future<CFTypeRef>, dispatch_block_t>> _layouts;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCollectionView:(UICollectionView *)collectionView dataSource:(id<ASCollectionViewHelperDataSource>)dataSource
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_dataSource = dataSource;
|
||||
|
||||
[collectionView registerClass:UICollectionViewCell.class
|
||||
forCellWithReuseIdentifier:@"asdkCellId"];
|
||||
_registeredViewClassesForSupplementaryKinds = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTableView:(UITableView *)tableView dataSource:(id<ASCollectionViewHelperDataSource>)dataSource
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_dataSource = dataSource;
|
||||
|
||||
[tableView registerClass:UITableViewCell.class forCellReuseIdentifier:@"asdkCellId"];
|
||||
_registeredViewClassesForSupplementaryKinds = [[NSMutableSet alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Data providing
|
||||
|
||||
- (CGFloat)heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return [self sizeForItemAtIndexPath:indexPath].height;
|
||||
}
|
||||
|
||||
- (CGFloat)heightForHeaderInSection:(NSInteger)section {
|
||||
return [self sizeForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]].height;
|
||||
}
|
||||
|
||||
- (CGFloat)heightForFooterInSection:(NSInteger)section {
|
||||
return [self sizeForSupplementaryElementOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]].height;
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
|
||||
cellForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
os_log_debug(ASCollectionLog2(), "request cell for node %lu", (unsigned long)indexPath.item);
|
||||
|
||||
auto cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"asdkCellId" forIndexPath:indexPath];
|
||||
[self host:{ nil, indexPath.section, indexPath.item } inContentView:cell.contentView];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
if (![_registeredViewClassesForSupplementaryKinds containsObject:kind]) {
|
||||
[collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:kind withReuseIdentifier:@"asdkSuppId"];
|
||||
[_registeredViewClassesForSupplementaryKinds addObject:kind];
|
||||
}
|
||||
UICollectionReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"asdkSuppId" forIndexPath:indexPath];
|
||||
[self host:{ kind, indexPath.section, indexPath.item } inContentView:view];
|
||||
return view;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)host:(ASCollectionElementPath)element inContentView:(UIView *)contentView
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
// Get the node, or bail if this is cell is not a node.
|
||||
auto node = [self _measuredNodeFor:element];
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
unowned let oldCellView = contentView.subviews.firstObject;
|
||||
unowned let nodeView = node.view;
|
||||
if (oldCellView != nodeView) {
|
||||
[oldCellView removeFromSuperview];
|
||||
[contentView addSubview:nodeView];
|
||||
nodeView.frame = contentView.bounds;
|
||||
nodeView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_startPreparingNodeFor:(ASCollectionElementPath)path knownSizeRange:(ASSizeRange)sizeRange
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
id object;
|
||||
if (path.supplementaryElementKind == nil) {
|
||||
object = [_dataSource collectionViewHelper:self objectForItemAtIndexPath:[NSIndexPath indexPathForItem:path.item inSection:path.section]];
|
||||
} else {
|
||||
object = [_dataSource collectionViewHelper:self objectForSupplementaryElementOfKind:path.supplementaryElementKind atIndexPath:[NSIndexPath indexPathForItem:path.item inSection:path.section]];
|
||||
}
|
||||
if (object == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ASSizeRangeEqualToSizeRange(sizeRange, ASSizeRangeNull)) {
|
||||
sizeRange = [self _sizeRangeFromLayoutFor:path];
|
||||
}
|
||||
|
||||
auto promise = new std::promise<CFTypeRef>();
|
||||
auto future = promise->get_future().share();
|
||||
__block dispatch_block_t dispatchBlock = dispatch_block_create((dispatch_block_flags_t)0, ^{
|
||||
if (dispatch_block_testcancel(dispatchBlock)) {
|
||||
delete promise;
|
||||
return;
|
||||
}
|
||||
|
||||
// We retain the key. The key retains the node.
|
||||
// If the data source also retains the key, then the node survives across updates.
|
||||
// If it doesn't, then we have to regenerate the node.
|
||||
static int nodeAssociationKey;
|
||||
|
||||
ASDisplayNode *node;
|
||||
@synchronized(object) {
|
||||
node = objc_getAssociatedObject(object, &nodeAssociationKey);
|
||||
if (node) {
|
||||
os_log_debug(ASCollectionLog2(), "reused node at %lu", (unsigned long)path.item);
|
||||
} else {
|
||||
os_log_debug(ASCollectionLog2(), "creating node at %lu", (unsigned long)path.item);
|
||||
node = [object createNode];
|
||||
if ((id)node != (id)object) {
|
||||
objc_setAssociatedObject(object, &nodeAssociationKey, node, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
} else {
|
||||
objc_setAssociatedObject(object, &nodeAssociationKey, node, OBJC_ASSOCIATION_ASSIGN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check canceled.
|
||||
if (dispatch_block_testcancel(dispatchBlock)) {
|
||||
os_log_debug(ASCollectionLog2(), "measure canceled", (unsigned long)path.item);
|
||||
delete promise;
|
||||
return;
|
||||
}
|
||||
|
||||
// Just compute the size and rely on the node's cache.
|
||||
[node layoutThatFits:sizeRange];
|
||||
os_log_debug(ASCollectionLog2(), "measured node at %lu", (unsigned long)path.item);
|
||||
|
||||
promise->set_value((__bridge CFTypeRef)node);
|
||||
delete promise;
|
||||
});
|
||||
[BoundedQueueGetDefault() dispatch:dispatchBlock];
|
||||
_layouts.insert({ (__bridge_retained CFTypeRef)key, { future, dispatchBlock }});
|
||||
}
|
||||
|
||||
/**
|
||||
* For sizing calls, the normal pattern (flow layout) is to size all cells upfront.
|
||||
*
|
||||
* We want to size them all upfront and avoid re-validating our data on each sizing call.
|
||||
* To do this, we need some cooperation from the layout object unfortunately. We need to know
|
||||
* that the data source is still valid.
|
||||
*/
|
||||
- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
os_log_debug(ASCollectionLog2(), "request size for node %lu", (unsigned long)indexPath.item);
|
||||
return [self _measuredNodeFor:{ nil, indexPath.section, indexPath.item }].calculatedSize;
|
||||
}
|
||||
|
||||
- (CGSize)flowLayoutReferenceSizeForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return [self sizeForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
|
||||
}
|
||||
|
||||
- (CGSize)flowLayoutReferenceSizeForFooterInSection:(NSInteger)section
|
||||
{
|
||||
return [self sizeForSupplementaryElementOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
|
||||
}
|
||||
|
||||
- (CGSize)sizeForSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
os_log_debug(ASCollectionLog2(), "request size for supp node %@ %lu", elementKind, (unsigned long)indexPath.section);
|
||||
return [self _measuredNodeFor:{ elementKind, indexPath.section, indexPath.item }].calculatedSize;
|
||||
}
|
||||
|
||||
- (ASDisplayNode *)_measuredNodeFor:(ASCollectionElementPath)path
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
id key = [_dataSource collectionViewHelper:self nodeKeyForCollectionPath:path];
|
||||
if (key == nil) {
|
||||
ASDisplayNodeFailAssert(@"Asked for size of item that isn't a node!");
|
||||
return nil;
|
||||
}
|
||||
auto it = _layouts.find((__bridge CFTypeRef)key);
|
||||
|
||||
// We didn't pre-warm this. Known causes of this are:
|
||||
// - Changes in the return value from nodeKeyForCollectionPath: for the same path without
|
||||
// invalidating the layout.
|
||||
// - Not including a supplementary element in -supplementaryElementsInSection:
|
||||
if (it == _layouts.end()) {
|
||||
os_log_debug(ASCollectionLog2(), "Warning: failed to warm layout for %lu", (unsigned long)path.item);
|
||||
[self _startPreparingNodeFor:path knownSizeRange:ASSizeRangeNull];
|
||||
it = _layouts.find((__bridge CFTypeRef)key);
|
||||
}
|
||||
|
||||
// Blocking: Wait on the layout promise.
|
||||
return (__bridge ASDisplayNode *)it->second.first.get();
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#import <AsyncDisplayKit/ASAvailability.h>
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASCollectionViewHelper.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Ancestry.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Convenience.h>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// BoundedQueue.h
|
||||
// FudgeFlowLayout
|
||||
//
|
||||
// Created by Adlai Holler on 8/8/18.
|
||||
// Copyright © 2018 Adlai Holler. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface BoundedQueue : NSObject
|
||||
|
||||
- (void)dispatch:(void(^)(void))block;
|
||||
|
||||
- (void)waitUntilReady;
|
||||
|
||||
@end
|
||||
|
||||
static BoundedQueue *_gDefaultBoundedQueue;
|
||||
|
||||
NS_INLINE void _EnsureDefaultBoundedQueue(void) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_gDefaultBoundedQueue = [[BoundedQueue alloc] init];
|
||||
});
|
||||
}
|
||||
|
||||
#define BoundedQueueGetDefault() ({ _EnsureDefaultBoundedQueue(); _gDefaultBoundedQueue; })
|
||||
|
||||
@interface BoundedQueue (LayoutQueue)
|
||||
/// The queue to which cell layouts are submitted by default.
|
||||
@property(class, readonly) BoundedQueue *layoutQueue;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// BoundedQueue.m
|
||||
// FudgeFlowLayout
|
||||
//
|
||||
// Created by Adlai Holler on 8/8/18.
|
||||
// Copyright © 2018 Adlai Holler. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BoundedQueue.h"
|
||||
|
||||
#import <atomic>
|
||||
#import <mutex>
|
||||
#import <queue>
|
||||
|
||||
@implementation BoundedQueue {
|
||||
std::mutex _lock;
|
||||
std::queue<void(^)(void)> _blocks;
|
||||
std::condition_variable _ready;
|
||||
int _threadLimit;
|
||||
int _threadCount;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_threadLimit = (int)NSProcessInfo.processInfo.processorCount * 2;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dispatch:(void(^)(void))block
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_lock);
|
||||
_blocks.push(block);
|
||||
// Spawn new thread if needed.
|
||||
if (_threadCount < _threadLimit) {
|
||||
__unsafe_unretained __typeof(self) uSelf = self;
|
||||
// NOTE: Using a concurrent queue does not reliably get us the concurrency we want.
|
||||
dispatch_queue_t q = dispatch_queue_create("BoundedQueue", NULL);
|
||||
dispatch_async(q, ^{
|
||||
[uSelf _threadBody];
|
||||
});
|
||||
_threadCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_threadBody
|
||||
{
|
||||
while (true) {
|
||||
void (^block)() = nil;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_lock);
|
||||
if (_blocks.empty()) {
|
||||
break;
|
||||
}
|
||||
block = _blocks.front();
|
||||
_blocks.pop();
|
||||
}
|
||||
block();
|
||||
}
|
||||
|
||||
// Before exit, decrement thread count and notify any waiters.
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_lock);
|
||||
_threadCount -= 1;
|
||||
}
|
||||
_ready.notify_all();
|
||||
}
|
||||
|
||||
- (void)waitUntilReady
|
||||
{
|
||||
std::unique_lock<std::mutex> l(_lock);
|
||||
while (!(_threadCount < _threadLimit)) {
|
||||
_ready.wait(l);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation BoundedQueue (LayoutQueue)
|
||||
|
||||
+ (BoundedQueue *)layoutQueue
|
||||
{
|
||||
static BoundedQueue *q;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
q = [[BoundedQueue alloc] init];
|
||||
});
|
||||
return q;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// BoundedQueue.h
|
||||
// FudgeFlowLayout
|
||||
//
|
||||
// Created by Adlai Holler on 8/8/18.
|
||||
// Copyright © 2018 Adlai Holler. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface BoundedQueue : NSObject
|
||||
|
||||
- (void)dispatch:(void(^)(void))block;
|
||||
|
||||
- (void)waitUntilReady;
|
||||
|
||||
@end
|
||||
|
||||
static BoundedQueue *_gDefaultBoundedQueue;
|
||||
|
||||
NS_INLINE void _EnsureDefaultBoundedQueue(void) {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_gDefaultBoundedQueue = [[BoundedQueue alloc] init];
|
||||
});
|
||||
}
|
||||
|
||||
#define BoundedQueueGetDefault() ({ _EnsureDefaultBoundedQueue(); _gDefaultBoundedQueue; })
|
||||
|
||||
@interface BoundedQueue (LayoutQueue)
|
||||
/// The queue to which cell layouts are submitted by default.
|
||||
@property(class, readonly) BoundedQueue *layoutQueue;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// BoundedQueue.m
|
||||
// FudgeFlowLayout
|
||||
//
|
||||
// Created by Adlai Holler on 8/8/18.
|
||||
// Copyright © 2018 Adlai Holler. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/ASBoundedQueue.h>
|
||||
|
||||
#import <atomic>
|
||||
#import <mutex>
|
||||
#import <queue>
|
||||
|
||||
@implementation BoundedQueue {
|
||||
std::mutex _lock;
|
||||
std::queue<void(^)(void)> _blocks;
|
||||
std::condition_variable _ready;
|
||||
int _threadLimit;
|
||||
int _threadCount;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_threadLimit = (int)NSProcessInfo.processInfo.processorCount * 2;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dispatch:(void(^)(void))block
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_lock);
|
||||
_blocks.push(block);
|
||||
// Spawn new thread if needed.
|
||||
if (_threadCount < _threadLimit) {
|
||||
__unsafe_unretained __typeof(self) uSelf = self;
|
||||
// NOTE: Using a concurrent queue does not reliably get us the concurrency we want.
|
||||
dispatch_queue_t q = dispatch_queue_create("BoundedQueue", NULL);
|
||||
dispatch_async(q, ^{
|
||||
[uSelf _threadBody];
|
||||
});
|
||||
_threadCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_threadBody
|
||||
{
|
||||
while (true) {
|
||||
void (^block)() = nil;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_lock);
|
||||
if (_blocks.empty()) {
|
||||
break;
|
||||
}
|
||||
block = _blocks.front();
|
||||
_blocks.pop();
|
||||
}
|
||||
block();
|
||||
}
|
||||
|
||||
// Before exit, decrement thread count and notify any waiters.
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_lock);
|
||||
_threadCount -= 1;
|
||||
}
|
||||
_ready.notify_all();
|
||||
}
|
||||
|
||||
- (void)waitUntilReady
|
||||
{
|
||||
std::unique_lock<std::mutex> l(_lock);
|
||||
while (!(_threadCount < _threadLimit)) {
|
||||
_ready.wait(l);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation BoundedQueue (LayoutQueue)
|
||||
|
||||
+ (BoundedQueue *)layoutQueue
|
||||
{
|
||||
static BoundedQueue *q;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
q = [[BoundedQueue alloc] init];
|
||||
});
|
||||
return q;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// ASCollectionViewObserver.h
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Pinterest. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ASCollectionViewObserver : NSObject
|
||||
|
||||
- (void)collectionViewWillPrepareLayout:(UICollectionViewLayout *)layout;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ASCollectionViewObserver.m
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Pinterest. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASCollectionViewObserver.h"
|
||||
|
||||
@implementation ASCollectionViewObserver
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ASCollectionViewObserverTests.m
|
||||
// AsyncDisplayKit
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Pinterest. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASCollectionViewObserverTests.h"
|
||||
|
||||
@implementation ASCollectionViewObserverTests
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,5 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '9.0'
|
||||
target 'Sample' do
|
||||
pod 'Texture', :path => '../..'
|
||||
end
|
||||
@@ -0,0 +1,55 @@
|
||||
PODS:
|
||||
- PINCache (3.0.1-beta.6):
|
||||
- PINCache/Arc-exception-safe (= 3.0.1-beta.6)
|
||||
- PINCache/Core (= 3.0.1-beta.6)
|
||||
- PINCache/Arc-exception-safe (3.0.1-beta.6):
|
||||
- PINCache/Core
|
||||
- PINCache/Core (3.0.1-beta.6):
|
||||
- PINOperation (~> 1.1.0)
|
||||
- PINOperation (1.1.1)
|
||||
- PINRemoteImage/Core (3.0.0-beta.13):
|
||||
- PINOperation
|
||||
- PINRemoteImage/iOS (3.0.0-beta.13):
|
||||
- PINRemoteImage/Core
|
||||
- PINRemoteImage/PINCache (3.0.0-beta.13):
|
||||
- PINCache (= 3.0.1-beta.6)
|
||||
- PINRemoteImage/Core
|
||||
- Texture (2.7):
|
||||
- Texture/AssetsLibrary (= 2.7)
|
||||
- Texture/MapKit (= 2.7)
|
||||
- Texture/Photos (= 2.7)
|
||||
- Texture/PINRemoteImage (= 2.7)
|
||||
- Texture/AssetsLibrary (2.7):
|
||||
- Texture/Core
|
||||
- Texture/Core (2.7)
|
||||
- Texture/MapKit (2.7):
|
||||
- Texture/Core
|
||||
- Texture/Photos (2.7):
|
||||
- Texture/Core
|
||||
- Texture/PINRemoteImage (2.7):
|
||||
- PINRemoteImage/iOS (= 3.0.0-beta.13)
|
||||
- PINRemoteImage/PINCache
|
||||
- Texture/Core
|
||||
|
||||
DEPENDENCIES:
|
||||
- Texture (from `../..`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- PINCache
|
||||
- PINOperation
|
||||
- PINRemoteImage
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Texture:
|
||||
:path: "../.."
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
PINCache: d195fdba255283f7e9900a55e3cced377f431f9b
|
||||
PINOperation: a6219e6fc9db9c269eb7a7b871ac193bcf400aac
|
||||
PINRemoteImage: d6d51c5d2adda55f1ce30c96e850b6c4ebd2856a
|
||||
Texture: c5e57fa8a7f5c464bdc4477bf54a3994b76e4afc
|
||||
|
||||
PODFILE CHECKSUM: 1854e46d17e3e0c67905b359e6bfbb0a0a4983c9
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
@@ -0,0 +1,474 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
91C402838901BD02685337A8 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F1E539014E1F516F00A8F167 /* libPods-Sample.a */; };
|
||||
AC3C4A641A11F47200143C57 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A631A11F47200143C57 /* main.m */; };
|
||||
AC3C4A671A11F47200143C57 /* TEAppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A661A11F47200143C57 /* TEAppDelegate.mm */; };
|
||||
AC3C4A8E1A11F80C00143C57 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AC3C4A8D1A11F80C00143C57 /* Images.xcassets */; };
|
||||
CC0AA16D21582C1E00622B21 /* PacMan.json in Resources */ = {isa = PBXBuildFile; fileRef = CC0AA16C21582C1E00622B21 /* PacMan.json */; };
|
||||
CC0AA17021582D9700622B21 /* ui_collection.fbs in Resources */ = {isa = PBXBuildFile; fileRef = CC0AA16F21582D9700622B21 /* ui_collection.fbs */; };
|
||||
CC0AA1762158346900622B21 /* PacMan.bin in Resources */ = {isa = PBXBuildFile; fileRef = CC0AA1752158346900622B21 /* PacMan.bin */; };
|
||||
CC1217872155D14700739E68 /* UIViewController+TEActions.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC1217862155D14700739E68 /* UIViewController+TEActions.mm */; };
|
||||
CC12178D2155D40E00739E68 /* TEBaseViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC12178C2155D40E00739E68 /* TEBaseViewController.mm */; };
|
||||
CC1217902155D41C00739E68 /* TECollectionViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC12178F2155D41C00739E68 /* TECollectionViewController.mm */; };
|
||||
CC1217932155D42200739E68 /* TETableViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC1217922155D42200739E68 /* TETableViewController.mm */; };
|
||||
CC12179A2155D54A00739E68 /* TECellNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC1217992155D54A00739E68 /* TECellNode.mm */; };
|
||||
CC1217B02155DA5100739E68 /* TECellView.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC1217AF2155DA5100739E68 /* TECellView.mm */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
65F7AC562A910A742522053C /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
|
||||
AC3C4A5E1A11F47200143C57 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AC3C4A621A11F47200143C57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
AC3C4A631A11F47200143C57 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
AC3C4A651A11F47200143C57 /* TEAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TEAppDelegate.h; sourceTree = "<group>"; };
|
||||
AC3C4A661A11F47200143C57 /* TEAppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TEAppDelegate.mm; sourceTree = "<group>"; };
|
||||
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
CC0AA1562156AA6200622B21 /* grpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grpc.h; sourceTree = "<group>"; };
|
||||
CC0AA1572156AA6200622B21 /* idl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = idl.h; sourceTree = "<group>"; };
|
||||
CC0AA1582156AA6200622B21 /* reflection_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reflection_generated.h; sourceTree = "<group>"; };
|
||||
CC0AA1592156AA6200622B21 /* registry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = registry.h; sourceTree = "<group>"; };
|
||||
CC0AA15A2156AA6200622B21 /* flatbuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flatbuffers.h; sourceTree = "<group>"; };
|
||||
CC0AA15B2156AA6200622B21 /* flatc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flatc.h; sourceTree = "<group>"; };
|
||||
CC0AA15C2156AA6200622B21 /* flexbuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flexbuffers.h; sourceTree = "<group>"; };
|
||||
CC0AA15D2156AA6200622B21 /* minireflect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minireflect.h; sourceTree = "<group>"; };
|
||||
CC0AA15E2156AA6200622B21 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
|
||||
CC0AA15F2156AA6200622B21 /* code_generators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = code_generators.h; sourceTree = "<group>"; };
|
||||
CC0AA1602156AA6200622B21 /* stl_emulation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stl_emulation.h; sourceTree = "<group>"; };
|
||||
CC0AA1612156AA6200622B21 /* hash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hash.h; sourceTree = "<group>"; };
|
||||
CC0AA1622156AA6200622B21 /* reflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reflection.h; sourceTree = "<group>"; };
|
||||
CC0AA1632156AA6200622B21 /* base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base.h; sourceTree = "<group>"; };
|
||||
CC0AA16C21582C1E00622B21 /* PacMan.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = PacMan.json; sourceTree = "<group>"; };
|
||||
CC0AA16F21582D9700622B21 /* ui_collection.fbs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ui_collection.fbs; sourceTree = "<group>"; };
|
||||
CC0AA17121582E3500622B21 /* ui_collection_generated.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ui_collection_generated.h; sourceTree = "<group>"; };
|
||||
CC0AA1752158346900622B21 /* PacMan.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = PacMan.bin; sourceTree = "<group>"; };
|
||||
CC1217852155D14700739E68 /* UIViewController+TEActions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+TEActions.h"; sourceTree = "<group>"; };
|
||||
CC1217862155D14700739E68 /* UIViewController+TEActions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIViewController+TEActions.mm"; sourceTree = "<group>"; };
|
||||
CC12178B2155D40E00739E68 /* TEBaseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TEBaseViewController.h; sourceTree = "<group>"; };
|
||||
CC12178C2155D40E00739E68 /* TEBaseViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TEBaseViewController.mm; sourceTree = "<group>"; };
|
||||
CC12178E2155D41C00739E68 /* TECollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TECollectionViewController.h; sourceTree = "<group>"; };
|
||||
CC12178F2155D41C00739E68 /* TECollectionViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TECollectionViewController.mm; sourceTree = "<group>"; };
|
||||
CC1217912155D42200739E68 /* TETableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TETableViewController.h; sourceTree = "<group>"; };
|
||||
CC1217922155D42200739E68 /* TETableViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TETableViewController.mm; sourceTree = "<group>"; };
|
||||
CC1217982155D54A00739E68 /* TECellNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TECellNode.h; sourceTree = "<group>"; };
|
||||
CC1217992155D54A00739E68 /* TECellNode.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TECellNode.mm; sourceTree = "<group>"; };
|
||||
CC1217AE2155DA5100739E68 /* TECellView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TECellView.h; sourceTree = "<group>"; };
|
||||
CC1217AF2155DA5100739E68 /* TECellView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TECellView.mm; sourceTree = "<group>"; };
|
||||
F1E539014E1F516F00A8F167 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F3A72D578C378357FF56486A /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
AC3C4A5B1A11F47200143C57 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
91C402838901BD02685337A8 /* libPods-Sample.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
90A2B9C5397C46134C8A793B /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3A72D578C378357FF56486A /* Pods-Sample.debug.xcconfig */,
|
||||
65F7AC562A910A742522053C /* Pods-Sample.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AC3C4A551A11F47200143C57 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA1542156AA6100622B21 /* include */,
|
||||
AC3C4A601A11F47200143C57 /* Sample */,
|
||||
AC3C4A5F1A11F47200143C57 /* Products */,
|
||||
90A2B9C5397C46134C8A793B /* Pods */,
|
||||
D6E38FF0CB18E3F55CF06437 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AC3C4A5F1A11F47200143C57 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AC3C4A5E1A11F47200143C57 /* Sample.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AC3C4A601A11F47200143C57 /* Sample */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA1642156AC7400622B21 /* flatbuf_gen */,
|
||||
CC0AA1662156AC7500622B21 /* flatbuf_schemas */,
|
||||
AC3C4A651A11F47200143C57 /* TEAppDelegate.h */,
|
||||
AC3C4A661A11F47200143C57 /* TEAppDelegate.mm */,
|
||||
CC12179B2155D54E00739E68 /* Cells */,
|
||||
CC1217942155D42900739E68 /* View Controllers */,
|
||||
CC1217852155D14700739E68 /* UIViewController+TEActions.h */,
|
||||
CC1217862155D14700739E68 /* UIViewController+TEActions.mm */,
|
||||
CC0AA1772158347300622B21 /* Fixture Data (Flatbuf) */,
|
||||
CC0AA16E21582C2100622B21 /* Fixture Data (JSON) */,
|
||||
AC3C4A611A11F47200143C57 /* Supporting Files */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
path = Sample;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
usesTabs = 0;
|
||||
};
|
||||
AC3C4A611A11F47200143C57 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */,
|
||||
AC3C4A621A11F47200143C57 /* Info.plist */,
|
||||
AC3C4A631A11F47200143C57 /* main.m */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC0AA1542156AA6100622B21 /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA1552156AA6200622B21 /* flatbuffers */,
|
||||
);
|
||||
path = include;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC0AA1552156AA6200622B21 /* flatbuffers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA1562156AA6200622B21 /* grpc.h */,
|
||||
CC0AA1572156AA6200622B21 /* idl.h */,
|
||||
CC0AA1582156AA6200622B21 /* reflection_generated.h */,
|
||||
CC0AA1592156AA6200622B21 /* registry.h */,
|
||||
CC0AA15A2156AA6200622B21 /* flatbuffers.h */,
|
||||
CC0AA15B2156AA6200622B21 /* flatc.h */,
|
||||
CC0AA15C2156AA6200622B21 /* flexbuffers.h */,
|
||||
CC0AA15D2156AA6200622B21 /* minireflect.h */,
|
||||
CC0AA15E2156AA6200622B21 /* util.h */,
|
||||
CC0AA15F2156AA6200622B21 /* code_generators.h */,
|
||||
CC0AA1602156AA6200622B21 /* stl_emulation.h */,
|
||||
CC0AA1612156AA6200622B21 /* hash.h */,
|
||||
CC0AA1622156AA6200622B21 /* reflection.h */,
|
||||
CC0AA1632156AA6200622B21 /* base.h */,
|
||||
);
|
||||
path = flatbuffers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC0AA1642156AC7400622B21 /* flatbuf_gen */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA17121582E3500622B21 /* ui_collection_generated.h */,
|
||||
);
|
||||
path = flatbuf_gen;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC0AA1662156AC7500622B21 /* flatbuf_schemas */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA16F21582D9700622B21 /* ui_collection.fbs */,
|
||||
);
|
||||
path = flatbuf_schemas;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC0AA16E21582C2100622B21 /* Fixture Data (JSON) */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA16C21582C1E00622B21 /* PacMan.json */,
|
||||
);
|
||||
name = "Fixture Data (JSON)";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC0AA1772158347300622B21 /* Fixture Data (Flatbuf) */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC0AA1752158346900622B21 /* PacMan.bin */,
|
||||
);
|
||||
name = "Fixture Data (Flatbuf)";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC1217942155D42900739E68 /* View Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC12178B2155D40E00739E68 /* TEBaseViewController.h */,
|
||||
CC12178C2155D40E00739E68 /* TEBaseViewController.mm */,
|
||||
CC12178E2155D41C00739E68 /* TECollectionViewController.h */,
|
||||
CC12178F2155D41C00739E68 /* TECollectionViewController.mm */,
|
||||
CC1217912155D42200739E68 /* TETableViewController.h */,
|
||||
CC1217922155D42200739E68 /* TETableViewController.mm */,
|
||||
);
|
||||
name = "View Controllers";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CC12179B2155D54E00739E68 /* Cells */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CC1217982155D54A00739E68 /* TECellNode.h */,
|
||||
CC1217992155D54A00739E68 /* TECellNode.mm */,
|
||||
CC1217AE2155DA5100739E68 /* TECellView.h */,
|
||||
CC1217AF2155DA5100739E68 /* TECellView.mm */,
|
||||
);
|
||||
name = Cells;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6E38FF0CB18E3F55CF06437 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F1E539014E1F516F00A8F167 /* libPods-Sample.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
AC3C4A5D1A11F47200143C57 /* Sample */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = AC3C4A811A11F47200143C57 /* Build configuration list for PBXNativeTarget "Sample" */;
|
||||
buildPhases = (
|
||||
F868CFBB21824CC9521B6588 /* [CP] Check Pods Manifest.lock */,
|
||||
AC3C4A5A1A11F47200143C57 /* Sources */,
|
||||
AC3C4A5B1A11F47200143C57 /* Frameworks */,
|
||||
AC3C4A5C1A11F47200143C57 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Sample;
|
||||
productName = Sample;
|
||||
productReference = AC3C4A5E1A11F47200143C57 /* Sample.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
AC3C4A561A11F47200143C57 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
AC3C4A5D1A11F47200143C57 = {
|
||||
CreatedOnToolsVersion = 6.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = AC3C4A591A11F47200143C57 /* Build configuration list for PBXProject "Sample" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = AC3C4A551A11F47200143C57;
|
||||
productRefGroup = AC3C4A5F1A11F47200143C57 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
AC3C4A5D1A11F47200143C57 /* Sample */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
AC3C4A5C1A11F47200143C57 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CC0AA17021582D9700622B21 /* ui_collection.fbs in Resources */,
|
||||
CC0AA1762158346900622B21 /* PacMan.bin in Resources */,
|
||||
AC3C4A8E1A11F80C00143C57 /* Images.xcassets in Resources */,
|
||||
CC0AA16D21582C1E00622B21 /* PacMan.json in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
F868CFBB21824CC9521B6588 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Sample-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
AC3C4A5A1A11F47200143C57 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
AC3C4A671A11F47200143C57 /* TEAppDelegate.mm in Sources */,
|
||||
CC1217B02155DA5100739E68 /* TECellView.mm in Sources */,
|
||||
CC12179A2155D54A00739E68 /* TECellNode.mm in Sources */,
|
||||
AC3C4A641A11F47200143C57 /* main.m in Sources */,
|
||||
CC12178D2155D40E00739E68 /* TEBaseViewController.mm in Sources */,
|
||||
CC1217902155D41C00739E68 /* TECollectionViewController.mm in Sources */,
|
||||
CC1217932155D42200739E68 /* TETableViewController.mm in Sources */,
|
||||
CC1217872155D14700739E68 /* UIViewController+TEActions.mm in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
AC3C4A7F1A11F47200143C57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "\"$(SRCROOT)/include\"/**";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AC3C4A801A11F47200143C57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = "\"$(SRCROOT)/include\"/**";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
AC3C4A821A11F47200143C57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = F3A72D578C378357FF56486A /* Pods-Sample.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
INFOPLIST_FILE = Sample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-fno-objc-arc-exceptions",
|
||||
);
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TARGETED_DEVICE_FAMILY = 2;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AC3C4A831A11F47200143C57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 65F7AC562A910A742522053C /* Pods-Sample.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
INFOPLIST_FILE = Sample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_CPLUSPLUSFLAGS = (
|
||||
"$(OTHER_CFLAGS)",
|
||||
"-fno-objc-arc-exceptions",
|
||||
);
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TARGETED_DEVICE_FAMILY = 2;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
AC3C4A591A11F47200143C57 /* Build configuration list for PBXProject "Sample" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
AC3C4A7F1A11F47200143C57 /* Debug */,
|
||||
AC3C4A801A11F47200143C57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
AC3C4A811A11F47200143C57 /* Build configuration list for PBXNativeTarget "Sample" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
AC3C4A821A11F47200143C57 /* Debug */,
|
||||
AC3C4A831A11F47200143C57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = AC3C4A561A11F47200143C57 /* Project object */;
|
||||
}
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Sample.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Sample.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"images" : [
|
||||
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIcons</key>
|
||||
<dict/>
|
||||
<key>CFBundleIcons~ipad</key>
|
||||
<dict/>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>http://lorempixel.com</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"sections": [
|
||||
{
|
||||
"header": {
|
||||
"use_texture": true,
|
||||
"text": "Protagonists"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"use_texture": true,
|
||||
"text": "Pac-Man"
|
||||
},
|
||||
{
|
||||
"use_texture": true,
|
||||
"text": "Ms. Pac-Man"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"header": {
|
||||
"use_texture": true,
|
||||
"text": "Ghosts"
|
||||
},
|
||||
"footer": {
|
||||
"use_texture": false,
|
||||
"text": "No more ghosts."
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"use_texture": true,
|
||||
"text": "Blinky"
|
||||
},
|
||||
{
|
||||
"use_texture": true,
|
||||
"text": "Pinky"
|
||||
},
|
||||
{
|
||||
"use_texture": true,
|
||||
"text": "Inky"
|
||||
},
|
||||
{
|
||||
"use_texture": false,
|
||||
"text": "Clyde"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// TEAppDelegate.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface TEAppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// TEAppDelegate.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "TEAppDelegate.h"
|
||||
|
||||
#import "TECollectionViewController.h"
|
||||
#import "TETableViewController.h"
|
||||
|
||||
@implementation TEAppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
// Appearance bits.
|
||||
UINavigationBar.appearance.barStyle = UIBarStyleBlack;
|
||||
UITabBar.appearance.barStyle = UIBarStyleBlack;
|
||||
UITableView.appearance.backgroundColor = UIColor.blackColor;
|
||||
|
||||
// Root VC.
|
||||
UITabBarController *tabCtrl = [[UITabBarController alloc] init];
|
||||
UINavigationController *cNav = [[UINavigationController alloc] initWithRootViewController:[TECollectionViewController new]];
|
||||
cNav.tabBarItem.title = @"Collection";
|
||||
UINavigationController *tNav = [[UINavigationController alloc] initWithRootViewController:[TETableViewController new]];
|
||||
tNav.tabBarItem.title = @"Table";
|
||||
tabCtrl.viewControllers = @[ cNav, tNav ];
|
||||
|
||||
// Window.
|
||||
_window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
|
||||
_window.tintColor = UIColor.orangeColor;
|
||||
_window.rootViewController = tabCtrl;
|
||||
[_window makeKeyAndVisible];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// TEBaseViewController.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "ui_collection_generated.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
static NSString *const TEViewPlatformPlain = @"plain";
|
||||
static NSString *const TEViewPlatformTexture = @"texture";
|
||||
|
||||
struct TEPath {
|
||||
int section; // NSNotFound means "global."
|
||||
int item; // NSNotFound means "section-level."
|
||||
__unsafe_unretained NSString * _Nullable supplementaryElementKind; // Nil means item.
|
||||
static TEPath make(NSIndexPath *indexPath, NSString *supplementaryElementKindArg = nil) {
|
||||
return { (int)indexPath.section, (int)indexPath.item, supplementaryElementKindArg };
|
||||
}
|
||||
static TEPath header(NSInteger sectionArg) {
|
||||
return { (int)sectionArg, 0, UICollectionElementKindSectionHeader };
|
||||
}
|
||||
static TEPath footer(NSInteger sectionArg) {
|
||||
return { (int)sectionArg, 0, UICollectionElementKindSectionFooter };
|
||||
}
|
||||
};
|
||||
|
||||
@class TECellView, TEModel, TESectionController;
|
||||
|
||||
@interface TEBaseViewController : UIViewController
|
||||
|
||||
/// Tell the view to reload data. Doesn't affect data source data.
|
||||
- (void)reloadData;
|
||||
|
||||
/// Don't call on base class.
|
||||
- (void)perform:(void(NS_NOESCAPE ^)(void))updates;
|
||||
|
||||
@end
|
||||
|
||||
@interface TEBaseViewController (UISubclassingHooks)
|
||||
|
||||
// Things subclasses call:
|
||||
- (NSInteger)numberOfSections;
|
||||
- (NSInteger)numberOfItemsIn:(NSInteger)section;
|
||||
- (CGSize)sizeAt:(const TEPath &)path;
|
||||
- (NSString *)reuseIdentifierAt:(const TEPath &)path;
|
||||
- (void)hostItemAt:(const TEPath &)path in:(UIView *)contentView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// TEBaseViewController.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TEBaseViewController.h"
|
||||
|
||||
#import "flatbuffers/flatbuffers.h"
|
||||
#import "flatbuffers/idl.h"
|
||||
#import <AsyncDisplayKit/ASCollectionViewHelper.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode.h>
|
||||
#import "TECellView.h"
|
||||
#import "UIViewController+TEActions.h"
|
||||
#import <memory>
|
||||
|
||||
@interface TEBaseViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation TEBaseViewController {
|
||||
ASCollectionViewHelper *_texHelper;
|
||||
// NOTE: This is only safe because the NSData behind this pointer is retained
|
||||
// by a static variable.
|
||||
const UICollection *_data;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
|
||||
static NSData *pacManData;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
pacManData = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"PacMan" ofType:@"bin"]];
|
||||
});
|
||||
|
||||
|
||||
_data = GetUICollection(pacManData.bytes);
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Act" style:UIBarButtonItemStyleDone target:self action:TEActionShowMenu];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)actionsForMenu {
|
||||
return @[ NSStringFromSelector(TEActionPushNewInstance),
|
||||
NSStringFromSelector(@selector(reloadData)) ];
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
NSAssert(NO, @"Abstract method.");
|
||||
}
|
||||
|
||||
- (void)perform:(void (NS_NOESCAPE ^)())updates {
|
||||
NSAssert(NO, @"Abstract method.");
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSections {
|
||||
return _data->sections()->size();
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfItemsIn:(NSInteger)section {
|
||||
return _data->sections()->Get((flatbuffers::uoffset_t)section)->items()->size();
|
||||
}
|
||||
|
||||
- (CGSize)sizeAt:(const TEPath &)path {
|
||||
auto item = [self _itemAt:path];
|
||||
// No item is valid. Could be this section has no footer, for example.
|
||||
if (!item) {
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
if (item->use_texture()) {
|
||||
ASDisplayNode *node; // TODO: Get the node from somewhere.
|
||||
return node.calculatedSize;
|
||||
} else {
|
||||
return [TECellView sizeForItem:*item inContainer:self.view];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)reuseIdentifierAt:(const TEPath &)path {
|
||||
return ([self _itemAt:path]->use_texture() ? TEViewPlatformTexture : TEViewPlatformPlain);
|
||||
}
|
||||
|
||||
- (void)hostItemAt:(const TEPath &)path in:(UIView *)contentView {
|
||||
auto item = [self _itemAt:path];
|
||||
if (item->use_texture()) {
|
||||
ASDisplayNode *node; // TODO: Get the node from somewhere.
|
||||
unowned UIView *nodeView = node.view;
|
||||
if ([contentView.subviews indexOfObjectIdenticalTo:nodeView] == NSNotFound) {
|
||||
for (UIView *subview in contentView.subviews) {
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
[contentView addSubview:nodeView];
|
||||
}
|
||||
} else {
|
||||
auto view = [TECellView hostInContentViewIfNeeded:contentView];
|
||||
[view setItem:*item];
|
||||
}
|
||||
}
|
||||
|
||||
- (const Item *)_itemAt:(const TEPath &)path {
|
||||
if (path.supplementaryElementKind == UICollectionElementKindSectionHeader) {
|
||||
return _data->sections()->Get(path.section)->header();
|
||||
} else if (path.supplementaryElementKind == UICollectionElementKindSectionFooter) {
|
||||
return _data->sections()->Get(path.section)->footer();
|
||||
} else {
|
||||
return _data->sections()->Get(path.section)->items()->Get(path.item);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// TECellNode.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
#import "ui_collection_generated.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TECellNode : ASDisplayNode
|
||||
|
||||
- (void)setItem:(const Item &)item;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// TECellNode.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TECellNode.h"
|
||||
|
||||
@implementation TECellNode {
|
||||
ASTextNode *_titleNode;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_titleNode = [[ASTextNode alloc] init];
|
||||
self.automaticallyManagesSubnodes = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize {
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:5 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsCenter children:@[ _titleNode ]];
|
||||
}
|
||||
|
||||
- (void)setItem:(const Item &)item {
|
||||
auto textPtr = item.text();
|
||||
auto nsstr = [[NSString alloc] initWithBytes:textPtr->c_str() length:textPtr->size() encoding:NSUTF8StringEncoding];
|
||||
_titleNode.attributedText = [[NSAttributedString alloc] initWithString:nsstr];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// TECellView.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "ui_collection_generated.h"
|
||||
#include <memory>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TEModel;
|
||||
|
||||
@interface TECellView : UIView
|
||||
|
||||
- (void)setItem:(const Item &)item;
|
||||
|
||||
+ (TECellView *)hostInContentViewIfNeeded:(UIView *)contentView;
|
||||
|
||||
+ (CGSize)sizeForItem:(const Item &)item inContainer:(UIView *)view;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// TECellView.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TECellView.h"
|
||||
|
||||
@implementation TECellView {
|
||||
UIStackView *_stackView;
|
||||
UILabel *_label;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
_stackView = [[UIStackView alloc] initWithFrame:self.bounds];
|
||||
_stackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self addSubview:_stackView];
|
||||
|
||||
_label = [[UILabel alloc] init];
|
||||
[_stackView addArrangedSubview:_label];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setItem:(const Item &)item {
|
||||
auto textPtr = item.text();
|
||||
_label.text = [[NSString alloc] initWithBytes:textPtr->c_str() length:textPtr->size() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
+ (TECellView *)hostInContentViewIfNeeded:(UIView *)contentView {
|
||||
TECellView *view = contentView.subviews.firstObject;
|
||||
if (view) {
|
||||
return view;
|
||||
}
|
||||
view = [[TECellView alloc] initWithFrame:contentView.bounds];
|
||||
[contentView addSubview:view];
|
||||
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
return view;
|
||||
}
|
||||
|
||||
+ (CGSize)sizeForItem:(const Item &)item inContainer:(UIView *)view {
|
||||
NSAssert(NSThread.isMainThread, nil);
|
||||
static TECellView *mannequinView;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
mannequinView = [[TECellView alloc] init];
|
||||
});
|
||||
[mannequinView setItem:item];
|
||||
return [mannequinView sizeThatFits:view.bounds.size];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TECollectionViewController.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TEBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TECollectionViewController : TEBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// TECollectionViewController.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TECollectionViewController.h"
|
||||
|
||||
@interface TECollectionViewController () <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource>
|
||||
|
||||
@end
|
||||
|
||||
@implementation TECollectionViewController {
|
||||
UICollectionView *_collectionView;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
|
||||
static NSInteger instanceID = 1;
|
||||
self.title = [NSString stringWithFormat:@"Collection #%ld", (long)instanceID++];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
UIView *view = self.view;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:view.bounds collectionViewLayout:[UICollectionViewFlowLayout new]];
|
||||
[_collectionView registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:TEViewPlatformTexture];
|
||||
[_collectionView registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:TEViewPlatformPlain];
|
||||
[_collectionView registerClass:UICollectionReusableView.class forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:TEViewPlatformTexture];
|
||||
[_collectionView registerClass:UICollectionReusableView.class forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:TEViewPlatformPlain];
|
||||
[_collectionView registerClass:UICollectionReusableView.class forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:TEViewPlatformTexture];
|
||||
[_collectionView registerClass:UICollectionReusableView.class forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:TEViewPlatformPlain];
|
||||
_collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.dataSource = self;
|
||||
[view addSubview:_collectionView];
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
[_collectionView reloadData];
|
||||
}
|
||||
|
||||
- (void)perform:(void (NS_NOESCAPE ^)())updates {
|
||||
[_collectionView performBatchUpdates:updates completion:nil];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
return [self numberOfSections];
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return [self numberOfItemsIn:section];
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return [self sizeAt:TEPath::make(indexPath)];
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
return [self sizeAt:TEPath::header(section)];
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section {
|
||||
return [self sizeAt:TEPath::footer(section)];
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
auto path = TEPath::make(indexPath);
|
||||
auto reuseID = [self reuseIdentifierAt:path];
|
||||
auto cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseID forIndexPath:indexPath];
|
||||
[self hostItemAt:path in:cell.contentView];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
||||
auto path = TEPath::make(indexPath, kind);
|
||||
auto reuseID = [self reuseIdentifierAt:path];
|
||||
auto cell = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:reuseID forIndexPath:indexPath];
|
||||
[self hostItemAt:path in:cell];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// TETableViewController.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TEBaseViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TETableViewController : TEBaseViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// TETableViewController.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TETableViewController.h"
|
||||
|
||||
@interface TETableViewController () <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
@end
|
||||
|
||||
@implementation TETableViewController {
|
||||
UITableView *_tableView;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
|
||||
static NSInteger instanceID = 1;
|
||||
self.title = [NSString stringWithFormat:@"Table #%ld", (long)instanceID++];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
UIView *view = self.view;
|
||||
_tableView = [[UITableView alloc] initWithFrame:view.bounds style:UITableViewStylePlain];
|
||||
[_tableView registerClass:UITableViewCell.class forCellReuseIdentifier:TEViewPlatformPlain];
|
||||
[_tableView registerClass:UITableViewCell.class forCellReuseIdentifier:TEViewPlatformTexture];
|
||||
|
||||
[_tableView registerClass:UITableViewHeaderFooterView.class forHeaderFooterViewReuseIdentifier:TEViewPlatformPlain];
|
||||
[_tableView registerClass:UITableViewHeaderFooterView.class forHeaderFooterViewReuseIdentifier:TEViewPlatformTexture];
|
||||
_tableView.delegate = self;
|
||||
_tableView.dataSource = self;
|
||||
[view addSubview:_tableView];
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
[_tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)perform:(void (NS_NOESCAPE ^)())updates {
|
||||
[_tableView beginUpdates];
|
||||
updates();
|
||||
[_tableView endUpdates];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return [self numberOfSections];
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return [self numberOfItemsIn:section];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return [self sizeAt:TEPath::make(indexPath)].height;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
||||
return [self sizeAt:TEPath::header(section)].height;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
|
||||
return [self sizeAt:TEPath::footer(section)].height;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
auto path = TEPath::make(indexPath);
|
||||
auto reuseID = [self reuseIdentifierAt:path];
|
||||
auto cell = [tableView dequeueReusableCellWithIdentifier:reuseID forIndexPath:indexPath];
|
||||
[self hostItemAt:path in:cell.contentView];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
|
||||
auto path = TEPath::header(section);
|
||||
auto reuseID = [self reuseIdentifierAt:path];
|
||||
auto cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:reuseID];
|
||||
[self hostItemAt:path in:cell.contentView];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
||||
auto path = TEPath::footer(section);
|
||||
auto reuseID = [self reuseIdentifierAt:path];
|
||||
auto cell = [tableView dequeueReusableHeaderFooterViewWithIdentifier:reuseID];
|
||||
[self hostItemAt:path in:cell.contentView];
|
||||
return cell;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// UIViewController+TEActions.h
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static SEL const TEActionShowMenu = sel_getUid("showActionsMenu:");
|
||||
static SEL const TEActionPushNewInstance = sel_getUid("pushNewInstance:");
|
||||
|
||||
@interface UIResponder (TEActions)
|
||||
- (void)showActionsMenu:(id)sender;
|
||||
- (nullable NSArray<NSString *> *)actionsForMenu;
|
||||
@end
|
||||
|
||||
@interface UIViewController (TEActions)
|
||||
|
||||
- (void)pushNewInstance:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// UIViewController+TEActions.m
|
||||
// Sample
|
||||
//
|
||||
// Created by Adlai Holler on 9/21/18.
|
||||
// Copyright © 2018 Facebook. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIViewController+TEActions.h"
|
||||
|
||||
@implementation UIResponder (TEActions)
|
||||
|
||||
- (void)showActionsMenu:(id)sender {
|
||||
auto actionLists = [[NSMutableArray<NSArray<NSString *> *> alloc] init];
|
||||
auto responders = [[NSMutableArray<UIResponder *> alloc] init];
|
||||
UINavigationController *navCtrl;
|
||||
|
||||
__unsafe_unretained UIResponder *responder = self;
|
||||
while (responder) {
|
||||
auto actions = [responder actionsForMenu];
|
||||
if (actions.count > 0) {
|
||||
[actionLists addObject:actions];
|
||||
[responders addObject:responder];
|
||||
}
|
||||
if (!navCtrl && [responder isKindOfClass:[UINavigationController class]]) {
|
||||
navCtrl = (UINavigationController *)responder;
|
||||
}
|
||||
responder = [responder nextResponder];
|
||||
}
|
||||
// Found no actions anywhere in responder chain.
|
||||
if (!actionLists.count) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIAlertController *ac = [UIAlertController alertControllerWithTitle:@"Actions" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
for (int i = 0; i < actionLists.count; i++) {
|
||||
NSString *headerTitle = [NSString stringWithFormat:@"-- %@ --", responders[i].class];
|
||||
auto headerAction = [UIAlertAction actionWithTitle:headerTitle style:UIAlertActionStyleDefault handler:nil];
|
||||
headerAction.enabled = NO;
|
||||
[ac addAction:headerAction];
|
||||
|
||||
for (int j = 0; j < actionLists[i].count; j++) {
|
||||
NSString *title = actionLists[i][j];
|
||||
auto action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
|
||||
[UIApplication.sharedApplication sendAction:NSSelectorFromString(title) to:responders[i] from:sender forEvent:nil];
|
||||
}];
|
||||
[ac addAction:action];
|
||||
}
|
||||
}
|
||||
auto cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
|
||||
[ac addAction:cancel];
|
||||
[navCtrl presentViewController:ac animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)actionsForMenu {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@implementation UIViewController (TEActions)
|
||||
|
||||
- (void)pushNewInstance:(id)sender
|
||||
{
|
||||
UIViewController *inst = [[self.class alloc] init];
|
||||
[self showViewController:inst sender:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,235 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_UICOLLECTION_H_
|
||||
#define FLATBUFFERS_GENERATED_UICOLLECTION_H_
|
||||
|
||||
#pragma clang system_header
|
||||
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
struct Item;
|
||||
|
||||
struct Section;
|
||||
|
||||
struct UICollection;
|
||||
|
||||
struct Item FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_USE_TEXTURE = 4,
|
||||
VT_TEXT = 6
|
||||
};
|
||||
bool use_texture() const {
|
||||
return GetField<uint8_t>(VT_USE_TEXTURE, 0) != 0;
|
||||
}
|
||||
const flatbuffers::String * _Nullable text() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_TEXT);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<uint8_t>(verifier, VT_USE_TEXTURE) &&
|
||||
VerifyOffset(verifier, VT_TEXT) &&
|
||||
verifier.Verify(text()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct ItemBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_use_texture(bool use_texture) {
|
||||
fbb_.AddElement<uint8_t>(Item::VT_USE_TEXTURE, static_cast<uint8_t>(use_texture), 0);
|
||||
}
|
||||
void add_text(flatbuffers::Offset<flatbuffers::String> text) {
|
||||
fbb_.AddOffset(Item::VT_TEXT, text);
|
||||
}
|
||||
explicit ItemBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
ItemBuilder &operator=(const ItemBuilder &);
|
||||
flatbuffers::Offset<Item> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Item>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Item> CreateItem(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
bool use_texture = false,
|
||||
flatbuffers::Offset<flatbuffers::String> text = 0) {
|
||||
ItemBuilder builder_(_fbb);
|
||||
builder_.add_text(text);
|
||||
builder_.add_use_texture(use_texture);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Item> CreateItemDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
bool use_texture = false,
|
||||
const char *text = nullptr) {
|
||||
return CreateItem(
|
||||
_fbb,
|
||||
use_texture,
|
||||
text ? _fbb.CreateString(text) : 0);
|
||||
}
|
||||
|
||||
struct Section FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_HEADER = 4,
|
||||
VT_FOOTER = 6,
|
||||
VT_ITEMS = 8
|
||||
};
|
||||
const Item * _Nullable header() const {
|
||||
return GetPointer<const Item *>(VT_HEADER);
|
||||
}
|
||||
const Item * _Nullable footer() const {
|
||||
return GetPointer<const Item *>(VT_FOOTER);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Item>> * _Nullable items() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Item>> *>(VT_ITEMS);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffset(verifier, VT_HEADER) &&
|
||||
verifier.VerifyTable(header()) &&
|
||||
VerifyOffset(verifier, VT_FOOTER) &&
|
||||
verifier.VerifyTable(footer()) &&
|
||||
VerifyOffset(verifier, VT_ITEMS) &&
|
||||
verifier.Verify(items()) &&
|
||||
verifier.VerifyVectorOfTables(items()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct SectionBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_header(flatbuffers::Offset<Item> header) {
|
||||
fbb_.AddOffset(Section::VT_HEADER, header);
|
||||
}
|
||||
void add_footer(flatbuffers::Offset<Item> footer) {
|
||||
fbb_.AddOffset(Section::VT_FOOTER, footer);
|
||||
}
|
||||
void add_items(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Item>>> items) {
|
||||
fbb_.AddOffset(Section::VT_ITEMS, items);
|
||||
}
|
||||
explicit SectionBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
SectionBuilder &operator=(const SectionBuilder &);
|
||||
flatbuffers::Offset<Section> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Section>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Section> CreateSection(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<Item> header = 0,
|
||||
flatbuffers::Offset<Item> footer = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Item>>> items = 0) {
|
||||
SectionBuilder builder_(_fbb);
|
||||
builder_.add_items(items);
|
||||
builder_.add_footer(footer);
|
||||
builder_.add_header(header);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Section> CreateSectionDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<Item> header = 0,
|
||||
flatbuffers::Offset<Item> footer = 0,
|
||||
const std::vector<flatbuffers::Offset<Item>> *items = nullptr) {
|
||||
return CreateSection(
|
||||
_fbb,
|
||||
header,
|
||||
footer,
|
||||
items ? _fbb.CreateVector<flatbuffers::Offset<Item>>(*items) : 0);
|
||||
}
|
||||
|
||||
struct UICollection FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_SECTIONS = 4
|
||||
};
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Section>> * _Nullable sections() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Section>> *>(VT_SECTIONS);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffset(verifier, VT_SECTIONS) &&
|
||||
verifier.Verify(sections()) &&
|
||||
verifier.VerifyVectorOfTables(sections()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct UICollectionBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_sections(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Section>>> sections) {
|
||||
fbb_.AddOffset(UICollection::VT_SECTIONS, sections);
|
||||
}
|
||||
explicit UICollectionBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
UICollectionBuilder &operator=(const UICollectionBuilder &);
|
||||
flatbuffers::Offset<UICollection> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<UICollection>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<UICollection> CreateUICollection(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Section>>> sections = 0) {
|
||||
UICollectionBuilder builder_(_fbb);
|
||||
builder_.add_sections(sections);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<UICollection> CreateUICollectionDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<flatbuffers::Offset<Section>> *sections = nullptr) {
|
||||
return CreateUICollection(
|
||||
_fbb,
|
||||
sections ? _fbb.CreateVector<flatbuffers::Offset<Section>>(*sections) : 0);
|
||||
}
|
||||
|
||||
inline const UICollection * _Nullable GetUICollection(const void *buf) {
|
||||
return flatbuffers::GetRoot<UICollection>(buf);
|
||||
}
|
||||
|
||||
inline const UICollection * _Nullable GetSizePrefixedUICollection(const void *buf) {
|
||||
return flatbuffers::GetSizePrefixedRoot<UICollection>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyUICollectionBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<UICollection>(nullptr);
|
||||
}
|
||||
|
||||
inline bool VerifySizePrefixedUICollectionBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifySizePrefixedBuffer<UICollection>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishUICollectionBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<UICollection> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline void FinishSizePrefixedUICollectionBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<UICollection> root) {
|
||||
fbb.FinishSizePrefixed(root);
|
||||
}
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_UICOLLECTION_H_
|
||||
@@ -0,0 +1,16 @@
|
||||
table Item {
|
||||
use_texture:bool;
|
||||
text:string;
|
||||
}
|
||||
|
||||
table Section {
|
||||
header:Item;
|
||||
footer:Item;
|
||||
items:[Item];
|
||||
}
|
||||
|
||||
table UICollection {
|
||||
sections:[Section];
|
||||
}
|
||||
|
||||
root_type UICollection;
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// main.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "TEAppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([TEAppDelegate class]));
|
||||
}
|
||||
}
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
#ifndef FLATBUFFERS_BASE_H_
|
||||
#define FLATBUFFERS_BASE_H_
|
||||
|
||||
// clang-format off
|
||||
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||
defined(_MSC_VER) && defined(_DEBUG)
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
|
||||
defined(_MSC_VER) && defined(_DEBUG)
|
||||
#include <crtdbg.h>
|
||||
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
|
||||
#include <utility.h>
|
||||
#else
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _STLPORT_VERSION
|
||||
#define FLATBUFFERS_CPP98_STL
|
||||
#endif
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#include <functional>
|
||||
#endif
|
||||
|
||||
#include "flatbuffers/stl_emulation.h"
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
#if __cplusplus <= 199711L && \
|
||||
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
|
||||
(!defined(__GNUC__) || \
|
||||
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
|
||||
#error A C++11 compatible compiler with support for the auto typing is \
|
||||
required for FlatBuffers.
|
||||
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
|
||||
#endif
|
||||
|
||||
#if !defined(__clang__) && \
|
||||
defined(__GNUC__) && \
|
||||
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
|
||||
// Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
|
||||
// and constexpr keywords. Note the __clang__ check is needed, because clang
|
||||
// presents itself as an older GNUC compiler.
|
||||
#ifndef nullptr_t
|
||||
const class nullptr_t {
|
||||
public:
|
||||
template<class T> inline operator T*() const { return 0; }
|
||||
private:
|
||||
void operator&() const;
|
||||
} nullptr = {};
|
||||
#endif
|
||||
#ifndef constexpr
|
||||
#define constexpr const
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The wire format uses a little endian encoding (since that's efficient for
|
||||
// the common platforms).
|
||||
#if defined(__s390x__)
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#endif // __s390x__
|
||||
#if !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#else
|
||||
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||
#endif // __BIG_ENDIAN__
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(_M_PPC)
|
||||
#define FLATBUFFERS_LITTLEENDIAN 0
|
||||
#else
|
||||
#define FLATBUFFERS_LITTLEENDIAN 1
|
||||
#endif
|
||||
#else
|
||||
#error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
|
||||
#endif
|
||||
#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
|
||||
|
||||
#define FLATBUFFERS_VERSION_MAJOR 1
|
||||
#define FLATBUFFERS_VERSION_MINOR 9
|
||||
#define FLATBUFFERS_VERSION_REVISION 0
|
||||
#define FLATBUFFERS_STRING_EXPAND(X) #X
|
||||
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
|
||||
#define FLATBUFFERS_FINAL_CLASS final
|
||||
#define FLATBUFFERS_OVERRIDE override
|
||||
#else
|
||||
#define FLATBUFFERS_FINAL_CLASS
|
||||
#define FLATBUFFERS_OVERRIDE
|
||||
#endif
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
|
||||
#define FLATBUFFERS_CONSTEXPR constexpr
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
||||
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP14
|
||||
#endif
|
||||
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
|
||||
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#define FLATBUFFERS_NOEXCEPT noexcept
|
||||
#else
|
||||
#define FLATBUFFERS_NOEXCEPT
|
||||
#endif
|
||||
|
||||
// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
|
||||
// private, so be sure to put it at the end or reset access mode explicitly.
|
||||
#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404))
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) func = delete;
|
||||
#else
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) private: func;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
|
||||
/// @file
|
||||
namespace flatbuffers {
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
// Our default offset / size type, 32bit on purpose on 64bit systems.
|
||||
// Also, using a consistent offset type maintains compatibility of serialized
|
||||
// offset values between 32bit and 64bit systems.
|
||||
typedef uint32_t uoffset_t;
|
||||
|
||||
// Signed offsets for references that can go in both directions.
|
||||
typedef int32_t soffset_t;
|
||||
|
||||
// Offset/index used in v-tables, can be changed to uint8_t in
|
||||
// format forks to save a bit of space if desired.
|
||||
typedef uint16_t voffset_t;
|
||||
|
||||
typedef uintmax_t largest_scalar_t;
|
||||
|
||||
// In 32bits, this evaluates to 2GB - 1
|
||||
#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
|
||||
|
||||
// We support aligning the contents of buffers up to this size.
|
||||
#define FLATBUFFERS_MAX_ALIGNMENT 16
|
||||
|
||||
template<typename T> T EndianSwap(T t) {
|
||||
#if defined(_MSC_VER)
|
||||
#define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
|
||||
#define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
|
||||
#define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
|
||||
#else
|
||||
#if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
|
||||
// __builtin_bswap16 was missing prior to GCC 4.8.
|
||||
#define FLATBUFFERS_BYTESWAP16(x) \
|
||||
static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
|
||||
#else
|
||||
#define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
|
||||
#endif
|
||||
#define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
|
||||
#define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
|
||||
#endif
|
||||
if (sizeof(T) == 1) { // Compile-time if-then's.
|
||||
return t;
|
||||
} else if (sizeof(T) == 2) {
|
||||
union { T t; uint16_t i; } u;
|
||||
u.t = t;
|
||||
u.i = FLATBUFFERS_BYTESWAP16(u.i);
|
||||
return u.t;
|
||||
} else if (sizeof(T) == 4) {
|
||||
union { T t; uint32_t i; } u;
|
||||
u.t = t;
|
||||
u.i = FLATBUFFERS_BYTESWAP32(u.i);
|
||||
return u.t;
|
||||
} else if (sizeof(T) == 8) {
|
||||
union { T t; uint64_t i; } u;
|
||||
u.t = t;
|
||||
u.i = FLATBUFFERS_BYTESWAP64(u.i);
|
||||
return u.t;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T> T EndianScalar(T t) {
|
||||
#if FLATBUFFERS_LITTLEENDIAN
|
||||
return t;
|
||||
#else
|
||||
return EndianSwap(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> T ReadScalar(const void *p) {
|
||||
return EndianScalar(*reinterpret_cast<const T *>(p));
|
||||
}
|
||||
|
||||
template<typename T> void WriteScalar(void *p, T t) {
|
||||
*reinterpret_cast<T *>(p) = EndianScalar(t);
|
||||
}
|
||||
|
||||
// Computes how many bytes you'd have to pad to be able to write an
|
||||
// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
|
||||
// memory).
|
||||
inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
|
||||
return ((~buf_size) + 1) & (scalar_size - 1);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
#endif // FLATBUFFERS_BASE_H_
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_CODE_GENERATORS_H_
|
||||
#define FLATBUFFERS_CODE_GENERATORS_H_
|
||||
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include "flatbuffers/idl.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Utility class to assist in generating code through use of text templates.
|
||||
//
|
||||
// Example code:
|
||||
// CodeWriter code;
|
||||
// code.SetValue("NAME", "Foo");
|
||||
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
|
||||
// code.SetValue("NAME", "Bar");
|
||||
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
|
||||
// std::cout << code.ToString() << std::endl;
|
||||
//
|
||||
// Output:
|
||||
// void Foo() { printf("%s", "Foo"); }
|
||||
// void Bar() { printf("%s", "Bar"); }
|
||||
class CodeWriter {
|
||||
public:
|
||||
CodeWriter() {}
|
||||
|
||||
// Clears the current "written" code.
|
||||
void Clear() {
|
||||
stream_.str("");
|
||||
stream_.clear();
|
||||
}
|
||||
|
||||
// Associates a key with a value. All subsequent calls to operator+=, where
|
||||
// the specified key is contained in {{ and }} delimiters will be replaced by
|
||||
// the given value.
|
||||
void SetValue(const std::string &key, const std::string &value) {
|
||||
value_map_[key] = value;
|
||||
}
|
||||
|
||||
// Appends the given text to the generated code as well as a newline
|
||||
// character. Any text within {{ and }} delimeters is replaced by values
|
||||
// previously stored in the CodeWriter by calling SetValue above. The newline
|
||||
// will be suppressed if the text ends with the \\ character.
|
||||
void operator+=(std::string text);
|
||||
|
||||
// Returns the current contents of the CodeWriter as a std::string.
|
||||
std::string ToString() const { return stream_.str(); }
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> value_map_;
|
||||
std::stringstream stream_;
|
||||
};
|
||||
|
||||
class BaseGenerator {
|
||||
public:
|
||||
virtual bool generate() = 0;
|
||||
|
||||
static std::string NamespaceDir(const Parser &parser, const std::string &path,
|
||||
const Namespace &ns);
|
||||
|
||||
protected:
|
||||
BaseGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name,
|
||||
const std::string qualifying_start,
|
||||
const std::string qualifying_separator)
|
||||
: parser_(parser),
|
||||
path_(path),
|
||||
file_name_(file_name),
|
||||
qualifying_start_(qualifying_start),
|
||||
qualifying_separator_(qualifying_separator) {}
|
||||
virtual ~BaseGenerator() {}
|
||||
|
||||
// No copy/assign.
|
||||
BaseGenerator &operator=(const BaseGenerator &);
|
||||
BaseGenerator(const BaseGenerator &);
|
||||
|
||||
std::string NamespaceDir(const Namespace &ns) const;
|
||||
|
||||
static const char *FlatBuffersGeneratedWarning();
|
||||
|
||||
static std::string FullNamespace(const char *separator, const Namespace &ns);
|
||||
|
||||
static std::string LastNamespacePart(const Namespace &ns);
|
||||
|
||||
// tracks the current namespace for early exit in WrapInNameSpace
|
||||
// c++, java and csharp returns a different namespace from
|
||||
// the following default (no early exit, always fully qualify),
|
||||
// which works for js and php
|
||||
virtual const Namespace *CurrentNameSpace() const { return nullptr; }
|
||||
|
||||
// Ensure that a type is prefixed with its namespace whenever it is used
|
||||
// outside of its namespace.
|
||||
std::string WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) const;
|
||||
|
||||
std::string WrapInNameSpace(const Definition &def) const;
|
||||
|
||||
std::string GetNameSpace(const Definition &def) const;
|
||||
|
||||
const Parser &parser_;
|
||||
const std::string &path_;
|
||||
const std::string &file_name_;
|
||||
const std::string qualifying_start_;
|
||||
const std::string qualifying_separator_;
|
||||
};
|
||||
|
||||
struct CommentConfig {
|
||||
const char *first_line;
|
||||
const char *content_line_prefix;
|
||||
const char *last_line;
|
||||
};
|
||||
|
||||
extern void GenComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr, const CommentConfig *config,
|
||||
const char *prefix = "");
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_CODE_GENERATORS_H_
|
||||
+2280
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2017 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 <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#ifndef FLATC_H_
|
||||
# define FLATC_H_
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
class FlatCompiler {
|
||||
public:
|
||||
// Output generator for the various programming languages and formats we
|
||||
// support.
|
||||
struct Generator {
|
||||
typedef bool (*GenerateFn)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
typedef std::string (*MakeRuleFn)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
GenerateFn generate;
|
||||
const char *generator_opt_short;
|
||||
const char *generator_opt_long;
|
||||
const char *lang_name;
|
||||
bool schema_only;
|
||||
GenerateFn generateGRPC;
|
||||
flatbuffers::IDLOptions::Language lang;
|
||||
const char *generator_help;
|
||||
MakeRuleFn make_rule;
|
||||
};
|
||||
|
||||
typedef void (*WarnFn)(const FlatCompiler *flatc, const std::string &warn,
|
||||
bool show_exe_name);
|
||||
|
||||
typedef void (*ErrorFn)(const FlatCompiler *flatc, const std::string &err,
|
||||
bool usage, bool show_exe_name);
|
||||
|
||||
// Parameters required to initialize the FlatCompiler.
|
||||
struct InitParams {
|
||||
InitParams()
|
||||
: generators(nullptr),
|
||||
num_generators(0),
|
||||
warn_fn(nullptr),
|
||||
error_fn(nullptr) {}
|
||||
|
||||
const Generator *generators;
|
||||
size_t num_generators;
|
||||
WarnFn warn_fn;
|
||||
ErrorFn error_fn;
|
||||
};
|
||||
|
||||
explicit FlatCompiler(const InitParams ¶ms) : params_(params) {}
|
||||
|
||||
int Compile(int argc, const char **argv);
|
||||
|
||||
std::string GetUsageString(const char *program_name) const;
|
||||
|
||||
private:
|
||||
void ParseFile(flatbuffers::Parser &parser, const std::string &filename,
|
||||
const std::string &contents,
|
||||
std::vector<const char *> &include_directories) const;
|
||||
|
||||
void Warn(const std::string &warn, bool show_exe_name = true) const;
|
||||
|
||||
void Error(const std::string &err, bool usage = true,
|
||||
bool show_exe_name = true) const;
|
||||
|
||||
InitParams params_;
|
||||
};
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATC_H_
|
||||
+1523
File diff suppressed because it is too large
Load Diff
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_GRPC_H_
|
||||
#define FLATBUFFERS_GRPC_H_
|
||||
|
||||
// Helper functionality to glue FlatBuffers and GRPC.
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "grpc++/support/byte_buffer.h"
|
||||
#include "grpc/byte_buffer_reader.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace grpc {
|
||||
|
||||
// Message is a typed wrapper around a buffer that manages the underlying
|
||||
// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
|
||||
// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
|
||||
// is refcounted and ownership is be managed automatically.
|
||||
template<class T> class Message {
|
||||
public:
|
||||
Message() : slice_(grpc_empty_slice()) {}
|
||||
|
||||
Message(grpc_slice slice, bool add_ref)
|
||||
: slice_(add_ref ? grpc_slice_ref(slice) : slice) {}
|
||||
|
||||
Message &operator=(const Message &other) = delete;
|
||||
|
||||
Message(Message &&other) : slice_(other.slice_) {
|
||||
other.slice_ = grpc_empty_slice();
|
||||
}
|
||||
|
||||
Message(const Message &other) = delete;
|
||||
|
||||
Message &operator=(Message &&other) {
|
||||
grpc_slice_unref(slice_);
|
||||
slice_ = other.slice_;
|
||||
other.slice_ = grpc_empty_slice();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Message() { grpc_slice_unref(slice_); }
|
||||
|
||||
const uint8_t *mutable_data() const { return GRPC_SLICE_START_PTR(slice_); }
|
||||
|
||||
const uint8_t *data() const { return GRPC_SLICE_START_PTR(slice_); }
|
||||
|
||||
size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
|
||||
|
||||
bool Verify() const {
|
||||
Verifier verifier(data(), size());
|
||||
return verifier.VerifyBuffer<T>(nullptr);
|
||||
}
|
||||
|
||||
T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
|
||||
|
||||
const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
|
||||
|
||||
// This is only intended for serializer use, or if you know what you're doing
|
||||
const grpc_slice &BorrowSlice() const { return slice_; }
|
||||
|
||||
private:
|
||||
grpc_slice slice_;
|
||||
};
|
||||
|
||||
class MessageBuilder;
|
||||
|
||||
// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
|
||||
// refcounted slices to manage memory ownership. This makes it easy and
|
||||
// efficient to transfer buffers to gRPC.
|
||||
class SliceAllocator : public Allocator {
|
||||
public:
|
||||
SliceAllocator() : slice_(grpc_empty_slice()) {}
|
||||
|
||||
SliceAllocator(const SliceAllocator &other) = delete;
|
||||
SliceAllocator &operator=(const SliceAllocator &other) = delete;
|
||||
|
||||
virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
|
||||
|
||||
virtual uint8_t *allocate(size_t size) override {
|
||||
assert(GRPC_SLICE_IS_EMPTY(slice_));
|
||||
slice_ = grpc_slice_malloc(size);
|
||||
return GRPC_SLICE_START_PTR(slice_);
|
||||
}
|
||||
|
||||
virtual void deallocate(uint8_t *p, size_t size) override {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(size == GRPC_SLICE_LENGTH(slice_));
|
||||
grpc_slice_unref(slice_);
|
||||
slice_ = grpc_empty_slice();
|
||||
}
|
||||
|
||||
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
|
||||
size_t new_size, size_t in_use_back,
|
||||
size_t in_use_front) override {
|
||||
assert(old_p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(old_size == GRPC_SLICE_LENGTH(slice_));
|
||||
assert(new_size > old_size);
|
||||
grpc_slice old_slice = slice_;
|
||||
grpc_slice new_slice = grpc_slice_malloc(new_size);
|
||||
uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
|
||||
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
|
||||
in_use_front);
|
||||
slice_ = new_slice;
|
||||
grpc_slice_unref(old_slice);
|
||||
return new_p;
|
||||
}
|
||||
|
||||
private:
|
||||
grpc_slice &get_slice(uint8_t *p, size_t size) {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(size == GRPC_SLICE_LENGTH(slice_));
|
||||
return slice_;
|
||||
}
|
||||
|
||||
grpc_slice slice_;
|
||||
|
||||
friend class MessageBuilder;
|
||||
};
|
||||
|
||||
// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
|
||||
// slice_allocator_ member is constructed before the FlatBufferBuilder, since
|
||||
// the allocator is used in the FlatBufferBuilder ctor.
|
||||
namespace detail {
|
||||
struct SliceAllocatorMember {
|
||||
SliceAllocator slice_allocator_;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
|
||||
// to allocate gRPC buffers.
|
||||
class MessageBuilder : private detail::SliceAllocatorMember,
|
||||
public FlatBufferBuilder {
|
||||
public:
|
||||
explicit MessageBuilder(uoffset_t initial_size = 1024)
|
||||
: FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
|
||||
|
||||
MessageBuilder(const MessageBuilder &other) = delete;
|
||||
MessageBuilder &operator=(const MessageBuilder &other) = delete;
|
||||
|
||||
~MessageBuilder() {}
|
||||
|
||||
// GetMessage extracts the subslice of the buffer corresponding to the
|
||||
// flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
|
||||
// ownership.
|
||||
template<class T> Message<T> GetMessage() {
|
||||
auto buf_data = buf_.scratch_data(); // pointer to memory
|
||||
auto buf_size = buf_.capacity(); // size of memory
|
||||
auto msg_data = buf_.data(); // pointer to msg
|
||||
auto msg_size = buf_.size(); // size of msg
|
||||
// Do some sanity checks on data/size
|
||||
assert(msg_data);
|
||||
assert(msg_size);
|
||||
assert(msg_data >= buf_data);
|
||||
assert(msg_data + msg_size <= buf_data + buf_size);
|
||||
// Calculate offsets from the buffer start
|
||||
auto begin = msg_data - buf_data;
|
||||
auto end = begin + msg_size;
|
||||
// Get the slice we are working with (no refcount change)
|
||||
grpc_slice slice = slice_allocator_.get_slice(buf_data, buf_size);
|
||||
// Extract a subslice of the existing slice (increment refcount)
|
||||
grpc_slice subslice = grpc_slice_sub(slice, begin, end);
|
||||
// Wrap the subslice in a `Message<T>`, but don't increment refcount
|
||||
Message<T> msg(subslice, false);
|
||||
return msg;
|
||||
}
|
||||
|
||||
template<class T> Message<T> ReleaseMessage() {
|
||||
Message<T> msg = GetMessage<T>();
|
||||
Reset();
|
||||
return msg;
|
||||
}
|
||||
|
||||
private:
|
||||
// SliceAllocator slice_allocator_; // part of SliceAllocatorMember
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
} // namespace flatbuffers
|
||||
|
||||
namespace grpc {
|
||||
|
||||
template<class T> class SerializationTraits<flatbuffers::grpc::Message<T>> {
|
||||
public:
|
||||
static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg,
|
||||
grpc_byte_buffer **buffer, bool *own_buffer) {
|
||||
// We are passed in a `Message<T>`, which is a wrapper around a
|
||||
// `grpc_slice`. We extract it here using `BorrowSlice()`. The const cast
|
||||
// is necesary because the `grpc_raw_byte_buffer_create` func expects
|
||||
// non-const slices in order to increment their refcounts.
|
||||
grpc_slice *slice = const_cast<grpc_slice *>(&msg.BorrowSlice());
|
||||
// Now use `grpc_raw_byte_buffer_create` to package the single slice into a
|
||||
// `grpc_byte_buffer`, incrementing the refcount in the process.
|
||||
*buffer = grpc_raw_byte_buffer_create(slice, 1);
|
||||
*own_buffer = true;
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
// Deserialize by pulling the
|
||||
static grpc::Status Deserialize(grpc_byte_buffer *buffer,
|
||||
flatbuffers::grpc::Message<T> *msg) {
|
||||
if (!buffer) {
|
||||
return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
|
||||
}
|
||||
// Check if this is a single uncompressed slice.
|
||||
if ((buffer->type == GRPC_BB_RAW) &&
|
||||
(buffer->data.raw.compression == GRPC_COMPRESS_NONE) &&
|
||||
(buffer->data.raw.slice_buffer.count == 1)) {
|
||||
// If it is, then we can reference the `grpc_slice` directly.
|
||||
grpc_slice slice = buffer->data.raw.slice_buffer.slices[0];
|
||||
// We wrap a `Message<T>` around the slice, incrementing the refcount.
|
||||
*msg = flatbuffers::grpc::Message<T>(slice, true);
|
||||
} else {
|
||||
// Otherwise, we need to use `grpc_byte_buffer_reader_readall` to read
|
||||
// `buffer` into a single contiguous `grpc_slice`. The gRPC reader gives
|
||||
// us back a new slice with the refcount already incremented.
|
||||
grpc_byte_buffer_reader reader;
|
||||
grpc_byte_buffer_reader_init(&reader, buffer);
|
||||
grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
// We wrap a `Message<T>` around the slice, but dont increment refcount
|
||||
*msg = flatbuffers::grpc::Message<T>(slice, false);
|
||||
}
|
||||
grpc_byte_buffer_destroy(buffer);
|
||||
#if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
|
||||
return ::grpc::Status::OK;
|
||||
#else
|
||||
if (msg->Verify()) {
|
||||
return ::grpc::Status::OK;
|
||||
} else {
|
||||
return ::grpc::Status(::grpc::StatusCode::INTERNAL,
|
||||
"Message verification failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // FLATBUFFERS_GRPC_H_
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_HASH_H_
|
||||
#define FLATBUFFERS_HASH_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
template<typename T> struct FnvTraits {
|
||||
static const T kFnvPrime;
|
||||
static const T kOffsetBasis;
|
||||
};
|
||||
|
||||
template<> struct FnvTraits<uint32_t> {
|
||||
static const uint32_t kFnvPrime = 0x01000193;
|
||||
static const uint32_t kOffsetBasis = 0x811C9DC5;
|
||||
};
|
||||
|
||||
template<> struct FnvTraits<uint64_t> {
|
||||
static const uint64_t kFnvPrime = 0x00000100000001b3ULL;
|
||||
static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL;
|
||||
};
|
||||
|
||||
template<typename T> FLATBUFFERS_CONSTEXPR_CPP14 T HashFnv1(const char *input) {
|
||||
T hash = FnvTraits<T>::kOffsetBasis;
|
||||
for (const char *c = input; *c; ++c) {
|
||||
hash *= FnvTraits<T>::kFnvPrime;
|
||||
hash ^= static_cast<unsigned char>(*c);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template<typename T> FLATBUFFERS_CONSTEXPR_CPP14 T HashFnv1a(const char *input) {
|
||||
T hash = FnvTraits<T>::kOffsetBasis;
|
||||
for (const char *c = input; *c; ++c) {
|
||||
hash ^= static_cast<unsigned char>(*c);
|
||||
hash *= FnvTraits<T>::kFnvPrime;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <> FLATBUFFERS_CONSTEXPR_CPP14 inline uint16_t HashFnv1<uint16_t>(const char *input) {
|
||||
uint32_t hash = HashFnv1<uint32_t>(input);
|
||||
return (hash >> 16) ^ (hash & 0xffff);
|
||||
}
|
||||
|
||||
template <> FLATBUFFERS_CONSTEXPR_CPP14 inline uint16_t HashFnv1a<uint16_t>(const char *input) {
|
||||
uint32_t hash = HashFnv1a<uint32_t>(input);
|
||||
return (hash >> 16) ^ (hash & 0xffff);
|
||||
}
|
||||
|
||||
template <typename T> struct NamedHashFunction {
|
||||
const char *name;
|
||||
|
||||
typedef T (*HashFunction)(const char *);
|
||||
HashFunction function;
|
||||
};
|
||||
|
||||
const NamedHashFunction<uint16_t> kHashFunctions16[] = {
|
||||
{ "fnv1_16", HashFnv1<uint16_t> },
|
||||
{ "fnv1a_16", HashFnv1a<uint16_t> },
|
||||
};
|
||||
|
||||
const NamedHashFunction<uint32_t> kHashFunctions32[] = {
|
||||
{ "fnv1_32", HashFnv1<uint32_t> },
|
||||
{ "fnv1a_32", HashFnv1a<uint32_t> },
|
||||
};
|
||||
|
||||
const NamedHashFunction<uint64_t> kHashFunctions64[] = {
|
||||
{ "fnv1_64", HashFnv1<uint64_t> },
|
||||
{ "fnv1a_64", HashFnv1a<uint64_t> },
|
||||
};
|
||||
|
||||
inline NamedHashFunction<uint16_t>::HashFunction FindHashFunction16(
|
||||
const char *name) {
|
||||
std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (std::strcmp(name, kHashFunctions16[i].name) == 0) {
|
||||
return kHashFunctions16[i].function;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline NamedHashFunction<uint32_t>::HashFunction FindHashFunction32(
|
||||
const char *name) {
|
||||
std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (std::strcmp(name, kHashFunctions32[i].name) == 0) {
|
||||
return kHashFunctions32[i].function;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline NamedHashFunction<uint64_t>::HashFunction FindHashFunction64(
|
||||
const char *name) {
|
||||
std::size_t size = sizeof(kHashFunctions64) / sizeof(kHashFunctions64[0]);
|
||||
for (std::size_t i = 0; i < size; ++i) {
|
||||
if (std::strcmp(name, kHashFunctions64[i].name) == 0) {
|
||||
return kHashFunctions64[i].function;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_HASH_H_
|
||||
+859
@@ -0,0 +1,859 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_IDL_H_
|
||||
#define FLATBUFFERS_IDL_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
|
||||
#include "flatbuffers/base.h"
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/reflection.h"
|
||||
|
||||
#if !defined(FLATBUFFERS_CPP98_STL)
|
||||
# include <functional>
|
||||
#endif // !defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// The order of these matters for Is*() functions below.
|
||||
// Additionally, Parser::ParseType assumes bool..string is a contiguous range
|
||||
// of type tokens.
|
||||
// clang-format off
|
||||
#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
|
||||
TD(NONE, "", uint8_t, byte, byte, byte, uint8) \
|
||||
TD(UTYPE, "", uint8_t, byte, byte, byte, uint8) /* begin scalar/int */ \
|
||||
TD(BOOL, "bool", uint8_t, boolean,byte, bool, bool) \
|
||||
TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8) \
|
||||
TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8) \
|
||||
TD(SHORT, "short", int16_t, short, int16, short, int16) \
|
||||
TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16) \
|
||||
TD(INT, "int", int32_t, int, int32, int, int32) \
|
||||
TD(UINT, "uint", uint32_t, int, uint32, uint, uint32) \
|
||||
TD(LONG, "long", int64_t, long, int64, long, int64) \
|
||||
TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64) /* end int */ \
|
||||
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, 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)
|
||||
|
||||
// The fields are:
|
||||
// - enum
|
||||
// - FlatBuffers schema type.
|
||||
// - C++ type.
|
||||
// - Java type.
|
||||
// - Go type.
|
||||
// - C# / .Net type.
|
||||
// - Python type.
|
||||
|
||||
// using these macros, we can now write code dealing with types just once, e.g.
|
||||
|
||||
/*
|
||||
switch (type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
// do something specific to CTYPE here
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
}
|
||||
*/
|
||||
|
||||
#define FLATBUFFERS_GEN_TYPES(TD) \
|
||||
FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(TD)
|
||||
|
||||
// Create an enum for all the types above.
|
||||
#ifdef __GNUC__
|
||||
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
|
||||
#endif
|
||||
enum BaseType {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
BASE_TYPE_ ## ENUM,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
|
||||
"define largest_scalar_t as " #CTYPE);
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
|
||||
inline bool IsScalar (BaseType t) { return t >= BASE_TYPE_UTYPE &&
|
||||
t <= BASE_TYPE_DOUBLE; }
|
||||
inline bool IsInteger(BaseType t) { return t >= BASE_TYPE_UTYPE &&
|
||||
t <= BASE_TYPE_ULONG; }
|
||||
inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT ||
|
||||
t == BASE_TYPE_DOUBLE; }
|
||||
inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG ||
|
||||
t == BASE_TYPE_ULONG; }
|
||||
inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; }
|
||||
// clang-format on
|
||||
|
||||
extern const char *const kTypeNames[];
|
||||
extern const char kTypeSizes[];
|
||||
|
||||
inline size_t SizeOf(BaseType t) { return kTypeSizes[t]; }
|
||||
|
||||
struct StructDef;
|
||||
struct EnumDef;
|
||||
class Parser;
|
||||
|
||||
// Represents any type in the IDL, which is a combination of the BaseType
|
||||
// and additional information for vectors/structs_.
|
||||
struct Type {
|
||||
explicit Type(BaseType _base_type = BASE_TYPE_NONE, StructDef *_sd = nullptr,
|
||||
EnumDef *_ed = nullptr)
|
||||
: base_type(_base_type),
|
||||
element(BASE_TYPE_NONE),
|
||||
struct_def(_sd),
|
||||
enum_def(_ed) {}
|
||||
|
||||
bool operator==(const Type &o) {
|
||||
return base_type == o.base_type && element == o.element &&
|
||||
struct_def == o.struct_def && enum_def == o.enum_def;
|
||||
}
|
||||
|
||||
Type VectorType() const { return Type(element, struct_def, enum_def); }
|
||||
|
||||
Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
BaseType base_type;
|
||||
BaseType element; // only set if t == BASE_TYPE_VECTOR
|
||||
StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
|
||||
EnumDef *enum_def; // set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE,
|
||||
// or for an integral type derived from an enum.
|
||||
};
|
||||
|
||||
// Represents a parsed scalar value, it's type, and field offset.
|
||||
struct Value {
|
||||
Value()
|
||||
: constant("0"),
|
||||
offset(static_cast<voffset_t>(~(static_cast<voffset_t>(0U)))) {}
|
||||
Type type;
|
||||
std::string constant;
|
||||
voffset_t offset;
|
||||
};
|
||||
|
||||
// Helper class that retains the original order of a set of identifiers and
|
||||
// also provides quick lookup.
|
||||
template<typename T> class SymbolTable {
|
||||
public:
|
||||
~SymbolTable() {
|
||||
for (auto it = vec.begin(); it != vec.end(); ++it) { delete *it; }
|
||||
}
|
||||
|
||||
bool Add(const std::string &name, T *e) {
|
||||
vector_emplace_back(&vec, e);
|
||||
auto it = dict.find(name);
|
||||
if (it != dict.end()) return true;
|
||||
dict[name] = e;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Move(const std::string &oldname, const std::string &newname) {
|
||||
auto it = dict.find(oldname);
|
||||
if (it != dict.end()) {
|
||||
auto obj = it->second;
|
||||
dict.erase(it);
|
||||
dict[newname] = obj;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
T *Lookup(const std::string &name) const {
|
||||
auto it = dict.find(name);
|
||||
return it == dict.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
public:
|
||||
std::map<std::string, T *> dict; // quick lookup
|
||||
std::vector<T *> vec; // Used to iterate in order of insertion
|
||||
};
|
||||
|
||||
// A name space, as set in the schema.
|
||||
struct Namespace {
|
||||
Namespace() : from_table(0) {}
|
||||
|
||||
// Given a (potentally unqualified) name, return the "fully qualified" name
|
||||
// which has a full namespaced descriptor.
|
||||
// With max_components you can request less than the number of components
|
||||
// the current namespace has.
|
||||
std::string GetFullyQualifiedName(const std::string &name,
|
||||
size_t max_components = 1000) const;
|
||||
|
||||
std::vector<std::string> components;
|
||||
size_t from_table; // Part of the namespace corresponds to a message/table.
|
||||
};
|
||||
|
||||
// Base class for all definition types (fields, structs_, enums_).
|
||||
struct Definition {
|
||||
Definition()
|
||||
: generated(false),
|
||||
defined_namespace(nullptr),
|
||||
serialized_location(0),
|
||||
index(-1),
|
||||
refcount(1) {}
|
||||
|
||||
flatbuffers::Offset<
|
||||
flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
|
||||
SerializeAttributes(FlatBufferBuilder *builder, const Parser &parser) const;
|
||||
|
||||
std::string name;
|
||||
std::string file;
|
||||
std::vector<std::string> doc_comment;
|
||||
SymbolTable<Value> attributes;
|
||||
bool generated; // did we already output code for this definition?
|
||||
Namespace *defined_namespace; // Where it was defined.
|
||||
|
||||
// For use with Serialize()
|
||||
uoffset_t serialized_location;
|
||||
int index; // Inside the vector it is stored.
|
||||
int refcount;
|
||||
};
|
||||
|
||||
struct FieldDef : public Definition {
|
||||
FieldDef()
|
||||
: deprecated(false),
|
||||
required(false),
|
||||
key(false),
|
||||
native_inline(false),
|
||||
flexbuffer(false),
|
||||
nested_flatbuffer(NULL),
|
||||
padding(0) {}
|
||||
|
||||
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
|
||||
const Parser &parser) const;
|
||||
|
||||
Value value;
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be.
|
||||
// written in new data nor accessed in new code.
|
||||
bool required; // Field must always be present.
|
||||
bool key; // Field functions as a key for creating sorted vectors.
|
||||
bool native_inline; // Field will be defined inline (instead of as a pointer)
|
||||
// for native tables if field is a struct.
|
||||
bool flexbuffer; // This field contains FlexBuffer data.
|
||||
StructDef *nested_flatbuffer; // This field contains nested FlatBuffer data.
|
||||
size_t padding; // Bytes to always pad after this field.
|
||||
};
|
||||
|
||||
struct StructDef : public Definition {
|
||||
StructDef()
|
||||
: fixed(false),
|
||||
predecl(true),
|
||||
sortbysize(true),
|
||||
has_key(false),
|
||||
minalign(1),
|
||||
bytesize(0) {}
|
||||
|
||||
void PadLastField(size_t min_align) {
|
||||
auto padding = PaddingBytes(bytesize, min_align);
|
||||
bytesize += padding;
|
||||
if (fields.vec.size()) fields.vec.back()->padding = padding;
|
||||
}
|
||||
|
||||
Offset<reflection::Object> Serialize(FlatBufferBuilder *builder,
|
||||
const Parser &parser) const;
|
||||
|
||||
SymbolTable<FieldDef> fields;
|
||||
|
||||
bool fixed; // If it's struct, not a table.
|
||||
bool predecl; // If it's used before it was defined.
|
||||
bool sortbysize; // Whether fields come in the declaration or size order.
|
||||
bool has_key; // It has a key field.
|
||||
size_t minalign; // What the whole object needs to be aligned to.
|
||||
size_t bytesize; // Size if fixed.
|
||||
|
||||
flatbuffers::unique_ptr<std::string> original_location;
|
||||
};
|
||||
|
||||
inline bool IsStruct(const Type &type) {
|
||||
return type.base_type == BASE_TYPE_STRUCT && type.struct_def->fixed;
|
||||
}
|
||||
|
||||
inline size_t InlineSize(const Type &type) {
|
||||
return IsStruct(type) ? type.struct_def->bytesize : SizeOf(type.base_type);
|
||||
}
|
||||
|
||||
inline size_t InlineAlignment(const Type &type) {
|
||||
return IsStruct(type) ? type.struct_def->minalign : SizeOf(type.base_type);
|
||||
}
|
||||
|
||||
struct EnumVal {
|
||||
EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {}
|
||||
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
std::string name;
|
||||
std::vector<std::string> doc_comment;
|
||||
int64_t value;
|
||||
Type union_type;
|
||||
};
|
||||
|
||||
struct EnumDef : public Definition {
|
||||
EnumDef() : is_union(false), uses_type_aliases(false) {}
|
||||
|
||||
EnumVal *ReverseLookup(int64_t enum_idx, bool skip_union_default = true) {
|
||||
for (auto it = vals.vec.begin() +
|
||||
static_cast<int>(is_union && skip_union_default);
|
||||
it != vals.vec.end(); ++it) {
|
||||
if ((*it)->value == enum_idx) { return *it; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder,
|
||||
const Parser &parser) const;
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
bool uses_type_aliases;
|
||||
Type underlying_type;
|
||||
};
|
||||
|
||||
inline bool EqualByName(const Type &a, const Type &b) {
|
||||
return a.base_type == b.base_type && a.element == b.element &&
|
||||
(a.struct_def == b.struct_def ||
|
||||
a.struct_def->name == b.struct_def->name) &&
|
||||
(a.enum_def == b.enum_def || a.enum_def->name == b.enum_def->name);
|
||||
}
|
||||
|
||||
struct RPCCall {
|
||||
std::string name;
|
||||
SymbolTable<Value> attributes;
|
||||
StructDef *request, *response;
|
||||
std::vector<std::string> rpc_comment;
|
||||
};
|
||||
|
||||
struct ServiceDef : public Definition {
|
||||
SymbolTable<RPCCall> calls;
|
||||
};
|
||||
|
||||
// Container of options that may apply to any of the source/text generators.
|
||||
struct IDLOptions {
|
||||
bool strict_json;
|
||||
bool skip_js_exports;
|
||||
bool use_goog_js_export_format;
|
||||
bool output_default_scalars_in_json;
|
||||
int indent_step;
|
||||
bool output_enum_identifiers;
|
||||
bool prefixed_enums;
|
||||
bool scoped_enums;
|
||||
bool include_dependence_headers;
|
||||
bool mutable_buffer;
|
||||
bool one_file;
|
||||
bool proto_mode;
|
||||
bool proto_oneof_union;
|
||||
bool generate_all;
|
||||
bool skip_unexpected_fields_in_json;
|
||||
bool generate_name_strings;
|
||||
bool generate_object_based_api;
|
||||
std::string cpp_object_api_pointer_type;
|
||||
std::string cpp_object_api_string_type;
|
||||
bool gen_nullable;
|
||||
std::string object_prefix;
|
||||
std::string object_suffix;
|
||||
bool union_value_namespacing;
|
||||
bool allow_non_utf8;
|
||||
std::string include_prefix;
|
||||
bool keep_include_path;
|
||||
bool binary_schema_comments;
|
||||
bool skip_flatbuffers_import;
|
||||
std::string go_import;
|
||||
std::string go_namespace;
|
||||
bool reexport_ts_modules;
|
||||
bool protobuf_ascii_alike;
|
||||
bool size_prefixed;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language {
|
||||
kJava = 1 << 0,
|
||||
kCSharp = 1 << 1,
|
||||
kGo = 1 << 2,
|
||||
kCpp = 1 << 3,
|
||||
kJs = 1 << 4,
|
||||
kPython = 1 << 5,
|
||||
kPhp = 1 << 6,
|
||||
kJson = 1 << 7,
|
||||
kBinary = 1 << 8,
|
||||
kTs = 1 << 9,
|
||||
kJsonSchema = 1 << 10,
|
||||
kMAX
|
||||
};
|
||||
|
||||
Language lang;
|
||||
|
||||
enum MiniReflect { kNone, kTypes, kTypesAndNames };
|
||||
|
||||
MiniReflect mini_reflect;
|
||||
|
||||
// The corresponding language bit will be set if a language is included
|
||||
// for code generation.
|
||||
unsigned long lang_to_generate;
|
||||
|
||||
IDLOptions()
|
||||
: strict_json(false),
|
||||
skip_js_exports(false),
|
||||
use_goog_js_export_format(false),
|
||||
output_default_scalars_in_json(false),
|
||||
indent_step(2),
|
||||
output_enum_identifiers(true),
|
||||
prefixed_enums(true),
|
||||
scoped_enums(false),
|
||||
include_dependence_headers(true),
|
||||
mutable_buffer(false),
|
||||
one_file(false),
|
||||
proto_mode(false),
|
||||
proto_oneof_union(false),
|
||||
generate_all(false),
|
||||
skip_unexpected_fields_in_json(false),
|
||||
generate_name_strings(false),
|
||||
generate_object_based_api(false),
|
||||
cpp_object_api_pointer_type("std::unique_ptr"),
|
||||
gen_nullable(false),
|
||||
object_suffix("T"),
|
||||
union_value_namespacing(true),
|
||||
allow_non_utf8(false),
|
||||
keep_include_path(false),
|
||||
binary_schema_comments(false),
|
||||
skip_flatbuffers_import(false),
|
||||
reexport_ts_modules(true),
|
||||
protobuf_ascii_alike(false),
|
||||
size_prefixed(false),
|
||||
lang(IDLOptions::kJava),
|
||||
mini_reflect(IDLOptions::kNone),
|
||||
lang_to_generate(0) {}
|
||||
};
|
||||
|
||||
// This encapsulates where the parser is in the current source file.
|
||||
struct ParserState {
|
||||
ParserState() : cursor_(nullptr), line_(1), token_(-1) {}
|
||||
|
||||
protected:
|
||||
const char *cursor_;
|
||||
int line_; // the current line being parsed
|
||||
int token_;
|
||||
|
||||
std::string attribute_;
|
||||
std::vector<std::string> doc_comment_;
|
||||
};
|
||||
|
||||
// A way to make error propagation less error prone by requiring values to be
|
||||
// checked.
|
||||
// Once you create a value of this type you must either:
|
||||
// - Call Check() on it.
|
||||
// - Copy or assign it to another value.
|
||||
// Failure to do so leads to an assert.
|
||||
// This guarantees that this as return value cannot be ignored.
|
||||
class CheckedError {
|
||||
public:
|
||||
explicit CheckedError(bool error)
|
||||
: is_error_(error), has_been_checked_(false) {}
|
||||
|
||||
CheckedError &operator=(const CheckedError &other) {
|
||||
is_error_ = other.is_error_;
|
||||
has_been_checked_ = false;
|
||||
other.has_been_checked_ = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CheckedError(const CheckedError &other) {
|
||||
*this = other; // Use assignment operator.
|
||||
}
|
||||
|
||||
~CheckedError() { assert(has_been_checked_); }
|
||||
|
||||
bool Check() {
|
||||
has_been_checked_ = true;
|
||||
return is_error_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_error_;
|
||||
mutable bool has_been_checked_;
|
||||
};
|
||||
|
||||
// Additionally, in GCC we can get these errors statically, for additional
|
||||
// assurance:
|
||||
// clang-format off
|
||||
#ifdef __GNUC__
|
||||
#define FLATBUFFERS_CHECKED_ERROR CheckedError \
|
||||
__attribute__((warn_unused_result))
|
||||
#else
|
||||
#define FLATBUFFERS_CHECKED_ERROR CheckedError
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
class Parser : public ParserState {
|
||||
public:
|
||||
explicit Parser(const IDLOptions &options = IDLOptions())
|
||||
: current_namespace_(nullptr),
|
||||
empty_namespace_(nullptr),
|
||||
root_struct_def_(nullptr),
|
||||
opts(options),
|
||||
uses_flexbuffers_(false),
|
||||
source_(nullptr),
|
||||
anonymous_counter(0) {
|
||||
// Start out with the empty namespace being current.
|
||||
empty_namespace_ = new Namespace();
|
||||
namespaces_.push_back(empty_namespace_);
|
||||
current_namespace_ = empty_namespace_;
|
||||
known_attributes_["deprecated"] = true;
|
||||
known_attributes_["required"] = true;
|
||||
known_attributes_["key"] = true;
|
||||
known_attributes_["hash"] = true;
|
||||
known_attributes_["id"] = true;
|
||||
known_attributes_["force_align"] = true;
|
||||
known_attributes_["bit_flags"] = true;
|
||||
known_attributes_["original_order"] = true;
|
||||
known_attributes_["nested_flatbuffer"] = true;
|
||||
known_attributes_["csharp_partial"] = true;
|
||||
known_attributes_["streaming"] = true;
|
||||
known_attributes_["idempotent"] = true;
|
||||
known_attributes_["cpp_type"] = true;
|
||||
known_attributes_["cpp_ptr_type"] = true;
|
||||
known_attributes_["cpp_ptr_type_get"] = true;
|
||||
known_attributes_["cpp_str_type"] = true;
|
||||
known_attributes_["native_inline"] = true;
|
||||
known_attributes_["native_custom_alloc"] = true;
|
||||
known_attributes_["native_type"] = true;
|
||||
known_attributes_["native_default"] = true;
|
||||
known_attributes_["flexbuffer"] = true;
|
||||
}
|
||||
|
||||
~Parser() {
|
||||
for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the string containing either schema or JSON data, which will
|
||||
// populate the SymbolTable's or the FlatBufferBuilder above.
|
||||
// include_paths is used to resolve any include statements, and typically
|
||||
// should at least include the project path (where you loaded source_ from).
|
||||
// include_paths must be nullptr terminated if specified.
|
||||
// If include_paths is nullptr, it will attempt to load from the current
|
||||
// directory.
|
||||
// If the source was loaded from a file and isn't an include file,
|
||||
// supply its name in source_filename.
|
||||
// All paths specified in this call must be in posix format, if you accept
|
||||
// paths from user input, please call PosixPath on them first.
|
||||
bool Parse(const char *_source, const char **include_paths = nullptr,
|
||||
const char *source_filename = nullptr);
|
||||
|
||||
// Set the root type. May override the one set in the schema.
|
||||
bool SetRootType(const char *name);
|
||||
|
||||
// Mark all definitions as already having code generated.
|
||||
void MarkGenerated();
|
||||
|
||||
// Get the files recursively included by the given file. The returned
|
||||
// container will have at least the given file.
|
||||
std::set<std::string> GetIncludedFilesRecursive(
|
||||
const std::string &file_name) const;
|
||||
|
||||
// Fills builder_ with a binary version of the schema parsed.
|
||||
// See reflection/reflection.fbs
|
||||
void Serialize();
|
||||
|
||||
// Checks that the schema represented by this parser is a safe evolution
|
||||
// of the schema provided. Returns non-empty error on any problems.
|
||||
std::string ConformTo(const Parser &base);
|
||||
|
||||
// Similar to Parse(), but now only accepts JSON to be parsed into a
|
||||
// FlexBuffer.
|
||||
bool ParseFlexBuffer(const char *source, const char *source_filename,
|
||||
flexbuffers::Builder *builder);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
|
||||
|
||||
StructDef *LookupStruct(const std::string &id) const;
|
||||
|
||||
private:
|
||||
void Message(const std::string &msg);
|
||||
void Warning(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR Next();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
||||
bool Is(int t) const;
|
||||
bool IsIdent(const char *id) const;
|
||||
FLATBUFFERS_CHECKED_ERROR Expect(int t);
|
||||
std::string TokenToStringId(int t) const;
|
||||
EnumDef *LookupEnum(const std::string &id);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseNamespacing(std::string *id,
|
||||
std::string *last);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTypeIdent(Type &type);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseType(Type &type);
|
||||
FLATBUFFERS_CHECKED_ERROR AddField(StructDef &struct_def,
|
||||
const std::string &name, const Type &type,
|
||||
FieldDef **dest);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseComma();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
|
||||
size_t parent_fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
// clang-format off
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
typedef CheckedError (*ParseTableDelimitersBody)(
|
||||
const std::string &name, size_t &fieldn, const StructDef *struct_def,
|
||||
void *state);
|
||||
#else
|
||||
typedef std::function<CheckedError(const std::string&, size_t&,
|
||||
const StructDef*, void*)>
|
||||
ParseTableDelimitersBody;
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
ParseTableDelimitersBody body,
|
||||
void *state);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
|
||||
std::string *value, uoffset_t *ovalue);
|
||||
void SerializeStruct(const StructDef &struct_def, const Value &val);
|
||||
// clang-format off
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
typedef CheckedError (*ParseVectorDelimitersBody)(size_t &count,
|
||||
void *state);
|
||||
#else
|
||||
typedef std::function<CheckedError(size_t&, void*)>
|
||||
ParseVectorDelimitersBody;
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// clang-format on
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(
|
||||
size_t &count, ParseVectorDelimitersBody body, void *state);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
|
||||
size_t fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
|
||||
FLATBUFFERS_CHECKED_ERROR TryTypedValue(const std::string *name, int dtoken, bool check, Value &e,
|
||||
BaseType req, bool *destmatch);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
|
||||
FLATBUFFERS_CHECKED_ERROR TokenError();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseSingleValue(const std::string *name, Value &e);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
|
||||
StructDef *LookupCreateStruct(const std::string &name,
|
||||
bool create_if_new = true,
|
||||
bool definition = false);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseNamespace();
|
||||
FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name,
|
||||
StructDef **dest);
|
||||
FLATBUFFERS_CHECKED_ERROR StartEnum(const std::string &name,
|
||||
bool is_union,
|
||||
EnumDef **dest);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseDecl();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseService();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def,
|
||||
bool isextend, bool inside_oneof);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoOption();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoKey();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoDecl();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
|
||||
FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
|
||||
FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename,
|
||||
const char *include_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
|
||||
StructDef *struct_def,
|
||||
const char *suffix,
|
||||
BaseType baseType);
|
||||
|
||||
bool SupportsVectorOfUnions() const;
|
||||
Namespace *UniqueNamespace(Namespace *ns);
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
SymbolTable<StructDef> structs_;
|
||||
SymbolTable<EnumDef> enums_;
|
||||
SymbolTable<ServiceDef> services_;
|
||||
std::vector<Namespace *> namespaces_;
|
||||
Namespace *current_namespace_;
|
||||
Namespace *empty_namespace_;
|
||||
std::string error_; // User readable error_ if Parse() == false
|
||||
|
||||
FlatBufferBuilder builder_; // any data contained in the file
|
||||
StructDef *root_struct_def_;
|
||||
std::string file_identifier_;
|
||||
std::string file_extension_;
|
||||
|
||||
std::map<std::string, std::string> included_files_;
|
||||
std::map<std::string, std::set<std::string>> files_included_per_file_;
|
||||
std::vector<std::string> native_included_files_;
|
||||
|
||||
std::map<std::string, bool> known_attributes_;
|
||||
|
||||
IDLOptions opts;
|
||||
bool uses_flexbuffers_;
|
||||
|
||||
private:
|
||||
const char *source_;
|
||||
|
||||
std::string file_being_parsed_;
|
||||
|
||||
std::vector<std::pair<Value, FieldDef *>> field_stack_;
|
||||
|
||||
int anonymous_counter;
|
||||
};
|
||||
|
||||
// Utility functions for multiple generators:
|
||||
|
||||
extern std::string MakeCamel(const std::string &in, bool first = true);
|
||||
|
||||
// Generate text (JSON) from a given FlatBuffer, and a given Parser
|
||||
// object that has been populated with the corresponding schema.
|
||||
// If ident_step is 0, no indentation will be generated. Additionally,
|
||||
// if it is less than 0, no linefeeds will be generated either.
|
||||
// See idl_gen_text.cpp.
|
||||
// strict_json adds "quotes" around field names if true.
|
||||
// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8
|
||||
// byte arrays in String values), returns false.
|
||||
extern bool GenerateText(const Parser &parser,
|
||||
const void *flatbuffer,
|
||||
std::string *text);
|
||||
extern bool GenerateTextFile(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate binary files from a given FlatBuffer, and a given Parser
|
||||
// object that has been populated with the corresponding schema.
|
||||
// See idl_gen_general.cpp.
|
||||
extern bool GenerateBinary(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a C++ header from the definitions in the Parser object.
|
||||
// See idl_gen_cpp.
|
||||
extern bool GenerateCPP(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
|
||||
// See idl_gen_js.
|
||||
extern bool GenerateJS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Go files from the definitions in the Parser object.
|
||||
// See idl_gen_go.cpp.
|
||||
extern bool GenerateGo(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Php code from the definitions in the Parser object.
|
||||
// See idl_gen_php.
|
||||
extern bool GeneratePhp(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Python files from the definitions in the Parser object.
|
||||
// See idl_gen_python.cpp.
|
||||
extern bool GeneratePython(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Json schema file
|
||||
// See idl_gen_json_schema.cpp.
|
||||
extern bool GenerateJsonSchema(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate Java/C#/.. files from the definitions in the Parser object.
|
||||
// See idl_gen_general.cpp.
|
||||
extern bool GenerateGeneral(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a schema file from the internal representation, useful after
|
||||
// parsing a .proto schema.
|
||||
extern std::string GenerateFBS(const Parser &parser,
|
||||
const std::string &file_name);
|
||||
extern bool GenerateFBS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated JavaScript or TypeScript code.
|
||||
// See idl_gen_js.cpp.
|
||||
extern std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated C++ header.
|
||||
// See idl_gen_cpp.cpp.
|
||||
extern std::string CPPMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated Java/C#/... files.
|
||||
// See idl_gen_general.cpp.
|
||||
extern std::string GeneralMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated text (JSON) files.
|
||||
// See idl_gen_text.cpp.
|
||||
extern std::string TextMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_names);
|
||||
|
||||
// Generate a make rule for the generated binary files.
|
||||
// See idl_gen_general.cpp.
|
||||
extern std::string BinaryMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate GRPC Cpp interfaces.
|
||||
// See idl_gen_grpc.cpp.
|
||||
bool GenerateCppGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate GRPC Go interfaces.
|
||||
// See idl_gen_grpc.cpp.
|
||||
bool GenerateGoGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate GRPC Java classes.
|
||||
// See idl_gen_grpc.cpp
|
||||
bool GenerateJavaGRPC(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_IDL_H_
|
||||
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_MINIREFLECT_H_
|
||||
#define FLATBUFFERS_MINIREFLECT_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Utilities that can be used with the "mini reflection" tables present
|
||||
// in generated code with --reflect-types (only types) or --reflect-names
|
||||
// (also names).
|
||||
// This allows basic reflection functionality such as pretty-printing
|
||||
// that does not require the use of the schema parser or loading of binary
|
||||
// schema files at runtime (reflection.h).
|
||||
|
||||
// For any of the functions below that take `const TypeTable *`, you pass
|
||||
// `FooTypeTable()` if the type of the root is `Foo`.
|
||||
|
||||
// First, a generic iterator that can be used by multiple algorithms.
|
||||
|
||||
struct IterationVisitor {
|
||||
// These mark the scope of a table or struct.
|
||||
virtual void StartSequence() {}
|
||||
virtual void EndSequence() {}
|
||||
// Called for each field regardless of wether it is present or not.
|
||||
// If not present, val == nullptr. set_idx is the index of all set fields.
|
||||
virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
|
||||
ElementaryType /*type*/, bool /*is_vector*/,
|
||||
const TypeTable * /*type_table*/, const char * /*name*/,
|
||||
const uint8_t * /*val*/) {}
|
||||
// Called for a value that is actually present, after a field, or as part
|
||||
// of a vector.
|
||||
virtual void UType(uint8_t, const char *) {}
|
||||
virtual void Bool(bool) {}
|
||||
virtual void Char(int8_t, const char *) {}
|
||||
virtual void UChar(uint8_t, const char *) {}
|
||||
virtual void Short(int16_t, const char *) {}
|
||||
virtual void UShort(uint16_t, const char *) {}
|
||||
virtual void Int(int32_t, const char *) {}
|
||||
virtual void UInt(uint32_t, const char *) {}
|
||||
virtual void Long(int64_t) {}
|
||||
virtual void ULong(uint64_t) {}
|
||||
virtual void Float(float) {}
|
||||
virtual void Double(double) {}
|
||||
virtual void String(const String *) {}
|
||||
virtual void Unknown(const uint8_t *) {} // From a future version.
|
||||
// These mark the scope of a vector.
|
||||
virtual void StartVector() {}
|
||||
virtual void EndVector() {}
|
||||
virtual void Element(size_t /*i*/, ElementaryType /*type*/,
|
||||
const TypeTable * /*type_table*/,
|
||||
const uint8_t * /*val*/) {}
|
||||
virtual ~IterationVisitor() {}
|
||||
};
|
||||
|
||||
inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
|
||||
switch (type) {
|
||||
case ET_UTYPE:
|
||||
case ET_BOOL:
|
||||
case ET_CHAR:
|
||||
case ET_UCHAR: return 1;
|
||||
case ET_SHORT:
|
||||
case ET_USHORT: return 2;
|
||||
case ET_INT:
|
||||
case ET_UINT:
|
||||
case ET_FLOAT:
|
||||
case ET_STRING: return 4;
|
||||
case ET_LONG:
|
||||
case ET_ULONG:
|
||||
case ET_DOUBLE: return 8;
|
||||
case ET_SEQUENCE:
|
||||
switch (type_table->st) {
|
||||
case ST_TABLE:
|
||||
case ST_UNION: return 4;
|
||||
case ST_STRUCT: return type_table->values[type_table->num_elems];
|
||||
default: assert(false); return 1;
|
||||
}
|
||||
default: assert(false); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t LookupEnum(int32_t enum_val, const int32_t *values,
|
||||
size_t num_values) {
|
||||
if (!values) return enum_val;
|
||||
for (size_t i = 0; i < num_values; i++) {
|
||||
if (enum_val == values[i]) return static_cast<int32_t>(i);
|
||||
}
|
||||
return -1; // Unknown enum value.
|
||||
}
|
||||
|
||||
template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
|
||||
if (!type_table || !type_table->names) return nullptr;
|
||||
auto i = LookupEnum(static_cast<int32_t>(tval), type_table->values,
|
||||
type_table->num_elems);
|
||||
if (i >= 0 && i < static_cast<int32_t>(type_table->num_elems)) {
|
||||
return type_table->names[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IterateObject(const uint8_t *obj, const TypeTable *type_table,
|
||||
IterationVisitor *visitor);
|
||||
|
||||
inline void IterateValue(ElementaryType type, const uint8_t *val,
|
||||
const TypeTable *type_table, const uint8_t *prev_val,
|
||||
soffset_t vector_index, IterationVisitor *visitor) {
|
||||
switch (type) {
|
||||
case ET_UTYPE: {
|
||||
auto tval = *reinterpret_cast<const uint8_t *>(val);
|
||||
visitor->UType(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_BOOL: {
|
||||
visitor->Bool(*reinterpret_cast<const uint8_t *>(val) != 0);
|
||||
break;
|
||||
}
|
||||
case ET_CHAR: {
|
||||
auto tval = *reinterpret_cast<const int8_t *>(val);
|
||||
visitor->Char(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_UCHAR: {
|
||||
auto tval = *reinterpret_cast<const uint8_t *>(val);
|
||||
visitor->UChar(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_SHORT: {
|
||||
auto tval = *reinterpret_cast<const int16_t *>(val);
|
||||
visitor->Short(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_USHORT: {
|
||||
auto tval = *reinterpret_cast<const uint16_t *>(val);
|
||||
visitor->UShort(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_INT: {
|
||||
auto tval = *reinterpret_cast<const int32_t *>(val);
|
||||
visitor->Int(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_UINT: {
|
||||
auto tval = *reinterpret_cast<const uint32_t *>(val);
|
||||
visitor->UInt(tval, EnumName(tval, type_table));
|
||||
break;
|
||||
}
|
||||
case ET_LONG: {
|
||||
visitor->Long(*reinterpret_cast<const int64_t *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_ULONG: {
|
||||
visitor->ULong(*reinterpret_cast<const uint64_t *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_FLOAT: {
|
||||
visitor->Float(*reinterpret_cast<const float *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_DOUBLE: {
|
||||
visitor->Double(*reinterpret_cast<const double *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_STRING: {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
visitor->String(reinterpret_cast<const String *>(val));
|
||||
break;
|
||||
}
|
||||
case ET_SEQUENCE: {
|
||||
switch (type_table->st) {
|
||||
case ST_TABLE:
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
IterateObject(val, type_table, visitor);
|
||||
break;
|
||||
case ST_STRUCT: IterateObject(val, type_table, visitor); break;
|
||||
case ST_UNION: {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
assert(prev_val);
|
||||
auto union_type = *prev_val; // Always a uint8_t.
|
||||
if (vector_index >= 0) {
|
||||
auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
|
||||
union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
|
||||
}
|
||||
auto type_code_idx =
|
||||
LookupEnum(union_type, type_table->values, type_table->num_elems);
|
||||
if (type_code_idx >= 0 &&
|
||||
type_code_idx < static_cast<int32_t>(type_table->num_elems)) {
|
||||
auto type_code = type_table->type_codes[type_code_idx];
|
||||
switch (type_code.base_type) {
|
||||
case ET_SEQUENCE: {
|
||||
auto ref = type_table->type_refs[type_code.sequence_ref]();
|
||||
IterateObject(val, ref, visitor);
|
||||
break;
|
||||
}
|
||||
case ET_STRING:
|
||||
visitor->String(reinterpret_cast<const String *>(val));
|
||||
break;
|
||||
default: visitor->Unknown(val);
|
||||
}
|
||||
} else {
|
||||
visitor->Unknown(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ST_ENUM: assert(false); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
visitor->Unknown(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void IterateObject(const uint8_t *obj, const TypeTable *type_table,
|
||||
IterationVisitor *visitor) {
|
||||
visitor->StartSequence();
|
||||
const uint8_t *prev_val = nullptr;
|
||||
size_t set_idx = 0;
|
||||
for (size_t i = 0; i < type_table->num_elems; i++) {
|
||||
auto type_code = type_table->type_codes[i];
|
||||
auto type = static_cast<ElementaryType>(type_code.base_type);
|
||||
auto is_vector = type_code.is_vector != 0;
|
||||
auto ref_idx = type_code.sequence_ref;
|
||||
const TypeTable *ref = nullptr;
|
||||
if (ref_idx >= 0) { ref = type_table->type_refs[ref_idx](); }
|
||||
auto name = type_table->names ? type_table->names[i] : nullptr;
|
||||
const uint8_t *val = nullptr;
|
||||
if (type_table->st == ST_TABLE) {
|
||||
val = reinterpret_cast<const Table *>(obj)->GetAddressOf(
|
||||
FieldIndexToOffset(static_cast<voffset_t>(i)));
|
||||
} else {
|
||||
val = obj + type_table->values[i];
|
||||
}
|
||||
visitor->Field(i, set_idx, type, is_vector, ref, name, val);
|
||||
if (val) {
|
||||
set_idx++;
|
||||
if (is_vector) {
|
||||
val += ReadScalar<uoffset_t>(val);
|
||||
auto vec = reinterpret_cast<const Vector<uint8_t> *>(val);
|
||||
visitor->StartVector();
|
||||
auto elem_ptr = vec->Data();
|
||||
for (size_t j = 0; j < vec->size(); j++) {
|
||||
visitor->Element(j, type, ref, elem_ptr);
|
||||
IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
|
||||
visitor);
|
||||
elem_ptr += InlineSize(type, ref);
|
||||
}
|
||||
visitor->EndVector();
|
||||
} else {
|
||||
IterateValue(type, val, ref, prev_val, -1, visitor);
|
||||
}
|
||||
}
|
||||
prev_val = val;
|
||||
}
|
||||
visitor->EndSequence();
|
||||
}
|
||||
|
||||
inline void IterateFlatBuffer(const uint8_t *buffer,
|
||||
const TypeTable *type_table,
|
||||
IterationVisitor *callback) {
|
||||
IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
|
||||
}
|
||||
|
||||
// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
|
||||
// the output generated by idl_gen_text.cpp.
|
||||
|
||||
struct ToStringVisitor : public IterationVisitor {
|
||||
std::string s;
|
||||
void StartSequence() { s += "{ "; }
|
||||
void EndSequence() { s += " }"; }
|
||||
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
|
||||
bool /*is_vector*/, const TypeTable * /*type_table*/,
|
||||
const char *name, const uint8_t *val) {
|
||||
if (!val) return;
|
||||
if (set_idx) s += ", ";
|
||||
if (name) {
|
||||
s += name;
|
||||
s += ": ";
|
||||
}
|
||||
}
|
||||
template<typename T> void Named(T x, const char *name) {
|
||||
if (name)
|
||||
s += name;
|
||||
else
|
||||
s += NumToString(x);
|
||||
}
|
||||
void UType(uint8_t x, const char *name) { Named(x, name); }
|
||||
void Bool(bool x) { s += x ? "true" : "false"; }
|
||||
void Char(int8_t x, const char *name) { Named(x, name); }
|
||||
void UChar(uint8_t x, const char *name) { Named(x, name); }
|
||||
void Short(int16_t x, const char *name) { Named(x, name); }
|
||||
void UShort(uint16_t x, const char *name) { Named(x, name); }
|
||||
void Int(int32_t x, const char *name) { Named(x, name); }
|
||||
void UInt(uint32_t x, const char *name) { Named(x, name); }
|
||||
void Long(int64_t x) { s += NumToString(x); }
|
||||
void ULong(uint64_t x) { s += NumToString(x); }
|
||||
void Float(float x) { s += NumToString(x); }
|
||||
void Double(double x) { s += NumToString(x); }
|
||||
void String(const struct String *str) {
|
||||
EscapeString(str->c_str(), str->size(), &s, true);
|
||||
}
|
||||
void Unknown(const uint8_t *) { s += "(?)"; }
|
||||
void StartVector() { s += "[ "; }
|
||||
void EndVector() { s += " ]"; }
|
||||
void Element(size_t i, ElementaryType /*type*/,
|
||||
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
|
||||
if (i) s += ", ";
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string FlatBufferToString(const uint8_t *buffer,
|
||||
const TypeTable *type_table) {
|
||||
ToStringVisitor tostring_visitor;
|
||||
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
|
||||
return tostring_visitor.s;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_MINIREFLECT_H_
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_REFLECTION_H_
|
||||
#define FLATBUFFERS_REFLECTION_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
|
||||
// previous version of flatc whenever this code needs to change.
|
||||
// See reflection/generate_code.sh
|
||||
#include "flatbuffers/reflection_generated.h"
|
||||
|
||||
// Helper functionality for reflection.
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// ------------------------- GETTERS -------------------------
|
||||
|
||||
inline bool IsScalar(reflection::BaseType t) {
|
||||
return t >= reflection::UType && t <= reflection::Double;
|
||||
}
|
||||
inline bool IsInteger(reflection::BaseType t) {
|
||||
return t >= reflection::UType && t <= reflection::ULong;
|
||||
}
|
||||
inline bool IsFloat(reflection::BaseType t) {
|
||||
return t == reflection::Float || t == reflection::Double;
|
||||
}
|
||||
inline bool IsLong(reflection::BaseType t) {
|
||||
return t == reflection::Long || t == reflection::ULong;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
|
||||
return GetRoot<Table>(flatbuf);
|
||||
}
|
||||
|
||||
// Get a field's default, if you know it's an integer, and its exact type.
|
||||
template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return static_cast<T>(field.default_integer());
|
||||
}
|
||||
|
||||
// Get a field's default, if you know it's floating point and its exact type.
|
||||
template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return static_cast<T>(field.default_real());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's an integer, and its exact type.
|
||||
template<typename T>
|
||||
T GetFieldI(const Table &table, const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table.GetField<T>(field.offset(),
|
||||
static_cast<T>(field.default_integer()));
|
||||
}
|
||||
|
||||
// Get a field, if you know it's floating point and its exact type.
|
||||
template<typename T>
|
||||
T GetFieldF(const Table &table, const reflection::Field &field) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table.GetField<T>(field.offset(),
|
||||
static_cast<T>(field.default_real()));
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a string.
|
||||
inline const String *GetFieldS(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::String);
|
||||
return table.GetPointer<const String *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a vector.
|
||||
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<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 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<Table *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a field, if you know it's a struct.
|
||||
inline const Struct *GetFieldStruct(const Table &table,
|
||||
const reflection::Field &field) {
|
||||
// TODO: This does NOT check if the field is a table or struct, but we'd need
|
||||
// access to the schema to check the is_struct flag.
|
||||
assert(field.type()->base_type() == reflection::Obj);
|
||||
return table.GetStruct<const Struct *>(field.offset());
|
||||
}
|
||||
|
||||
// Get a structure's field, if you know it's a struct.
|
||||
inline const Struct *GetFieldStruct(const Struct &structure,
|
||||
const reflection::Field &field) {
|
||||
assert(field.type()->base_type() == reflection::Obj);
|
||||
return structure.GetStruct<const Struct *>(field.offset());
|
||||
}
|
||||
|
||||
// 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) {
|
||||
auto field_ptr = table.GetAddressOf(field.offset());
|
||||
return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
|
||||
: field.default_integer();
|
||||
}
|
||||
|
||||
// Get any table field as a double, regardless of what type it is.
|
||||
inline double GetAnyFieldF(const Table &table, const reflection::Field &field) {
|
||||
auto field_ptr = table.GetAddressOf(field.offset());
|
||||
return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
|
||||
: field.default_real();
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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) {
|
||||
reflection::BaseType type = field.type()->base_type();
|
||||
if (!IsScalar(type)) { return false; }
|
||||
assert(sizeof(T) == GetTypeSize(type));
|
||||
T def;
|
||||
if (IsInteger(type)) {
|
||||
def = GetFieldDefaultI<T>(field);
|
||||
} else {
|
||||
assert(IsFloat(type));
|
||||
def = GetFieldDefaultF<T>(field);
|
||||
}
|
||||
return table->SetField(field.offset(), val, def);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
|
||||
SetAnyValueI(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set any table field as a double, regardless of what type it is.
|
||||
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
|
||||
double val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return val == GetFieldDefaultF<double>(field);
|
||||
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 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) {
|
||||
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(T *ptr, std::vector<U> &vec)
|
||||
: offset_(reinterpret_cast<uint8_t *>(ptr) -
|
||||
reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec))),
|
||||
vec_(vec) {}
|
||||
|
||||
T *operator*() const {
|
||||
return reinterpret_cast<T *>(
|
||||
reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec_)) + offset_);
|
||||
}
|
||||
T *operator->() const { return operator*(); }
|
||||
void operator=(const pointer_inside_vector &piv);
|
||||
|
||||
private:
|
||||
size_t offset_;
|
||||
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(T *ptr, std::vector<U> &vec) {
|
||||
return pointer_inside_vector<T, U>(ptr, vec);
|
||||
}
|
||||
|
||||
inline const char *UnionTypeFieldSuffix() { return "_type"; }
|
||||
|
||||
// Helper to figure out the actual table type a union refers to.
|
||||
inline const reflection::Object &GetUnionType(
|
||||
const reflection::Schema &schema, const reflection::Object &parent,
|
||||
const reflection::Field &unionfield, const Table &table) {
|
||||
auto enumdef = schema.enums()->Get(unionfield.type()->index());
|
||||
// TODO: this is clumsy and slow, but no other way to find it?
|
||||
auto type_field = parent.fields()->LookupByKey(
|
||||
(unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
|
||||
assert(type_field);
|
||||
auto union_type = GetFieldI<uint8_t>(table, *type_field);
|
||||
auto enumval = enumdef->values()->LookupByKey(union_type);
|
||||
return *enumval->object();
|
||||
}
|
||||
|
||||
// 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.
|
||||
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 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 = flatbuffers::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
|
||||
// above resizing functionality has introduced garbage in a buffer you want
|
||||
// to remove.
|
||||
// Note: this does not deal with DAGs correctly. If the table passed forms a
|
||||
// DAG, the copy will be a tree instead (with duplicates). Strings can be
|
||||
// shared however, by passing true for use_string_pooling.
|
||||
|
||||
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &objectdef,
|
||||
const Table &table,
|
||||
bool use_string_pooling = false);
|
||||
|
||||
// Verifies the provided flatbuffer using reflection.
|
||||
// root should point to the root type for this flatbuffer.
|
||||
// buf should point to the start of flatbuffer data.
|
||||
// length specifies the size of the flatbuffer data.
|
||||
bool Verify(const reflection::Schema &schema, const reflection::Object &root,
|
||||
const uint8_t *buf, size_t length);
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_REFLECTION_H_
|
||||
@@ -0,0 +1,919 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
namespace reflection {
|
||||
|
||||
struct Type;
|
||||
|
||||
struct KeyValue;
|
||||
|
||||
struct EnumVal;
|
||||
|
||||
struct Enum;
|
||||
|
||||
struct Field;
|
||||
|
||||
struct Object;
|
||||
|
||||
struct Schema;
|
||||
|
||||
enum BaseType {
|
||||
None = 0,
|
||||
UType = 1,
|
||||
Bool = 2,
|
||||
Byte = 3,
|
||||
UByte = 4,
|
||||
Short = 5,
|
||||
UShort = 6,
|
||||
Int = 7,
|
||||
UInt = 8,
|
||||
Long = 9,
|
||||
ULong = 10,
|
||||
Float = 11,
|
||||
Double = 12,
|
||||
String = 13,
|
||||
Vector = 14,
|
||||
Obj = 15,
|
||||
Union = 16
|
||||
};
|
||||
|
||||
inline const BaseType (&EnumValuesBaseType())[17] {
|
||||
static const BaseType values[] = {
|
||||
None,
|
||||
UType,
|
||||
Bool,
|
||||
Byte,
|
||||
UByte,
|
||||
Short,
|
||||
UShort,
|
||||
Int,
|
||||
UInt,
|
||||
Long,
|
||||
ULong,
|
||||
Float,
|
||||
Double,
|
||||
String,
|
||||
Vector,
|
||||
Obj,
|
||||
Union
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char * const *EnumNamesBaseType() {
|
||||
static const char * const names[] = {
|
||||
"None",
|
||||
"UType",
|
||||
"Bool",
|
||||
"Byte",
|
||||
"UByte",
|
||||
"Short",
|
||||
"UShort",
|
||||
"Int",
|
||||
"UInt",
|
||||
"Long",
|
||||
"ULong",
|
||||
"Float",
|
||||
"Double",
|
||||
"String",
|
||||
"Vector",
|
||||
"Obj",
|
||||
"Union",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameBaseType(BaseType e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesBaseType()[index];
|
||||
}
|
||||
|
||||
struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_BASE_TYPE = 4,
|
||||
VT_ELEMENT = 6,
|
||||
VT_INDEX = 8
|
||||
};
|
||||
BaseType base_type() const {
|
||||
return static_cast<BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0));
|
||||
}
|
||||
BaseType element() const {
|
||||
return static_cast<BaseType>(GetField<int8_t>(VT_ELEMENT, 0));
|
||||
}
|
||||
int32_t index() const {
|
||||
return GetField<int32_t>(VT_INDEX, -1);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<int8_t>(verifier, VT_BASE_TYPE) &&
|
||||
VerifyField<int8_t>(verifier, VT_ELEMENT) &&
|
||||
VerifyField<int32_t>(verifier, VT_INDEX) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct TypeBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_base_type(BaseType base_type) {
|
||||
fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0);
|
||||
}
|
||||
void add_element(BaseType element) {
|
||||
fbb_.AddElement<int8_t>(Type::VT_ELEMENT, static_cast<int8_t>(element), 0);
|
||||
}
|
||||
void add_index(int32_t index) {
|
||||
fbb_.AddElement<int32_t>(Type::VT_INDEX, index, -1);
|
||||
}
|
||||
explicit TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
TypeBuilder &operator=(const TypeBuilder &);
|
||||
flatbuffers::Offset<Type> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Type>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Type> CreateType(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
BaseType base_type = None,
|
||||
BaseType element = None,
|
||||
int32_t index = -1) {
|
||||
TypeBuilder builder_(_fbb);
|
||||
builder_.add_index(index);
|
||||
builder_.add_element(element);
|
||||
builder_.add_base_type(base_type);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_KEY = 4,
|
||||
VT_VALUE = 6
|
||||
};
|
||||
const flatbuffers::String *key() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_KEY);
|
||||
}
|
||||
bool KeyCompareLessThan(const KeyValue *o) const {
|
||||
return *key() < *o->key();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(key()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::String *value() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_VALUE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_KEY) &&
|
||||
verifier.Verify(key()) &&
|
||||
VerifyOffset(verifier, VT_VALUE) &&
|
||||
verifier.Verify(value()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct KeyValueBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_key(flatbuffers::Offset<flatbuffers::String> key) {
|
||||
fbb_.AddOffset(KeyValue::VT_KEY, key);
|
||||
}
|
||||
void add_value(flatbuffers::Offset<flatbuffers::String> value) {
|
||||
fbb_.AddOffset(KeyValue::VT_VALUE, value);
|
||||
}
|
||||
explicit KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
KeyValueBuilder &operator=(const KeyValueBuilder &);
|
||||
flatbuffers::Offset<KeyValue> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<KeyValue>(end);
|
||||
fbb_.Required(o, KeyValue::VT_KEY);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValue(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> key = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> value = 0) {
|
||||
KeyValueBuilder builder_(_fbb);
|
||||
builder_.add_value(value);
|
||||
builder_.add_key(key);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *key = nullptr,
|
||||
const char *value = nullptr) {
|
||||
return reflection::CreateKeyValue(
|
||||
_fbb,
|
||||
key ? _fbb.CreateString(key) : 0,
|
||||
value ? _fbb.CreateString(value) : 0);
|
||||
}
|
||||
|
||||
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_VALUE = 6,
|
||||
VT_OBJECT = 8,
|
||||
VT_UNION_TYPE = 10
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
int64_t value() const {
|
||||
return GetField<int64_t>(VT_VALUE, 0);
|
||||
}
|
||||
bool KeyCompareLessThan(const EnumVal *o) const {
|
||||
return value() < o->value();
|
||||
}
|
||||
int KeyCompareWithValue(int64_t val) const {
|
||||
const auto key = value();
|
||||
if (key < val) {
|
||||
return -1;
|
||||
} else if (key > val) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const Object *object() const {
|
||||
return GetPointer<const Object *>(VT_OBJECT);
|
||||
}
|
||||
const Type *union_type() const {
|
||||
return GetPointer<const Type *>(VT_UNION_TYPE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<int64_t>(verifier, VT_VALUE) &&
|
||||
VerifyOffset(verifier, VT_OBJECT) &&
|
||||
verifier.VerifyTable(object()) &&
|
||||
VerifyOffset(verifier, VT_UNION_TYPE) &&
|
||||
verifier.VerifyTable(union_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct EnumValBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(EnumVal::VT_NAME, name);
|
||||
}
|
||||
void add_value(int64_t value) {
|
||||
fbb_.AddElement<int64_t>(EnumVal::VT_VALUE, value, 0);
|
||||
}
|
||||
void add_object(flatbuffers::Offset<Object> object) {
|
||||
fbb_.AddOffset(EnumVal::VT_OBJECT, object);
|
||||
}
|
||||
void add_union_type(flatbuffers::Offset<Type> union_type) {
|
||||
fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
|
||||
}
|
||||
explicit EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
EnumValBuilder &operator=(const EnumValBuilder &);
|
||||
flatbuffers::Offset<EnumVal> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<EnumVal>(end);
|
||||
fbb_.Required(o, EnumVal::VT_NAME);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumVal(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
EnumValBuilder builder_(_fbb);
|
||||
builder_.add_value(value);
|
||||
builder_.add_union_type(union_type);
|
||||
builder_.add_object(object);
|
||||
builder_.add_name(name);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
return reflection::CreateEnumVal(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
value,
|
||||
object,
|
||||
union_type);
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_VALUES = 6,
|
||||
VT_IS_UNION = 8,
|
||||
VT_UNDERLYING_TYPE = 10,
|
||||
VT_ATTRIBUTES = 12,
|
||||
VT_DOCUMENTATION = 14
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Enum *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *values() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(VT_VALUES);
|
||||
}
|
||||
bool is_union() const {
|
||||
return GetField<uint8_t>(VT_IS_UNION, 0) != 0;
|
||||
}
|
||||
const Type *underlying_type() const {
|
||||
return GetPointer<const Type *>(VT_UNDERLYING_TYPE);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_VALUES) &&
|
||||
verifier.Verify(values()) &&
|
||||
verifier.VerifyVectorOfTables(values()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
|
||||
VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
|
||||
verifier.VerifyTable(underlying_type()) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct EnumBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Enum::VT_NAME, name);
|
||||
}
|
||||
void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values) {
|
||||
fbb_.AddOffset(Enum::VT_VALUES, values);
|
||||
}
|
||||
void add_is_union(bool is_union) {
|
||||
fbb_.AddElement<uint8_t>(Enum::VT_IS_UNION, static_cast<uint8_t>(is_union), 0);
|
||||
}
|
||||
void add_underlying_type(flatbuffers::Offset<Type> underlying_type) {
|
||||
fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
explicit EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
EnumBuilder &operator=(const EnumBuilder &);
|
||||
flatbuffers::Offset<Enum> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Enum>(end);
|
||||
fbb_.Required(o, Enum::VT_NAME);
|
||||
fbb_.Required(o, Enum::VT_VALUES);
|
||||
fbb_.Required(o, Enum::VT_UNDERLYING_TYPE);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Enum> CreateEnum(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values = 0,
|
||||
bool is_union = false,
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
EnumBuilder builder_(_fbb);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_underlying_type(underlying_type);
|
||||
builder_.add_values(values);
|
||||
builder_.add_name(name);
|
||||
builder_.add_is_union(is_union);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Enum> CreateEnumDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<EnumVal>> *values = nullptr,
|
||||
bool is_union = false,
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateEnum(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0,
|
||||
is_union,
|
||||
underlying_type,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_TYPE = 6,
|
||||
VT_ID = 8,
|
||||
VT_OFFSET = 10,
|
||||
VT_DEFAULT_INTEGER = 12,
|
||||
VT_DEFAULT_REAL = 14,
|
||||
VT_DEPRECATED = 16,
|
||||
VT_REQUIRED = 18,
|
||||
VT_KEY = 20,
|
||||
VT_ATTRIBUTES = 22,
|
||||
VT_DOCUMENTATION = 24
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Field *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const Type *type() const {
|
||||
return GetPointer<const Type *>(VT_TYPE);
|
||||
}
|
||||
uint16_t id() const {
|
||||
return GetField<uint16_t>(VT_ID, 0);
|
||||
}
|
||||
uint16_t offset() const {
|
||||
return GetField<uint16_t>(VT_OFFSET, 0);
|
||||
}
|
||||
int64_t default_integer() const {
|
||||
return GetField<int64_t>(VT_DEFAULT_INTEGER, 0);
|
||||
}
|
||||
double default_real() const {
|
||||
return GetField<double>(VT_DEFAULT_REAL, 0.0);
|
||||
}
|
||||
bool deprecated() const {
|
||||
return GetField<uint8_t>(VT_DEPRECATED, 0) != 0;
|
||||
}
|
||||
bool required() const {
|
||||
return GetField<uint8_t>(VT_REQUIRED, 0) != 0;
|
||||
}
|
||||
bool key() const {
|
||||
return GetField<uint8_t>(VT_KEY, 0) != 0;
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_TYPE) &&
|
||||
verifier.VerifyTable(type()) &&
|
||||
VerifyField<uint16_t>(verifier, VT_ID) &&
|
||||
VerifyField<uint16_t>(verifier, VT_OFFSET) &&
|
||||
VerifyField<int64_t>(verifier, VT_DEFAULT_INTEGER) &&
|
||||
VerifyField<double>(verifier, VT_DEFAULT_REAL) &&
|
||||
VerifyField<uint8_t>(verifier, VT_DEPRECATED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_KEY) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct FieldBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Field::VT_NAME, name);
|
||||
}
|
||||
void add_type(flatbuffers::Offset<Type> type) {
|
||||
fbb_.AddOffset(Field::VT_TYPE, type);
|
||||
}
|
||||
void add_id(uint16_t id) {
|
||||
fbb_.AddElement<uint16_t>(Field::VT_ID, id, 0);
|
||||
}
|
||||
void add_offset(uint16_t offset) {
|
||||
fbb_.AddElement<uint16_t>(Field::VT_OFFSET, offset, 0);
|
||||
}
|
||||
void add_default_integer(int64_t default_integer) {
|
||||
fbb_.AddElement<int64_t>(Field::VT_DEFAULT_INTEGER, default_integer, 0);
|
||||
}
|
||||
void add_default_real(double default_real) {
|
||||
fbb_.AddElement<double>(Field::VT_DEFAULT_REAL, default_real, 0.0);
|
||||
}
|
||||
void add_deprecated(bool deprecated) {
|
||||
fbb_.AddElement<uint8_t>(Field::VT_DEPRECATED, static_cast<uint8_t>(deprecated), 0);
|
||||
}
|
||||
void add_required(bool required) {
|
||||
fbb_.AddElement<uint8_t>(Field::VT_REQUIRED, static_cast<uint8_t>(required), 0);
|
||||
}
|
||||
void add_key(bool key) {
|
||||
fbb_.AddElement<uint8_t>(Field::VT_KEY, static_cast<uint8_t>(key), 0);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Field::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
explicit FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
FieldBuilder &operator=(const FieldBuilder &);
|
||||
flatbuffers::Offset<Field> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Field>(end);
|
||||
fbb_.Required(o, Field::VT_NAME);
|
||||
fbb_.Required(o, Field::VT_TYPE);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Field> CreateField(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
uint16_t offset = 0,
|
||||
int64_t default_integer = 0,
|
||||
double default_real = 0.0,
|
||||
bool deprecated = false,
|
||||
bool required = false,
|
||||
bool key = false,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
FieldBuilder builder_(_fbb);
|
||||
builder_.add_default_real(default_real);
|
||||
builder_.add_default_integer(default_integer);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_type(type);
|
||||
builder_.add_name(name);
|
||||
builder_.add_offset(offset);
|
||||
builder_.add_id(id);
|
||||
builder_.add_key(key);
|
||||
builder_.add_required(required);
|
||||
builder_.add_deprecated(deprecated);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Field> CreateFieldDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
uint16_t offset = 0,
|
||||
int64_t default_integer = 0,
|
||||
double default_real = 0.0,
|
||||
bool deprecated = false,
|
||||
bool required = false,
|
||||
bool key = false,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateField(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
type,
|
||||
id,
|
||||
offset,
|
||||
default_integer,
|
||||
default_real,
|
||||
deprecated,
|
||||
required,
|
||||
key,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_FIELDS = 6,
|
||||
VT_IS_STRUCT = 8,
|
||||
VT_MINALIGN = 10,
|
||||
VT_BYTESIZE = 12,
|
||||
VT_ATTRIBUTES = 14,
|
||||
VT_DOCUMENTATION = 16
|
||||
};
|
||||
const flatbuffers::String *name() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_NAME);
|
||||
}
|
||||
bool KeyCompareLessThan(const Object *o) const {
|
||||
return *name() < *o->name();
|
||||
}
|
||||
int KeyCompareWithValue(const char *val) const {
|
||||
return strcmp(name()->c_str(), val);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(VT_FIELDS);
|
||||
}
|
||||
bool is_struct() const {
|
||||
return GetField<uint8_t>(VT_IS_STRUCT, 0) != 0;
|
||||
}
|
||||
int32_t minalign() const {
|
||||
return GetField<int32_t>(VT_MINALIGN, 0);
|
||||
}
|
||||
int32_t bytesize() const {
|
||||
return GetField<int32_t>(VT_BYTESIZE, 0);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyOffsetRequired(verifier, VT_FIELDS) &&
|
||||
verifier.Verify(fields()) &&
|
||||
verifier.VerifyVectorOfTables(fields()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
|
||||
VerifyField<int32_t>(verifier, VT_MINALIGN) &&
|
||||
VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct ObjectBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Object::VT_NAME, name);
|
||||
}
|
||||
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) {
|
||||
fbb_.AddOffset(Object::VT_FIELDS, fields);
|
||||
}
|
||||
void add_is_struct(bool is_struct) {
|
||||
fbb_.AddElement<uint8_t>(Object::VT_IS_STRUCT, static_cast<uint8_t>(is_struct), 0);
|
||||
}
|
||||
void add_minalign(int32_t minalign) {
|
||||
fbb_.AddElement<int32_t>(Object::VT_MINALIGN, minalign, 0);
|
||||
}
|
||||
void add_bytesize(int32_t bytesize) {
|
||||
fbb_.AddElement<int32_t>(Object::VT_BYTESIZE, bytesize, 0);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) {
|
||||
fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes);
|
||||
}
|
||||
void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
|
||||
fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation);
|
||||
}
|
||||
explicit ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
ObjectBuilder &operator=(const ObjectBuilder &);
|
||||
flatbuffers::Offset<Object> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Object>(end);
|
||||
fbb_.Required(o, Object::VT_NAME);
|
||||
fbb_.Required(o, Object::VT_FIELDS);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Object> CreateObject(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0,
|
||||
bool is_struct = false,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
|
||||
ObjectBuilder builder_(_fbb);
|
||||
builder_.add_documentation(documentation);
|
||||
builder_.add_attributes(attributes);
|
||||
builder_.add_bytesize(bytesize);
|
||||
builder_.add_minalign(minalign);
|
||||
builder_.add_fields(fields);
|
||||
builder_.add_name(name);
|
||||
builder_.add_is_struct(is_struct);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Object> CreateObjectDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<Field>> *fields = nullptr,
|
||||
bool is_struct = false,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateObject(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0,
|
||||
is_struct,
|
||||
minalign,
|
||||
bytesize,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_OBJECTS = 4,
|
||||
VT_ENUMS = 6,
|
||||
VT_FILE_IDENT = 8,
|
||||
VT_FILE_EXT = 10,
|
||||
VT_ROOT_TABLE = 12
|
||||
};
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Enum>> *>(VT_ENUMS);
|
||||
}
|
||||
const flatbuffers::String *file_ident() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_FILE_IDENT);
|
||||
}
|
||||
const flatbuffers::String *file_ext() const {
|
||||
return GetPointer<const flatbuffers::String *>(VT_FILE_EXT);
|
||||
}
|
||||
const Object *root_table() const {
|
||||
return GetPointer<const Object *>(VT_ROOT_TABLE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
|
||||
verifier.Verify(objects()) &&
|
||||
verifier.VerifyVectorOfTables(objects()) &&
|
||||
VerifyOffsetRequired(verifier, VT_ENUMS) &&
|
||||
verifier.Verify(enums()) &&
|
||||
verifier.VerifyVectorOfTables(enums()) &&
|
||||
VerifyOffset(verifier, VT_FILE_IDENT) &&
|
||||
verifier.Verify(file_ident()) &&
|
||||
VerifyOffset(verifier, VT_FILE_EXT) &&
|
||||
verifier.Verify(file_ext()) &&
|
||||
VerifyOffset(verifier, VT_ROOT_TABLE) &&
|
||||
verifier.VerifyTable(root_table()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct SchemaBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) {
|
||||
fbb_.AddOffset(Schema::VT_OBJECTS, objects);
|
||||
}
|
||||
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums) {
|
||||
fbb_.AddOffset(Schema::VT_ENUMS, enums);
|
||||
}
|
||||
void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) {
|
||||
fbb_.AddOffset(Schema::VT_FILE_IDENT, file_ident);
|
||||
}
|
||||
void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) {
|
||||
fbb_.AddOffset(Schema::VT_FILE_EXT, file_ext);
|
||||
}
|
||||
void add_root_table(flatbuffers::Offset<Object> root_table) {
|
||||
fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table);
|
||||
}
|
||||
explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
SchemaBuilder &operator=(const SchemaBuilder &);
|
||||
flatbuffers::Offset<Schema> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Schema>(end);
|
||||
fbb_.Required(o, Schema::VT_OBJECTS);
|
||||
fbb_.Required(o, Schema::VT_ENUMS);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Schema> CreateSchema(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> file_ident = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> file_ext = 0,
|
||||
flatbuffers::Offset<Object> root_table = 0) {
|
||||
SchemaBuilder builder_(_fbb);
|
||||
builder_.add_root_table(root_table);
|
||||
builder_.add_file_ext(file_ext);
|
||||
builder_.add_file_ident(file_ident);
|
||||
builder_.add_enums(enums);
|
||||
builder_.add_objects(objects);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Schema> CreateSchemaDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<flatbuffers::Offset<Object>> *objects = nullptr,
|
||||
const std::vector<flatbuffers::Offset<Enum>> *enums = nullptr,
|
||||
const char *file_ident = nullptr,
|
||||
const char *file_ext = nullptr,
|
||||
flatbuffers::Offset<Object> root_table = 0) {
|
||||
return reflection::CreateSchema(
|
||||
_fbb,
|
||||
objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0,
|
||||
enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0,
|
||||
file_ident ? _fbb.CreateString(file_ident) : 0,
|
||||
file_ext ? _fbb.CreateString(file_ext) : 0,
|
||||
root_table);
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSchema(const void *buf) {
|
||||
return flatbuffers::GetRoot<reflection::Schema>(buf);
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSizePrefixedSchema(const void *buf) {
|
||||
return flatbuffers::GetSizePrefixedRoot<reflection::Schema>(buf);
|
||||
}
|
||||
|
||||
inline const char *SchemaIdentifier() {
|
||||
return "BFBS";
|
||||
}
|
||||
|
||||
inline bool SchemaBufferHasIdentifier(const void *buf) {
|
||||
return flatbuffers::BufferHasIdentifier(
|
||||
buf, SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline bool VerifySchemaBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline bool VerifySizePrefixedSchemaBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifySizePrefixedBuffer<reflection::Schema>(SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline const char *SchemaExtension() {
|
||||
return "bfbs";
|
||||
}
|
||||
|
||||
inline void FinishSchemaBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<reflection::Schema> root) {
|
||||
fbb.Finish(root, SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline void FinishSizePrefixedSchemaBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<reflection::Schema> root) {
|
||||
fbb.FinishSizePrefixed(root, SchemaIdentifier());
|
||||
}
|
||||
|
||||
} // namespace reflection
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_REGISTRY_H_
|
||||
#define FLATBUFFERS_REGISTRY_H_
|
||||
|
||||
#include "flatbuffers/idl.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
|
||||
// Simply pre-populate it with all schema filenames that may be in use, and
|
||||
// This class will look them up using the file_identifier declared in the
|
||||
// schema.
|
||||
class Registry {
|
||||
public:
|
||||
// Call this for all schemas that may be in use. The identifier has
|
||||
// a function in the generated code, e.g. MonsterIdentifier().
|
||||
void Register(const char *file_identifier, const char *schema_path) {
|
||||
Schema schema;
|
||||
schema.path_ = schema_path;
|
||||
schemas_[file_identifier] = schema;
|
||||
}
|
||||
|
||||
// Generate text from an arbitrary FlatBuffer by looking up its
|
||||
// file_identifier in the registry.
|
||||
bool FlatBufferToText(const uint8_t *flatbuf, size_t len, std::string *dest) {
|
||||
// Get the identifier out of the buffer.
|
||||
// If the buffer is truncated, exit.
|
||||
if (len < sizeof(uoffset_t) + FlatBufferBuilder::kFileIdentifierLength) {
|
||||
lasterror_ = "buffer truncated";
|
||||
return false;
|
||||
}
|
||||
std::string ident(
|
||||
reinterpret_cast<const char *>(flatbuf) + sizeof(uoffset_t),
|
||||
FlatBufferBuilder::kFileIdentifierLength);
|
||||
// Load and parse the schema.
|
||||
Parser parser;
|
||||
if (!LoadSchema(ident, &parser)) return false;
|
||||
// Now we're ready to generate text.
|
||||
if (!GenerateText(parser, flatbuf, dest)) {
|
||||
lasterror_ = "unable to generate text for FlatBuffer binary";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Converts a binary buffer to text using one of the schemas in the registry,
|
||||
// use the file_identifier to indicate which.
|
||||
// If DetachedBuffer::data() is null then parsing failed.
|
||||
DetachedBuffer TextToFlatBuffer(const char *text,
|
||||
const char *file_identifier) {
|
||||
// Load and parse the schema.
|
||||
Parser parser;
|
||||
if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
|
||||
// Parse the text.
|
||||
if (!parser.Parse(text)) {
|
||||
lasterror_ = parser.error_;
|
||||
return DetachedBuffer();
|
||||
}
|
||||
// We have a valid FlatBuffer. Detach it from the builder and return.
|
||||
return parser.builder_.ReleaseBufferPointer();
|
||||
}
|
||||
|
||||
// Modify any parsing / output options used by the other functions.
|
||||
void SetOptions(const IDLOptions &opts) { opts_ = opts; }
|
||||
|
||||
// If schemas used contain include statements, call this function for every
|
||||
// directory the parser should search them for.
|
||||
void AddIncludeDirectory(const char *path) { include_paths_.push_back(path); }
|
||||
|
||||
// Returns a human readable error if any of the above functions fail.
|
||||
const std::string &GetLastError() { return lasterror_; }
|
||||
|
||||
private:
|
||||
bool LoadSchema(const std::string &ident, Parser *parser) {
|
||||
// Find the schema, if not, exit.
|
||||
auto it = schemas_.find(ident);
|
||||
if (it == schemas_.end()) {
|
||||
// Don't attach the identifier, since it may not be human readable.
|
||||
lasterror_ = "identifier for this buffer not in the registry";
|
||||
return false;
|
||||
}
|
||||
auto &schema = it->second;
|
||||
// Load the schema from disk. If not, exit.
|
||||
std::string schematext;
|
||||
if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
|
||||
lasterror_ = "could not load schema: " + schema.path_;
|
||||
return false;
|
||||
}
|
||||
// Parse schema.
|
||||
parser->opts = opts_;
|
||||
if (!parser->Parse(schematext.c_str(), vector_data(include_paths_),
|
||||
schema.path_.c_str())) {
|
||||
lasterror_ = parser->error_;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Schema {
|
||||
std::string path_;
|
||||
// TODO(wvo) optionally cache schema file or parsed schema here.
|
||||
};
|
||||
|
||||
std::string lasterror_;
|
||||
IDLOptions opts_;
|
||||
std::vector<const char *> include_paths_;
|
||||
std::map<std::string, Schema> schemas_;
|
||||
};
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_REGISTRY_H_
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_STL_EMULATION_H_
|
||||
#define FLATBUFFERS_STL_EMULATION_H_
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
#define FLATBUFFERS_CPP98_STL
|
||||
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
#include <cctype>
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// This header provides backwards compatibility for C++98 STLs like stlport.
|
||||
namespace flatbuffers {
|
||||
|
||||
// Retrieve ::back() from a string in a way that is compatible with pre C++11
|
||||
// STLs (e.g stlport).
|
||||
inline char& string_back(std::string &value) {
|
||||
return value[value.length() - 1];
|
||||
}
|
||||
|
||||
inline char string_back(const std::string &value) {
|
||||
return value[value.length() - 1];
|
||||
}
|
||||
|
||||
// Helper method that retrieves ::data() from a vector in a way that is
|
||||
// compatible with pre C++11 STLs (e.g stlport).
|
||||
template <typename T> inline T *vector_data(std::vector<T> &vector) {
|
||||
// In some debug environments, operator[] does bounds checking, so &vector[0]
|
||||
// can't be used.
|
||||
return vector.empty() ? nullptr : &vector[0];
|
||||
}
|
||||
|
||||
template <typename T> inline const T *vector_data(
|
||||
const std::vector<T> &vector) {
|
||||
return vector.empty() ? nullptr : &vector[0];
|
||||
}
|
||||
|
||||
template <typename T, typename V>
|
||||
inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
vector->push_back(data);
|
||||
#else
|
||||
vector->emplace_back(std::forward<V>(data));
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
}
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
template <typename T>
|
||||
using numeric_limits = std::numeric_limits<T>;
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#else
|
||||
template <typename T> class numeric_limits :
|
||||
public std::numeric_limits<T> {};
|
||||
|
||||
template <> class numeric_limits<unsigned long long> {
|
||||
public:
|
||||
static unsigned long long min() { return 0ULL; }
|
||||
static unsigned long long max() { return ~0ULL; }
|
||||
};
|
||||
|
||||
template <> class numeric_limits<long long> {
|
||||
public:
|
||||
static long long min() {
|
||||
return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
|
||||
}
|
||||
static long long max() {
|
||||
return static_cast<long long>(
|
||||
(1ULL << ((sizeof(long long) << 3) - 1)) - 1);
|
||||
}
|
||||
};
|
||||
#endif // FLATBUFFERS_CPP98_STL
|
||||
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
template <typename T> using is_scalar = std::is_scalar<T>;
|
||||
template <typename T, typename U> using is_same = std::is_same<T,U>;
|
||||
template <typename T> using is_floating_point = std::is_floating_point<T>;
|
||||
template <typename T> using is_unsigned = std::is_unsigned<T>;
|
||||
#else
|
||||
// Map C++ TR1 templates defined by stlport.
|
||||
template <typename T> using is_scalar = std::tr1::is_scalar<T>;
|
||||
template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
|
||||
template <typename T> using is_floating_point =
|
||||
std::tr1::is_floating_point<T>;
|
||||
template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
|
||||
#endif // !FLATBUFFERS_CPP98_STL
|
||||
#else
|
||||
// MSVC 2010 doesn't support C++11 aliases.
|
||||
template <typename T> struct is_scalar : public std::is_scalar<T> {};
|
||||
template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
|
||||
template <typename T> struct is_floating_point :
|
||||
public std::is_floating_point<T> {};
|
||||
template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
|
||||
#ifndef FLATBUFFERS_CPP98_STL
|
||||
#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
template <class T> using unique_ptr = std::unique_ptr<T>;
|
||||
#else
|
||||
// MSVC 2010 doesn't support C++11 aliases.
|
||||
// We're manually "aliasing" the class here as we want to bring unique_ptr
|
||||
// into the flatbuffers namespace. We have unique_ptr in the flatbuffers
|
||||
// namespace we have a completely independent implemenation (see below)
|
||||
// for C++98 STL implementations.
|
||||
template <class T> class unique_ptr : public std::unique_ptr<T> {
|
||||
public:
|
||||
unique_ptr() {}
|
||||
explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
|
||||
unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
|
||||
unique_ptr(unique_ptr&& u) { *this = std::move(u); }
|
||||
unique_ptr& operator=(std::unique_ptr<T>&& u) {
|
||||
std::unique_ptr<T>::reset(u.release());
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(unique_ptr&& u) {
|
||||
std::unique_ptr<T>::reset(u.release());
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(T* p) {
|
||||
return std::unique_ptr<T>::operator=(p);
|
||||
}
|
||||
};
|
||||
#endif // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
|
||||
#else
|
||||
// Very limited implementation of unique_ptr.
|
||||
// This is provided simply to allow the C++ code generated from the default
|
||||
// settings to function in C++98 environments with no modifications.
|
||||
template <class T> class unique_ptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
unique_ptr() : ptr_(nullptr) {}
|
||||
explicit unique_ptr(T* p) : ptr_(p) {}
|
||||
unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
|
||||
unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
|
||||
reset(const_cast<unique_ptr*>(&u)->release());
|
||||
}
|
||||
~unique_ptr() { reset(); }
|
||||
|
||||
unique_ptr& operator=(const unique_ptr& u) {
|
||||
reset(const_cast<unique_ptr*>(&u)->release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr& operator=(unique_ptr&& u) {
|
||||
reset(u.release());
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr& operator=(T* p) {
|
||||
reset(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
T* get() const noexcept { return ptr_; }
|
||||
explicit operator bool() const { return ptr_ != nullptr; }
|
||||
|
||||
// modifiers
|
||||
T* release() {
|
||||
T* value = ptr_;
|
||||
ptr_ = nullptr;
|
||||
return value;
|
||||
}
|
||||
|
||||
void reset(T* p = nullptr) {
|
||||
T* value = ptr_;
|
||||
ptr_ = p;
|
||||
if (value) delete value;
|
||||
}
|
||||
|
||||
void swap(unique_ptr& u) {
|
||||
T* temp_ptr = ptr_;
|
||||
ptr_ = u.ptr_;
|
||||
u.ptr_ = temp_ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
T* ptr_;
|
||||
};
|
||||
|
||||
template <class T> bool operator==(const unique_ptr<T>& x,
|
||||
const unique_ptr<T>& y) {
|
||||
return x.get() == y.get();
|
||||
}
|
||||
|
||||
template <class T, class D> bool operator==(const unique_ptr<T>& x,
|
||||
const D* y) {
|
||||
return static_cast<D*>(x.get()) == y;
|
||||
}
|
||||
|
||||
template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
|
||||
return reinterpret_cast<intptr_t>(x.get()) == y;
|
||||
}
|
||||
#endif // !FLATBUFFERS_CPP98_STL
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_STL_EMULATION_H_
|
||||
+452
@@ -0,0 +1,452 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef FLATBUFFERS_UTIL_H_
|
||||
#define FLATBUFFERS_UTIL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h> // Must be included before <direct.h>
|
||||
# include <direct.h>
|
||||
# include <winbase.h>
|
||||
# undef interface // This is also important because of reasons
|
||||
#else
|
||||
# include <limits.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "flatbuffers/base.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
// Convert an integer or floating point value to a string.
|
||||
// In contrast to std::stringstream, "char" values are
|
||||
// converted to a string of digits, and we don't use scientific notation.
|
||||
template<typename T> std::string NumToString(T t) {
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
}
|
||||
// Avoid char types used as character data.
|
||||
template<> inline std::string NumToString<signed char>(signed char t) {
|
||||
return NumToString(static_cast<int>(t));
|
||||
}
|
||||
template<> inline std::string NumToString<unsigned char>(unsigned char t) {
|
||||
return NumToString(static_cast<int>(t));
|
||||
}
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
template<> inline std::string NumToString<long long>(long long t) {
|
||||
char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2
|
||||
snprintf(buf, sizeof(buf), "%lld", t);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string NumToString<unsigned long long>(unsigned long long t) {
|
||||
char buf[22]; // (log((1 << 63) - 1) / log(10)) + 1
|
||||
snprintf(buf, sizeof(buf), "%llu", t);
|
||||
return std::string(buf);
|
||||
}
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// Special versions for floats/doubles.
|
||||
template<typename T> std::string FloatToString(T t, int precision) {
|
||||
// to_string() prints different numbers of digits for floats depending on
|
||||
// platform and isn't available on Android, so we use stringstream
|
||||
std::stringstream ss;
|
||||
// Use std::fixed to surpress scientific notation.
|
||||
ss << std::fixed;
|
||||
// Default precision is 6, we want that to be higher for doubles.
|
||||
ss << std::setprecision(precision);
|
||||
ss << t;
|
||||
auto s = ss.str();
|
||||
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
|
||||
auto p = s.find_last_not_of('0');
|
||||
if (p != std::string::npos) {
|
||||
// Strip trailing zeroes. If it is a whole number, keep one zero.
|
||||
s.resize(p + (s[p] == '.' ? 2 : 1));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template<> inline std::string NumToString<double>(double t) {
|
||||
return FloatToString(t, 12);
|
||||
}
|
||||
template<> inline std::string NumToString<float>(float t) {
|
||||
return FloatToString(t, 6);
|
||||
}
|
||||
|
||||
// Convert an integer value to a hexadecimal string.
|
||||
// The returned string length is always xdigits long, prefixed by 0 digits.
|
||||
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
||||
inline std::string IntToStringHex(int i, int xdigits) {
|
||||
std::stringstream ss;
|
||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||
<< i;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// Portable implementation of strtoll().
|
||||
inline int64_t StringToInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
// clang-format off
|
||||
#ifdef _MSC_VER
|
||||
return _strtoi64(str, endptr, base);
|
||||
#else
|
||||
return strtoll(str, endptr, base);
|
||||
#endif
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Portable implementation of strtoull().
|
||||
inline uint64_t StringToUInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
// clang-format off
|
||||
#ifdef _MSC_VER
|
||||
return _strtoui64(str, endptr, base);
|
||||
#else
|
||||
return strtoull(str, endptr, base);
|
||||
#endif
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
typedef bool (*LoadFileFunction)(const char *filename, bool binary,
|
||||
std::string *dest);
|
||||
typedef bool (*FileExistsFunction)(const char *filename);
|
||||
|
||||
LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function);
|
||||
|
||||
FileExistsFunction SetFileExistsFunction(
|
||||
FileExistsFunction file_exists_function);
|
||||
|
||||
// Check if file "name" exists.
|
||||
bool FileExists(const char *name);
|
||||
|
||||
// Check if "name" exists and it is also a directory.
|
||||
bool DirExists(const char *name);
|
||||
|
||||
// Load file "name" into "buf" returning true if successful
|
||||
// false otherwise. If "binary" is false data is read
|
||||
// using ifstream's text mode, otherwise data is read with
|
||||
// no transcoding.
|
||||
bool LoadFile(const char *name, bool binary, std::string *buf);
|
||||
|
||||
// Save data "buf" of length "len" bytes into a file
|
||||
// "name" returning true if successful, false otherwise.
|
||||
// If "binary" is false data is written using ifstream's
|
||||
// text mode, otherwise data is written with no
|
||||
// transcoding.
|
||||
inline bool SaveFile(const char *name, const char *buf, size_t len,
|
||||
bool binary) {
|
||||
std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out);
|
||||
if (!ofs.is_open()) return false;
|
||||
ofs.write(buf, len);
|
||||
return !ofs.bad();
|
||||
}
|
||||
|
||||
// Save data "buf" into file "name" returning true if
|
||||
// successful, false otherwise. If "binary" is false
|
||||
// data is written using ifstream's text mode, otherwise
|
||||
// data is written with no transcoding.
|
||||
inline bool SaveFile(const char *name, const std::string &buf, bool binary) {
|
||||
return SaveFile(name, buf.c_str(), buf.size(), binary);
|
||||
}
|
||||
|
||||
// Functionality for minimalistic portable path handling.
|
||||
|
||||
// The functions below behave correctly regardless of whether posix ('/') or
|
||||
// Windows ('/' or '\\') separators are used.
|
||||
|
||||
// Any new separators inserted are always posix.
|
||||
|
||||
// We internally store paths in posix format ('/'). Paths supplied
|
||||
// by the user should go through PosixPath to ensure correct behavior
|
||||
// on Windows when paths are string-compared.
|
||||
|
||||
static const char kPathSeparator = '/';
|
||||
static const char kPathSeparatorWindows = '\\';
|
||||
static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
|
||||
|
||||
// Returns the path with the extension, if any, removed.
|
||||
inline std::string StripExtension(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(".");
|
||||
return i != std::string::npos ? filepath.substr(0, i) : filepath;
|
||||
}
|
||||
|
||||
// Returns the extension, if any.
|
||||
inline std::string GetExtension(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(".");
|
||||
return i != std::string::npos ? filepath.substr(i + 1) : "";
|
||||
}
|
||||
|
||||
// Return the last component of the path, after the last separator.
|
||||
inline std::string StripPath(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(PathSeparatorSet);
|
||||
return i != std::string::npos ? filepath.substr(i + 1) : filepath;
|
||||
}
|
||||
|
||||
// Strip the last component of the path + separator.
|
||||
inline std::string StripFileName(const std::string &filepath) {
|
||||
size_t i = filepath.find_last_of(PathSeparatorSet);
|
||||
return i != std::string::npos ? filepath.substr(0, i) : "";
|
||||
}
|
||||
|
||||
// Concatenates a path with a filename, regardless of wether the path
|
||||
// ends in a separator or not.
|
||||
inline std::string ConCatPathFileName(const std::string &path,
|
||||
const std::string &filename) {
|
||||
std::string filepath = path;
|
||||
if (filepath.length()) {
|
||||
char &filepath_last_character = string_back(filepath);
|
||||
if (filepath_last_character == kPathSeparatorWindows) {
|
||||
filepath_last_character = kPathSeparator;
|
||||
} else if (filepath_last_character != kPathSeparator) {
|
||||
filepath += kPathSeparator;
|
||||
}
|
||||
}
|
||||
filepath += filename;
|
||||
// Ignore './' at the start of filepath.
|
||||
if (filepath[0] == '.' && filepath[1] == kPathSeparator) {
|
||||
filepath.erase(0, 2);
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
|
||||
// Replaces any '\\' separators with '/'
|
||||
inline std::string PosixPath(const char *path) {
|
||||
std::string p = path;
|
||||
std::replace(p.begin(), p.end(), '\\', '/');
|
||||
return p;
|
||||
}
|
||||
|
||||
// This function ensure a directory exists, by recursively
|
||||
// creating dirs for any parts of the path that don't exist yet.
|
||||
inline void EnsureDirExists(const std::string &filepath) {
|
||||
auto parent = StripFileName(filepath);
|
||||
if (parent.length()) EnsureDirExists(parent);
|
||||
// clang-format off
|
||||
#ifdef _WIN32
|
||||
(void)_mkdir(filepath.c_str());
|
||||
#else
|
||||
mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
|
||||
#endif
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Obtains the absolute path from any other path.
|
||||
// Returns the input path if the absolute path couldn't be resolved.
|
||||
inline std::string AbsolutePath(const std::string &filepath) {
|
||||
// clang-format off
|
||||
#ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
|
||||
return filepath;
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
char abs_path[MAX_PATH];
|
||||
return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
|
||||
#else
|
||||
char abs_path[PATH_MAX];
|
||||
return realpath(filepath.c_str(), abs_path)
|
||||
#endif
|
||||
? abs_path
|
||||
: filepath;
|
||||
#endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// To and from UTF-8 unicode conversion functions
|
||||
|
||||
// Convert a unicode code point into a UTF-8 representation by appending it
|
||||
// to a string. Returns the number of bytes generated.
|
||||
inline int ToUTF8(uint32_t ucc, std::string *out) {
|
||||
assert(!(ucc & 0x80000000)); // Top bit can't be set.
|
||||
// 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8
|
||||
for (int i = 0; i < 6; i++) {
|
||||
// Max bits this encoding can represent.
|
||||
uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i);
|
||||
if (ucc < (1u << max_bits)) { // does it fit?
|
||||
// Remaining bits not encoded in the first byte, store 6 bits each
|
||||
uint32_t remain_bits = i * 6;
|
||||
// Store first byte:
|
||||
(*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) |
|
||||
(ucc >> remain_bits));
|
||||
// Store remaining bytes:
|
||||
for (int j = i - 1; j >= 0; j--) {
|
||||
(*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80);
|
||||
}
|
||||
return i + 1; // Return the number of bytes added.
|
||||
}
|
||||
}
|
||||
assert(0); // Impossible to arrive here.
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Converts whatever prefix of the incoming string corresponds to a valid
|
||||
// UTF-8 sequence into a unicode code. The incoming pointer will have been
|
||||
// advanced past all bytes parsed.
|
||||
// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in
|
||||
// this case).
|
||||
inline int FromUTF8(const char **in) {
|
||||
int len = 0;
|
||||
// Count leading 1 bits.
|
||||
for (int mask = 0x80; mask >= 0x04; mask >>= 1) {
|
||||
if (**in & mask) {
|
||||
len++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((static_cast<const unsigned char>(**in) << len) & 0x80) return -1; // Bit after leading 1's must be 0.
|
||||
if (!len) return *(*in)++;
|
||||
// UTF-8 encoded values with a length are between 2 and 4 bytes.
|
||||
if (len < 2 || len > 4) { return -1; }
|
||||
// Grab initial bits of the code.
|
||||
int ucc = *(*in)++ & ((1 << (7 - len)) - 1);
|
||||
for (int i = 0; i < len - 1; i++) {
|
||||
if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0.
|
||||
ucc <<= 6;
|
||||
ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code.
|
||||
}
|
||||
// UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for
|
||||
// UTF-16 surrogate pairs).
|
||||
if (ucc >= 0xD800 && ucc <= 0xDFFF) { return -1; }
|
||||
// UTF-8 must represent code points in their shortest possible encoding.
|
||||
switch (len) {
|
||||
case 2:
|
||||
// Two bytes of UTF-8 can represent code points from U+0080 to U+07FF.
|
||||
if (ucc < 0x0080 || ucc > 0x07FF) { return -1; }
|
||||
break;
|
||||
case 3:
|
||||
// Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF.
|
||||
if (ucc < 0x0800 || ucc > 0xFFFF) { return -1; }
|
||||
break;
|
||||
case 4:
|
||||
// Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF.
|
||||
if (ucc < 0x10000 || ucc > 0x10FFFF) { return -1; }
|
||||
break;
|
||||
}
|
||||
return ucc;
|
||||
}
|
||||
|
||||
// Wraps a string to a maximum length, inserting new lines where necessary. Any
|
||||
// existing whitespace will be collapsed down to a single space. A prefix or
|
||||
// suffix can be provided, which will be inserted before or after a wrapped
|
||||
// line, respectively.
|
||||
inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
const std::string wrapped_line_prefix,
|
||||
const std::string wrapped_line_suffix) {
|
||||
std::istringstream in_stream(in);
|
||||
std::string wrapped, line, word;
|
||||
|
||||
in_stream >> word;
|
||||
line = word;
|
||||
|
||||
while (in_stream >> word) {
|
||||
if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) <
|
||||
max_length) {
|
||||
line += " " + word;
|
||||
} else {
|
||||
wrapped += line + wrapped_line_suffix + "\n";
|
||||
line = wrapped_line_prefix + word;
|
||||
}
|
||||
}
|
||||
wrapped += line;
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_utf8) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < length; i++) {
|
||||
char c = s[i];
|
||||
switch (c) {
|
||||
case '\n': text += "\\n"; break;
|
||||
case '\t': text += "\\t"; break;
|
||||
case '\r': text += "\\r"; break;
|
||||
case '\b': text += "\\b"; break;
|
||||
case '\f': text += "\\f"; break;
|
||||
case '\"': text += "\\\""; break;
|
||||
case '\\': text += "\\\\"; break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~') {
|
||||
text += c;
|
||||
} else {
|
||||
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
|
||||
const char *utf8 = s + i;
|
||||
int ucc = FromUTF8(&utf8);
|
||||
if (ucc < 0) {
|
||||
if (allow_non_utf8) {
|
||||
text += "\\x";
|
||||
text += IntToStringHex(static_cast<uint8_t>(c), 2);
|
||||
} else {
|
||||
// There are two cases here:
|
||||
//
|
||||
// 1) We reached here by parsing an IDL file. In that case,
|
||||
// we previously checked for non-UTF-8, so we shouldn't reach
|
||||
// here.
|
||||
//
|
||||
// 2) We reached here by someone calling GenerateText()
|
||||
// on a previously-serialized flatbuffer. The data might have
|
||||
// non-UTF-8 Strings, or might be corrupt.
|
||||
//
|
||||
// In both cases, we have to give up and inform the caller
|
||||
// they have no JSON.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ucc <= 0xFFFF) {
|
||||
// Parses as Unicode within JSON's \uXXXX range, so use that.
|
||||
text += "\\u";
|
||||
text += IntToStringHex(ucc, 4);
|
||||
} else if (ucc <= 0x10FFFF) {
|
||||
// Encode Unicode SMP values to a surrogate pair using two \u
|
||||
// escapes.
|
||||
uint32_t base = ucc - 0x10000;
|
||||
auto high_surrogate = (base >> 10) + 0xD800;
|
||||
auto low_surrogate = (base & 0x03FF) + 0xDC00;
|
||||
text += "\\u";
|
||||
text += IntToStringHex(high_surrogate, 4);
|
||||
text += "\\u";
|
||||
text += IntToStringHex(low_surrogate, 4);
|
||||
}
|
||||
// Skip past characters recognized.
|
||||
i = static_cast<uoffset_t>(utf8 - s - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
text += "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_UTIL_H_
|
||||
Reference in New Issue
Block a user